mirror of
https://github.com/jrnl-org/jrnl.git
synced 2025-05-10 08:38:32 +02:00
Update more arg parsing options and handling
This commit is contained in:
parent
c98d01bb8b
commit
22db905e3d
5 changed files with 240 additions and 181 deletions
|
@ -25,7 +25,7 @@ import platform
|
|||
import sys
|
||||
|
||||
from . import install, plugins, util
|
||||
from .commands import list_journals
|
||||
from .util import list_journals
|
||||
from .parsing import parse_args_before_config
|
||||
from .Journal import PlainJournal, open_journal
|
||||
from .util import WARNING_COLOR, ERROR_COLOR, RESET_COLOR, UserAbort
|
||||
|
@ -148,7 +148,7 @@ Python 3.7 (or higher) soon.
|
|||
configure_logger(args.debug)
|
||||
|
||||
# Run command if possible before config is available
|
||||
if args.preconfig_cmd is not None:
|
||||
if callable(args.preconfig_cmd):
|
||||
args.preconfig_cmd(args)
|
||||
sys.exit(0)
|
||||
|
||||
|
@ -160,7 +160,7 @@ Python 3.7 (or higher) soon.
|
|||
sys.exit(1)
|
||||
|
||||
# Run command now that config is available
|
||||
if args.postconfig_cmd is not None:
|
||||
if callable(args.postconfig_cmd):
|
||||
args.postconfig_cmd(config=config, args=args)
|
||||
sys.exit(0)
|
||||
|
||||
|
|
|
@ -1,17 +1,3 @@
|
|||
def deprecated_cmd(old_cmd, new_cmd, callback, **kwargs):
|
||||
import sys
|
||||
from .util import RESET_COLOR, WARNING_COLOR
|
||||
|
||||
print(
|
||||
WARNING_COLOR,
|
||||
f"\nThe command {old_cmd} is deprecated and will be removed from jrnl soon.\n"
|
||||
f"Please use {new_cmd} instead.\n",
|
||||
RESET_COLOR,
|
||||
file=sys.stderr,
|
||||
)
|
||||
callback(**kwargs)
|
||||
|
||||
|
||||
def preconfig_diagnostic(_):
|
||||
import platform
|
||||
import sys
|
||||
|
@ -31,22 +17,7 @@ def preconfig_version(_):
|
|||
print(version_str)
|
||||
|
||||
|
||||
def preconfig_command(args):
|
||||
print("this is a pre-config command")
|
||||
|
||||
|
||||
def postconfig_list(config, **kwargs):
|
||||
from .util import list_journals
|
||||
|
||||
print(list_journals(config))
|
||||
|
||||
|
||||
def list_journals(config):
|
||||
from . import install
|
||||
|
||||
"""List the journals specified in the configuration file"""
|
||||
result = f"Journals defined in {install.CONFIG_FILE_PATH}\n"
|
||||
ml = min(max(len(k) for k in config["journals"]), 20)
|
||||
for journal, cfg in config["journals"].items():
|
||||
result += " * {:{}} -> {}\n".format(
|
||||
journal, ml, cfg["journal"] if isinstance(cfg, dict) else cfg
|
||||
)
|
||||
return result
|
||||
|
|
345
jrnl/parsing.py
345
jrnl/parsing.py
|
@ -1,11 +1,20 @@
|
|||
import argparse
|
||||
import re
|
||||
import textwrap
|
||||
|
||||
from . import plugins
|
||||
from .plugins import util
|
||||
from .plugins import IMPORT_FORMATS
|
||||
from .plugins import EXPORT_FORMATS
|
||||
from .commands import preconfig_version
|
||||
from .commands import preconfig_diagnostic
|
||||
from .commands import postconfig_list
|
||||
from .commands import deprecated_cmd
|
||||
from .util import deprecated_cmd
|
||||
|
||||
|
||||
class WrappingFormatter(argparse.RawDescriptionHelpFormatter):
|
||||
def _split_lines(self, text, width):
|
||||
text = self._whitespace_matcher.sub(" ", text).strip()
|
||||
return textwrap.wrap(text, width=56)
|
||||
|
||||
|
||||
def parse_args_before_config(args=None):
|
||||
|
@ -13,165 +22,72 @@ def parse_args_before_config(args=None):
|
|||
Argument parsing that is doable before the config is available.
|
||||
Everything else goes into "text" for later parsing.
|
||||
"""
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=WrappingFormatter,
|
||||
add_help=False,
|
||||
description="The command-line note-taking and journaling app.",
|
||||
epilog="",
|
||||
)
|
||||
|
||||
optional = parser.add_argument_group("Optional Arguments")
|
||||
optional.add_argument(
|
||||
"--debug",
|
||||
dest="debug",
|
||||
action="store_true",
|
||||
help="Print information useful for troubleshooting",
|
||||
)
|
||||
|
||||
standalone = parser.add_argument_group(
|
||||
"Standalone Commands",
|
||||
"These commands will exit after they complete. You may only run one at a time.",
|
||||
)
|
||||
standalone.add_argument("--help", action="help", help="Show this help message")
|
||||
standalone.add_argument("-h", action="help", help=argparse.SUPPRESS)
|
||||
standalone.add_argument(
|
||||
"--version",
|
||||
action="store_const",
|
||||
const=preconfig_version,
|
||||
dest="preconfig_cmd",
|
||||
help="prints version information and exits",
|
||||
help="prints version information",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--cmd1",
|
||||
standalone.add_argument(
|
||||
"-v",
|
||||
action="store_const",
|
||||
const=lambda: print("cmd1"),
|
||||
const=preconfig_version,
|
||||
dest="preconfig_cmd",
|
||||
help=argparse.SUPPRESS,
|
||||
)
|
||||
parser.add_argument(
|
||||
standalone.add_argument(
|
||||
"--diagnostic",
|
||||
action="store_const",
|
||||
const=preconfig_diagnostic,
|
||||
dest="preconfig_cmd",
|
||||
help="outputs diagnostic information and exits",
|
||||
help=argparse.SUPPRESS,
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--ls",
|
||||
standalone.add_argument(
|
||||
"--list",
|
||||
action="store_const",
|
||||
const=postconfig_list,
|
||||
dest="postconfig_cmd",
|
||||
help="lists all configured journals",
|
||||
help="list all configured journals",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
standalone.add_argument(
|
||||
"--ls",
|
||||
action="store_const",
|
||||
const=postconfig_list,
|
||||
dest="postconfig_cmd",
|
||||
help=argparse.SUPPRESS,
|
||||
)
|
||||
standalone.add_argument(
|
||||
"-ls",
|
||||
action="store_const",
|
||||
const=lambda **kwargs: deprecated_cmd(
|
||||
"-ls", "--ls or --list", callback=postconfig_list, **kwargs
|
||||
"-ls", "--list or --ls", callback=postconfig_list, **kwargs
|
||||
),
|
||||
dest="postconfig_cmd",
|
||||
help="displays accessible journals",
|
||||
help=argparse.SUPPRESS,
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-d", "--debug", dest="debug", action="store_true", help="execute in debug mode"
|
||||
)
|
||||
|
||||
composing = parser.add_argument_group(
|
||||
"Composing",
|
||||
'To write an entry simply write it on the command line, e.g. "jrnl yesterday at 1pm: Went to the gym."',
|
||||
)
|
||||
|
||||
reading = parser.add_argument_group(
|
||||
"Reading",
|
||||
"Specifying either of these parameters will display posts of your journal",
|
||||
)
|
||||
reading.add_argument(
|
||||
"-from", dest="start_date", metavar="DATE", help="View entries after this date"
|
||||
)
|
||||
reading.add_argument(
|
||||
"-until",
|
||||
"-to",
|
||||
dest="end_date",
|
||||
metavar="DATE",
|
||||
help="View entries before this date",
|
||||
)
|
||||
reading.add_argument(
|
||||
"-contains", dest="contains", help="View entries containing a specific string"
|
||||
)
|
||||
reading.add_argument(
|
||||
"-on", dest="on_date", metavar="DATE", help="View entries on this date"
|
||||
)
|
||||
reading.add_argument(
|
||||
"-and",
|
||||
dest="strict",
|
||||
action="store_true",
|
||||
help="Filter by tags using AND (default: OR)",
|
||||
)
|
||||
reading.add_argument(
|
||||
"-starred",
|
||||
dest="starred",
|
||||
action="store_true",
|
||||
help="Show only starred entries",
|
||||
)
|
||||
reading.add_argument(
|
||||
"-n",
|
||||
dest="limit",
|
||||
default=None,
|
||||
metavar="N",
|
||||
help="Shows the last n entries matching the filter. '-n 3' and '-3' have the same effect.",
|
||||
nargs="?",
|
||||
type=int,
|
||||
)
|
||||
reading.add_argument(
|
||||
"-not",
|
||||
dest="excluded",
|
||||
nargs="?",
|
||||
default=[],
|
||||
metavar="E",
|
||||
action="append",
|
||||
help="Exclude entries with these tags",
|
||||
)
|
||||
|
||||
exporting = parser.add_argument_group(
|
||||
"Export / Import", "Options for transmogrifying your journal"
|
||||
)
|
||||
exporting.add_argument(
|
||||
"-s",
|
||||
"--short",
|
||||
dest="short",
|
||||
action="store_true",
|
||||
help="Show only titles or line containing the search tags",
|
||||
)
|
||||
exporting.add_argument(
|
||||
"--tags",
|
||||
dest="tags",
|
||||
action="store_true",
|
||||
help="Returns a list of all tags and number of occurences",
|
||||
)
|
||||
exporting.add_argument(
|
||||
"--export",
|
||||
metavar="TYPE",
|
||||
dest="export",
|
||||
choices=plugins.EXPORT_FORMATS,
|
||||
help="Export your journal. TYPE can be {}.".format(
|
||||
plugins.util.oxford_list(plugins.EXPORT_FORMATS)
|
||||
),
|
||||
default=False,
|
||||
const=None,
|
||||
)
|
||||
exporting.add_argument(
|
||||
"-o",
|
||||
metavar="OUTPUT",
|
||||
dest="output",
|
||||
help="Optionally specifies output file when using --export. If OUTPUT is a directory, exports each entry into an individual file instead.",
|
||||
default=False,
|
||||
const=None,
|
||||
)
|
||||
exporting.add_argument(
|
||||
"--import",
|
||||
metavar="TYPE",
|
||||
dest="import_",
|
||||
choices=plugins.IMPORT_FORMATS,
|
||||
help="Import entries into your journal. TYPE can be {}, and it defaults to jrnl if nothing else is specified.".format(
|
||||
plugins.util.oxford_list(plugins.IMPORT_FORMATS)
|
||||
),
|
||||
default=False,
|
||||
const="jrnl",
|
||||
nargs="?",
|
||||
)
|
||||
exporting.add_argument(
|
||||
"-i",
|
||||
metavar="INPUT",
|
||||
dest="input",
|
||||
help="Optionally specifies input file when using --import.",
|
||||
default=False,
|
||||
const=None,
|
||||
)
|
||||
exporting.add_argument(
|
||||
standalone.add_argument(
|
||||
"--encrypt",
|
||||
metavar="FILENAME",
|
||||
dest="encrypt",
|
||||
|
@ -180,7 +96,7 @@ def parse_args_before_config(args=None):
|
|||
default=False,
|
||||
const=None,
|
||||
)
|
||||
exporting.add_argument(
|
||||
standalone.add_argument(
|
||||
"--decrypt",
|
||||
metavar="FILENAME",
|
||||
dest="decrypt",
|
||||
|
@ -189,22 +105,163 @@ def parse_args_before_config(args=None):
|
|||
default=False,
|
||||
const=None,
|
||||
)
|
||||
standalone.add_argument(
|
||||
"--import",
|
||||
metavar="TYPE",
|
||||
dest="import_",
|
||||
choices=IMPORT_FORMATS,
|
||||
help=f"Import entries into your journal. TYPE can be: {util.oxford_list(IMPORT_FORMATS)} (default: jrnl)",
|
||||
default=False,
|
||||
const="jrnl",
|
||||
nargs="?",
|
||||
)
|
||||
standalone.add_argument(
|
||||
"-i",
|
||||
metavar="FILENAME",
|
||||
dest="input",
|
||||
help="Optionally specifies input file when using --import.",
|
||||
default=False,
|
||||
const=None,
|
||||
)
|
||||
|
||||
compose_msg = """ To add a new entry into your journal, simply write it on the command line:
|
||||
|
||||
jrnl yesterday: I was walking and I found this big log.
|
||||
|
||||
The date and the following colon ("yesterday:") are optional. If you leave
|
||||
them out, "now" will be used:
|
||||
|
||||
jrnl Then I rolled the log over, and underneath was a tiny little stick.
|
||||
|
||||
Also, you can mark extra special entries ("star" them) with an asterisk:
|
||||
|
||||
jrnl *That log had a child!
|
||||
|
||||
Please note that asterisks might be a special character in your shell, so you
|
||||
might have to escape them. When in doubt about escaping, put single quotes
|
||||
around your entire entry:
|
||||
|
||||
jrnl 'saturday at 8pm: *Always pass on what you have learned. -Yoda'"""
|
||||
|
||||
composing = parser.add_argument_group(
|
||||
"Writing", textwrap.dedent(compose_msg).strip()
|
||||
)
|
||||
composing.add_argument("text", metavar="", nargs="*")
|
||||
|
||||
read_msg = (
|
||||
"To find entries from your journal, use any combination of the below filters."
|
||||
)
|
||||
reading = parser.add_argument_group("Searching", textwrap.dedent(read_msg))
|
||||
reading.add_argument(
|
||||
"-on", dest="on_date", metavar="DATE", help="Show entries on this date"
|
||||
)
|
||||
reading.add_argument(
|
||||
"-from",
|
||||
dest="start_date",
|
||||
metavar="DATE",
|
||||
help="Show entries after, or on, this date",
|
||||
)
|
||||
reading.add_argument(
|
||||
"-to",
|
||||
dest="end_date",
|
||||
metavar="DATE",
|
||||
help="Show entries before, or on, this date (alias: -until)",
|
||||
)
|
||||
reading.add_argument(
|
||||
"-until", dest="end_date", help=argparse.SUPPRESS,
|
||||
)
|
||||
reading.add_argument(
|
||||
"-contains",
|
||||
dest="contains",
|
||||
metavar="TEXT",
|
||||
help="Show entries containing specific text (put quotes around text with spaces)",
|
||||
)
|
||||
reading.add_argument(
|
||||
"-and",
|
||||
dest="strict",
|
||||
action="store_true",
|
||||
help='Show only entries that match all conditions, like saying "x AND y" (default: OR)',
|
||||
)
|
||||
reading.add_argument(
|
||||
"-starred",
|
||||
dest="starred",
|
||||
action="store_true",
|
||||
help="Show only starred entries (marked with *)",
|
||||
)
|
||||
reading.add_argument(
|
||||
"-n",
|
||||
dest="limit",
|
||||
default=None,
|
||||
metavar="NUMBER",
|
||||
help="Show a maximum of NUMBER entries (note: '-n 3' and '-3' have the same effect)",
|
||||
nargs="?",
|
||||
type=int,
|
||||
)
|
||||
reading.add_argument(
|
||||
"-not",
|
||||
dest="excluded",
|
||||
nargs="?",
|
||||
default=[],
|
||||
metavar="TAG",
|
||||
action="append",
|
||||
help="Exclude entries with this tag",
|
||||
)
|
||||
|
||||
search_options_msg = """ These help you do various tasks with the selected entries from your search.
|
||||
If used on their own (with no search), they will act on your entire journal"""
|
||||
exporting = parser.add_argument_group(
|
||||
"Options for Searching", textwrap.dedent(search_options_msg)
|
||||
)
|
||||
exporting.add_argument(
|
||||
"--edit",
|
||||
dest="edit",
|
||||
help="Opens your editor to edit the selected entries.",
|
||||
help="Opens the selected entries in your configured editor",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
exporting.add_argument(
|
||||
"--delete",
|
||||
dest="delete",
|
||||
action="store_true",
|
||||
help="Opens an interactive interface for deleting entries.",
|
||||
help="Interactively deletes selected entries",
|
||||
)
|
||||
exporting.add_argument(
|
||||
"--format",
|
||||
metavar="TYPE",
|
||||
dest="export",
|
||||
choices=EXPORT_FORMATS,
|
||||
help=f"Display selected entries in an alternate format (other than jrnl). TYPE can be: {util.oxford_list(EXPORT_FORMATS)}.",
|
||||
default=False,
|
||||
)
|
||||
exporting.add_argument(
|
||||
"--export",
|
||||
metavar="TYPE",
|
||||
dest="export",
|
||||
choices=EXPORT_FORMATS,
|
||||
help=argparse.SUPPRESS,
|
||||
)
|
||||
exporting.add_argument(
|
||||
"--tags",
|
||||
dest="tags",
|
||||
action="store_true",
|
||||
help="Alias for '--format tags'. Returns a list of all tags and number of occurences",
|
||||
)
|
||||
exporting.add_argument(
|
||||
"--short",
|
||||
dest="short",
|
||||
action="store_true",
|
||||
help="Show only titles or line containing the search tags",
|
||||
)
|
||||
exporting.add_argument(
|
||||
"-s", dest="short", action="store_true", help=argparse.SUPPRESS,
|
||||
)
|
||||
exporting.add_argument(
|
||||
"-o",
|
||||
metavar="FILENAME",
|
||||
dest="output",
|
||||
help="Optionally specifies output file (or directory) when using --format.",
|
||||
default=False,
|
||||
const=None,
|
||||
)
|
||||
|
||||
# Everything else
|
||||
composing.add_argument("text", metavar="", nargs="*")
|
||||
|
||||
if not args:
|
||||
args = []
|
||||
|
|
32
jrnl/util.py
32
jrnl/util.py
|
@ -289,3 +289,35 @@ def split_title(text):
|
|||
if not sep:
|
||||
return text, ""
|
||||
return text[: sep.end()].strip(), text[sep.end() :].strip()
|
||||
|
||||
|
||||
def deprecated_cmd(old_cmd, new_cmd, callback=None, **kwargs):
|
||||
import sys
|
||||
import textwrap
|
||||
from .util import RESET_COLOR, WARNING_COLOR
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
warning_msg = f"""
|
||||
The command {old_cmd} is deprecated and will be removed from jrnl soon.
|
||||
Please us {new_cmd} instead.
|
||||
"""
|
||||
warning_msg = textwrap.dedent(warning_msg)
|
||||
log.warning(warning_msg)
|
||||
print(f"{WARNING_COLOR}{warning_msg}{RESET_COLOR}", file=sys.stderr)
|
||||
|
||||
if callback is not None:
|
||||
callback(**kwargs)
|
||||
|
||||
|
||||
def list_journals(config):
|
||||
from . import install
|
||||
|
||||
"""List the journals specified in the configuration file"""
|
||||
result = f"Journals defined in {install.CONFIG_FILE_PATH}\n"
|
||||
ml = min(max(len(k) for k in config["journals"]), 20)
|
||||
for journal, cfg in config["journals"].items():
|
||||
result += " * {:{}} -> {}\n".format(
|
||||
journal, ml, cfg["journal"] if isinstance(cfg, dict) else cfg
|
||||
)
|
||||
return result
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from jrnl.cli import parse_args_before_config as parse_args
|
||||
from jrnl.cli import parse_args_before_config
|
||||
|
||||
import pytest
|
||||
import shlex
|
||||
|
@ -6,7 +6,7 @@ import shlex
|
|||
|
||||
def cli_as_dict(str):
|
||||
cli = shlex.split(str)
|
||||
args = parse_args(cli)
|
||||
args = parse_args_before_config(cli)
|
||||
return vars(args)
|
||||
|
||||
|
||||
|
@ -48,7 +48,6 @@ def test_contains_alone():
|
|||
|
||||
def test_debug_alone():
|
||||
assert cli_as_dict("--debug") == expected_args(debug=True)
|
||||
assert cli_as_dict("-d") == expected_args(debug=True)
|
||||
|
||||
|
||||
def test_delete_alone():
|
||||
|
|
Loading…
Add table
Reference in a new issue