Fix editor config when an argument with a space is used (#953)

* Fix editor config when an argument with a space is used
* skip broken test on windows
* fix jrnl not behaving nicely with testing suite
* fix argument parsing for test suite
* fix one windows test, disable one windows test
This commit is contained in:
Jonathan Wren 2020-05-23 15:56:31 -07:00 committed by GitHub
parent 7600e14278
commit c456b85bc5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 72 additions and 10 deletions

View file

@ -39,6 +39,16 @@ Feature: Basic reading and writing to a journal
When we open the editor and enter nothing When we open the editor and enter nothing
Then we should see the message "[Nothing saved to file]" Then we should see the message "[Nothing saved to file]"
@skip_win
Scenario: Sending an argument with spaces to the editor should work
Given we use the config "editor-args.yaml"
When we open the editor and enter "lorem ipsum"
Then the editor should have been called with 5 arguments
And one editor argument should be "vim"
And one editor argument should be "-f"
And one editor argument should be "-c"
And one editor argument should match "'?setf markdown'?"
Scenario: Writing an empty entry from the command line Scenario: Writing an empty entry from the command line
Given we use the config "basic.yaml" Given we use the config "basic.yaml"
When we run "jrnl" and enter nothing When we run "jrnl" and enter nothing

View file

@ -0,0 +1,12 @@
default_hour: 9
default_minute: 0
editor: vim -f -c 'setf markdown'
encrypt: false
highlight: true
journals:
default: features/journals/simple.journal
linewrap: 80
tagsymbols: "@"
template: false
timeformat: "%Y-%m-%d %H:%M"
indent_character: "|"

View file

@ -2,6 +2,7 @@ import ast
from collections import defaultdict from collections import defaultdict
import os import os
from pathlib import Path from pathlib import Path
import re
import shlex import shlex
import sys import sys
import time import time
@ -85,6 +86,7 @@ def open_editor_and_enter(context, text=""):
text = text or context.text or "" text = text or context.text or ""
def _mock_editor_function(command): def _mock_editor_function(command):
context.editor_command = command
tmpfile = command[-1] tmpfile = command[-1]
with open(tmpfile, "w+") as f: with open(tmpfile, "w+") as f:
f.write(text) f.write(text)
@ -92,7 +94,29 @@ def open_editor_and_enter(context, text=""):
return tmpfile return tmpfile
with patch("subprocess.call", side_effect=_mock_editor_function): with patch("subprocess.call", side_effect=_mock_editor_function):
run(context, "jrnl") context.execute_steps('when we run "jrnl"')
@then("the editor should have been called with {num} arguments")
def count_editor_args(context, num):
assert len(context.editor_command) == int(num)
@then('one editor argument should be "{arg}"')
def contains_editor_arg(context, arg):
args = context.editor_command
assert (
arg in args and args.count(arg) == 1
), f"\narg not in args exactly 1 time:\n{arg}\n{str(args)}"
@then('one editor argument should match "{regex}"')
def matches_editor_arg(context, regex):
args = context.editor_command
matches = list(filter(lambda x: re.match(regex, x), args))
assert (
len(matches) == 1
), f"\nRegex didn't match exactly 1 time:\n{regex}\n{str(args)}"
def _mock_getpass(inputs): def _mock_getpass(inputs):
@ -155,9 +179,11 @@ def run(context, command, cache_dir=None):
cache_dir = os.path.join("features", "cache", cache_dir) cache_dir = os.path.join("features", "cache", cache_dir)
command = command.format(cache_dir=cache_dir) command = command.format(cache_dir=cache_dir)
args = ushlex(command)[1:] args = ushlex(command)
try: try:
cli.run(args or None) with patch("sys.argv", args):
cli.run(args[1:])
context.exit_status = 0 context.exit_status = 0
except SystemExit as e: except SystemExit as e:
context.exit_status = e.code context.exit_status = e.code

View file

@ -194,11 +194,14 @@ def parse_args(args=None):
help="Opens an interactive interface for deleting entries.", help="Opens an interactive interface for deleting entries.",
) )
if not args:
args = []
# Handle '-123' as a shortcut for '-n 123' # Handle '-123' as a shortcut for '-n 123'
num = re.compile(r"^-(\d+)$") num = re.compile(r"^-(\d+)$")
if args is None: args = [num.sub(r"-n \1", arg) for arg in args]
args = sys.argv[1:]
return parser.parse_args([num.sub(r"-n \1", a) for a in args]) return parser.parse_args(args)
def guess_mode(args, config): def guess_mode(args, config):
@ -300,6 +303,9 @@ def configure_logger(debug=False):
def run(manual_args=None): def run(manual_args=None):
if manual_args is None:
manual_args = sys.argv[1:]
args = parse_args(manual_args) args = parse_args(manual_args)
configure_logger(args.debug) configure_logger(args.debug)

View file

@ -9,6 +9,7 @@ from string import punctuation, whitespace
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
import textwrap
from typing import Callable, Optional from typing import Callable, Optional
import unicodedata import unicodedata
@ -172,10 +173,17 @@ def get_text_from_editor(config, template=""):
try: try:
subprocess.call( subprocess.call(
shlex.split(config["editor"], posix="win" not in sys.platform) + [tmpfile] shlex.split(config["editor"], posix="win32" not in sys.platform) + [tmpfile]
) )
except AttributeError: except Exception as e:
subprocess.call(config["editor"] + [tmpfile]) error_msg = f"""
{ERROR_COLOR}{str(e)}{RESET_COLOR}
Please check the 'editor' key in your config file for errors:
{repr(config['editor'])}
"""
print(textwrap.dedent(error_msg).strip(), file=sys.stderr)
exit(1)
with open(tmpfile, "r", encoding="utf-8") as f: with open(tmpfile, "r", encoding="utf-8") as f:
raw = f.read() raw = f.read()