From 7a6b622cd025d0244e10bf11758001335d64eb02 Mon Sep 17 00:00:00 2001 From: Adam Porter Date: Sat, 16 Dec 2023 03:57:35 -0600 Subject: [PATCH] Fix: Ignore empty quoted strings when parsing string queries Fixes #383. Reported-by: Adam Porter --- README.org | 3 ++- org-ql.el | 18 ++++++++++++++++-- tests/test-org-ql.el | 8 ++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/README.org b/README.org index 3fa1607..ba7ad9d 100644 --- a/README.org +++ b/README.org @@ -544,7 +544,8 @@ Simple links may also be written manually in either sexp or non-sexp form, like: ** 0.7.4-pre -Nothing new yet. +*Fixes* ++ Ignore empty quoted strings in plain-string queries ([[https://github.com/alphapapa/org-ql/issues/383][#383]]). ** 0.7.3 diff --git a/org-ql.el b/org-ql.el index 568225d..96a3235 100644 --- a/org-ql.el +++ b/org-ql.el @@ -285,6 +285,11 @@ Matches with or without time.") :link '(custom-manual "(org-ql)Usage") :link '(url-link "https://github.com/alphapapa/org-ql")) +(defcustom org-ql-signal-peg-failure nil + "Signal an error when parsing a plain-string query fails. +This should only be enabled while debugging." + :type 'boolean) + (defcustom org-ql-ask-unsafe-queries t "Ask before running a query that could run arbitrary code. Org QL queries in sexp form can contain arbitrary expressions. @@ -950,7 +955,7 @@ value of `org-ql-predicates')." (term (or (and negation (list positive-term) ;; This is a bit confusing, but it seems to work. There's probably a better way. `(pred -- (list 'not (car pred)))) - positive-term)) + positive-term empty-quote)) (positive-term (or (and predicate-with-args `(pred args -- (cons (intern pred) args))) (and predicate-without-args `(pred -- (list (intern pred)))) (and plain-string `(s -- (list org-ql-default-predicate s))))) @@ -963,6 +968,12 @@ value of `org-ql-predicates')." (keyword (substring (+ (not (or separator "=" "\"" (syntax-class whitespace))) (any)))) (quoted-arg "\"" (substring (+ (not (or separator "\"")) (any))) "\"") (unquoted-arg (substring (+ (not (or separator "\"" (syntax-class whitespace))) (any)))) + (empty-quote + ;; This avoids aborting parsing or signaling an + ;; error if the user types in two successive + ;; quotation marks while typing a query (e.g. when + ;; using electric-pair-mode). + "\"\"") (negation "!") (separator "," ))) (closure (lambda (input &optional boolean) @@ -983,7 +994,10 @@ value of `org-ql-predicates')." ;; have to borrow some code. It ends up that we only have to ;; borrow this `with-peg-rules' call, which isn't too bad. (eval `(with-peg-rules ,pexs - (peg-run (peg ,(caar pexs)) #'peg-signal-failure)))))) + (peg-run (peg ,(caar pexs)) + (lambda (failures) + (when org-ql-signal-peg-failure + (peg-signal-failure failures))))))))) (pcase parsed-sexp (`(,one-predicate) one-predicate) (`(,_ . ,_) (cons boolean (reverse parsed-sexp))) diff --git a/tests/test-org-ql.el b/tests/test-org-ql.el index 9008179..12e8eb0 100644 --- a/tests/test-org-ql.el +++ b/tests/test-org-ql.el @@ -648,6 +648,14 @@ with keyword arg NOW in PLIST." ;; TODO: Other predicates. + (it "Ignores empty quoted strings" + (expect (org-ql--query-string-to-sexp "\"\"") + :to-equal nil) + (expect (org-ql--query-string-to-sexp "foo \"\" bar") + :to-equal '(and (rifle "foo") (rifle "bar"))) + (expect (org-ql--query-string-to-sexp "foo \"baz\" bar") + :to-equal '(and (rifle "foo") (rifle "baz") (rifle "bar")))) + (it "Negated terms" (expect (org-ql--query-string-to-sexp "todo: !todo:CHECK,SOMEDAY") :to-equal '(and (todo) (not (todo "CHECK" "SOMEDAY"))))