From c573ca94183a0e8a5e25de7f6c7e16aadf58fe9c Mon Sep 17 00:00:00 2001 From: Ciaran Concannon Date: Thu, 12 Jan 2023 12:47:57 +0000 Subject: [PATCH] Allow for `-not -starred` to search for unstarred entries --- jrnl/args.py | 25 ++++++++++++++++++++----- jrnl/controller.py | 3 +++ jrnl/journals/Journal.py | 23 ++++++++++++----------- tests/bdd/features/search.feature | 14 ++++++++++++++ tests/unit/test_parse_args.py | 1 + 5 files changed, 50 insertions(+), 16 deletions(-) diff --git a/jrnl/args.py b/jrnl/args.py index d23e1e53..cf162c1a 100644 --- a/jrnl/args.py +++ b/jrnl/args.py @@ -27,6 +27,10 @@ class WrappingFormatter(argparse.RawTextHelpFormatter): text = [item for sublist in text for item in sublist] return text +class IgnoreNoneAppendAction(argparse._AppendAction): + def __call__(self, parser, namespace, values, option_string=None): + if values is not None: + super().__call__(parser, namespace, values, option_string) def parse_args(args: list[str] = []) -> argparse.Namespace: """ @@ -249,11 +253,13 @@ def parse_args(args: list[str] = []) -> argparse.Namespace: reading.add_argument( "-not", dest="excluded", - nargs=1, + nargs="?", default=[], - metavar="TAG", - action="extend", - help="Exclude entries with this tag", + metavar="TAG/FLAG", + action=IgnoreNoneAppendAction, + help=("If passed a string, will exclude entries with that tag. " + "If it preceeds -starred flag, will exclude starred entries" + ), ) search_options_msg = """ These help you do various tasks with the selected entries from your search. @@ -388,5 +394,14 @@ def parse_args(args: list[str] = []) -> argparse.Namespace: # Handle '-123' as a shortcut for '-n 123' num = re.compile(r"^-(\d+)$") args = [num.sub(r"-n \1", arg) for arg in args] + parsed_args = parser.parse_intermixed_args(args) + parsed_args.exclude_starred = False - return parser.parse_intermixed_args(args) + # Handle -not where it is reversing the behaviour of a flag + if "-not-starred" in "".join(args): + parsed_args.starred = False + parsed_args.exclude_starred = True + if "-not" in args and not any([parsed_args.exclude_starred, parsed_args.excluded]): + return parser.error("argument -not: expected 1 argument") + + return parsed_args diff --git a/jrnl/controller.py b/jrnl/controller.py index 7d7c87ce..242dfbee 100644 --- a/jrnl/controller.py +++ b/jrnl/controller.py @@ -89,6 +89,7 @@ def _is_write_mode(args: "Namespace", config: dict, **kwargs) -> bool: args.edit, args.change_time, args.excluded, + args.exclude_starred, args.export, args.end_date, args.today_in_history, @@ -271,6 +272,7 @@ def _has_search_args(args: "Namespace") -> bool: args.strict, args.starred, args.excluded, + args.exclude_starred, args.contains, args.limit, ) @@ -297,6 +299,7 @@ def _filter_journal_entries(args: "Namespace", journal: Journal, **kwargs) -> No strict=args.strict, starred=args.starred, exclude=args.excluded, + exclude_starred=args.exclude_starred, contains=args.contains, ) journal.limit(args.limit) diff --git a/jrnl/journals/Journal.py b/jrnl/journals/Journal.py index 5a8b016e..a3bbcf8b 100644 --- a/jrnl/journals/Journal.py +++ b/jrnl/journals/Journal.py @@ -229,16 +229,17 @@ class Journal: def filter( self, - tags: list = [], - month: str | int | None = None, - day: str | int | None = None, - year: str | None = None, - start_date: str | None = None, - end_date: str | None = None, - starred: bool = False, - strict: bool = False, - contains: bool = None, - exclude: list = [], + tags=[], + month=None, + day=None, + year=None, + start_date=None, + end_date=None, + starred=False, + exclude_starred=False, + strict=False, + contains=None, + exclude=[], ): """Removes all entries from the journal that don't match the filter. @@ -276,7 +277,7 @@ class Journal: entry for entry in self.entries if (not tags or tagged(entry.tags)) - and (not starred or entry.starred) + and (not (starred or exclude_starred) or entry.starred == starred) and (not month or entry.date.month == compare_d.month) and (not day or entry.date.day == compare_d.day) and (not year or entry.date.year == compare_d.year) diff --git a/tests/bdd/features/search.feature b/tests/bdd/features/search.feature index d653a621..6853a726 100644 --- a/tests/bdd/features/search.feature +++ b/tests/bdd/features/search.feature @@ -124,6 +124,20 @@ Feature: Searching in a journal | basic_folder.yaml | | basic_dayone.yaml | + + Scenario: Searching for unstarred entries + Given we use the config "" + And we use the password "test" if prompted + When we run "jrnl -not -starred" + Then we should get no error + And the output should contain "2 entries found" + + Examples: configs + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | + Scenario Outline: Searching for dates Given we use the config "" When we run "jrnl -on 2020-08-31 --short" diff --git a/tests/unit/test_parse_args.py b/tests/unit/test_parse_args.py index ccb7f5a2..72910d5e 100644 --- a/tests/unit/test_parse_args.py +++ b/tests/unit/test_parse_args.py @@ -23,6 +23,7 @@ def expected_args(**kwargs): "change_time": None, "edit": False, "end_date": None, + "exclude_starred": False, "today_in_history": False, "month": None, "day": None,