diff --git a/README.org b/README.org index 1a20b83..34c4011 100644 --- a/README.org +++ b/README.org @@ -522,6 +522,11 @@ Simple links may also be written manually in either sexp or non-sexp form, like: /Note:/ Breaking changes may be made before version 1.0, but in the event of major changes, attempts at backward compatibility will be made with obsolescence declarations, translation of arguments, etc. Users who need stability guarantees before 1.0 may choose to use tagged stable releases. +** 0.7-pre + +*Fixed* ++ In dynamic blocks, links to headings with statistics cookies were broken. (Fixes [[https://github.com/alphapapa/org-ql/issues/248][#248]]. Thanks to [[https://github.com/maikol-solis][Maikol Solis]] and [[https://github.com/yantar92][Ihor Radchenko]].) + ** 0.6 *Added* diff --git a/org-ql-search.el b/org-ql-search.el index 4fb5489..aa75656 100644 --- a/org-ql-search.el +++ b/org-ql-search.el @@ -38,6 +38,15 @@ (require 'org-ql) (require 'org-ql-view) +;;;; Compatibility + +(defalias 'org-ql-search--link-heading-search-string + (cond ((fboundp 'org-link--normalize-string) #'org-link--normalize-string) + ((fboundp 'org-link-heading-search-string) #'org-link-heading-search-string) + ((fboundp 'org-make-org-heading-search-string) #'org-make-org-heading-search-string) + (t (warn "org-ql: Unable to define alias `org-ql-search--link-heading-search-string'. This may affect links in dynamic blocks. Please report this as a bug.") + #'identity))) + ;;;; Variables (defvar org-ql-block-header nil @@ -285,9 +294,9 @@ For example, an org-ql dynamic block header could look like: (list (cons 'todo (lambda (element) (org-element-property :todo-keyword element))) (cons 'heading (lambda (element) - (org-make-link-string (org-element-property :raw-value element) - (org-link-display-format - (org-element-property :raw-value element))))) + (let ((normalized-heading + (org-ql-search--link-heading-search-string (org-element-property :raw-value element)))) + (org-make-link-string normalized-heading (org-link-display-format normalized-heading))))) (cons 'priority (lambda (element) (--when-let (org-element-property :priority element) (char-to-string it)))) diff --git a/org-ql.el b/org-ql.el index 91d2710..83df2a5 100644 --- a/org-ql.el +++ b/org-ql.el @@ -2,7 +2,7 @@ ;; Author: Adam Porter ;; Url: https://github.com/alphapapa/org-ql -;; Version: 0.6 +;; Version: 0.7-pre ;; Package-Requires: ((emacs "26.1") (dash "2.18.1") (f "0.17.2") (map "2.1") (org "9.0") (org-super-agenda "1.2") (ov "1.0.6") (peg "1.0") (s "1.12.0") (transient "0.1") (ts "0.2-pre")) ;; Keywords: hypermedia, outlines, Org, agenda @@ -2134,6 +2134,89 @@ any planning prefix); it defaults to 0 (i.e. the whole regexp)." (from (test-timestamps (ts<= from next-ts))) (to (test-timestamps (ts<= next-ts to))))))) +;;;;;; Logbooks + +(org-ql-defpred logbook (&key string from to on state regexp) + "Return non-nil if current entry has a logbook matching arguments. +FIXME: Document remaining arguments. NOTE: STRING argument is +accepted as first argument rather than only as keyword argument." + :normalizers + ((`(,predicate-names . ,rest) + (let ((string (if (stringp (car rest)) + (prog1 + (regexp-quote (car rest)) + (setf rest (cdr rest))) + (plist-get rest :string))) + (regexp (plist-get rest :regexp)) + (state (plist-get rest :state))) + (org-ql--normalize-from-to-on + `(logbook :string ,string :regexp ,regexp :state ,state + :from ,from :to ,to :on ,on))))) + + ;; TODO: :preambles. When arguments are given, search for an + ;; appropriate regexp, then use the :body predicate to confirm it's + ;; in a logbook drawer. Without arguments, simply search for a + ;; logbook drawer (though note that this would preclude using + ;; entry-specific logbook drawer names). + + :body + ;; For now, we'll model part of this on `org-log-beginning', though + ;; it may not be fast enough to run on every potential match. + + ;; NOTE: It's regrettable, but since any entry or subtree may define + ;; its own logbook drawer name, to be correct, we must call + ;; `org-log-into-drawer' for each entry. This also means concatting + ;; a regexp string to match such a drawer. + + ;; TODO: Optionally assume default logbook drawer names and optimize + ;; for that case. + (when-let ((drawer-name (org-log-into-drawer))) + ;; Look for logbook drawer in entry. + (save-excursion + (org-end-of-meta-data) + (let ((drawer-regexp (concat "^[ \t]*:" (regexp-quote drawer-name) ":[ \t]*$")) + (end (if (org-at-heading-p) + (point) + (save-excursion + (outline-next-heading) + (point)))) + (case-fold-search t)) + (when-let ((drawer-element (cl-loop while (re-search-forward drawer-regexp end t) + for element = (org-element-at-point) + when (eq 'drawer (org-element-type element)) + return element))) + ;; Logbook drawer found: narrow to it and confirm that + ;; arguments are found in it. + (save-restriction + (narrow-to-region (point) (org-element-property :contents-end drawer-element)) + (and (or (not string) + (save-excursion + (re-search-forward string nil t))) + (or (not regexp) + (save-excursion + (re-search-forward regexp nil t))) + ;; TODO: from, to, on, state + + ;; TODO: Search notes added like "- Note taken on + ;; [2022-03-07 Mon 13:55] \\" (this starts to get + ;; complicated; org-element might help, but might + ;; also be too slow). + + ;; TODO: Without arguments, search for any logbook + ;; entries. + ))))))) + +(defun org-ql--state-change-regexp (to &optional from) + "Return regexp matching logbook state-change line for states TO and FROM. +Regexp includes an inactive timestamp with hour:minute at +end-of-line." + (let ((from-regexp (if from + `(,(concat "\"" from "\"") (1+ blank)) + '("")))) + (rx-to-string `(seq bol (0+ blank) "-" (repeat 1 2 " ") "State " "\"" ,to "\"" (1+ blank) + "from " ,@from-regexp (1+ blank) + (regexp ,org-ql-regexp-ts-inactive-with-time))))) + ;; NOTE: Predicates defined: stop deferring and define normalizer and ;; preamble functions now. Reversing preserves the order in which ;; they were defined. Generally it shouldn't matter, but it might... diff --git a/org-ql.info b/org-ql.info index 09826ca..a61c3a8 100644 --- a/org-ql.info +++ b/org-ql.info @@ -69,6 +69,7 @@ Functions / Macros Changelog +* 0.7-pre: 07-pre. * 0.6: 06. * 0.5.2: 052. * 0.5.1: 051. @@ -957,6 +958,7 @@ releases. * Menu: +* 0.7-pre: 07-pre. * 0.6: 06. * 0.5.2: 052. * 0.5.1: 051. @@ -981,9 +983,22 @@ releases. * 0.1: 01.  -File: README.info, Node: 06, Next: 052, Up: Changelog +File: README.info, Node: 07-pre, Next: 06, Up: Changelog -5.1 0.6 +5.1 0.7-pre +=========== + +*Fixed* + • In dynamic blocks, links to headings with statistics cookies were + broken. (Fixes #248 + (https://github.com/alphapapa/org-ql/issues/248). Thanks to Maikol + Solis (https://github.com/maikol-solis) and Ihor Radchenko + (https://github.com/yantar92).) + + +File: README.info, Node: 06, Next: 052, Prev: 07-pre, Up: Changelog + +5.2 0.6 ======= *Added* @@ -1050,7 +1065,7 @@ File: README.info, Node: 06, Next: 052, Up: Changelog  File: README.info, Node: 052, Next: 051, Prev: 06, Up: Changelog -5.2 0.5.2 +5.3 0.5.2 ========= *Fixed* @@ -1061,7 +1076,7 @@ File: README.info, Node: 052, Next: 051, Prev: 06, Up: Changelog  File: README.info, Node: 051, Next: 05, Prev: 052, Up: Changelog -5.3 0.5.1 +5.4 0.5.1 ========= *Fixed* @@ -1074,7 +1089,7 @@ File: README.info, Node: 051, Next: 05, Prev: 052, Up: Changelog  File: README.info, Node: 05, Next: 049, Prev: 051, Up: Changelog -5.4 0.5 +5.5 0.5 ======= *Added* @@ -1115,7 +1130,7 @@ File: README.info, Node: 05, Next: 049, Prev: 051, Up: Changelog  File: README.info, Node: 049, Next: 048, Prev: 05, Up: Changelog -5.5 0.4.9 +5.6 0.4.9 ========= *Fixed* @@ -1126,7 +1141,7 @@ File: README.info, Node: 049, Next: 048, Prev: 05, Up: Changelog  File: README.info, Node: 048, Next: 047, Prev: 049, Up: Changelog -5.6 0.4.8 +5.7 0.4.8 ========= *Fixed* @@ -1138,7 +1153,7 @@ File: README.info, Node: 048, Next: 047, Prev: 049, Up: Changelog  File: README.info, Node: 047, Next: 046, Prev: 048, Up: Changelog -5.7 0.4.7 +5.8 0.4.7 ========= *Fixed* @@ -1151,7 +1166,7 @@ File: README.info, Node: 047, Next: 046, Prev: 048, Up: Changelog  File: README.info, Node: 046, Next: 045, Prev: 047, Up: Changelog -5.8 0.4.6 +5.9 0.4.6 ========= *Fixed* @@ -1164,8 +1179,8 @@ File: README.info, Node: 046, Next: 045, Prev: 047, Up: Changelog  File: README.info, Node: 045, Next: 044, Prev: 046, Up: Changelog -5.9 0.4.5 -========= +5.10 0.4.5 +========== *Fixed* • Non-case-folding predicates like ‘(todo)’ unnecessarily disabled @@ -1176,7 +1191,7 @@ File: README.info, Node: 045, Next: 044, Prev: 046, Up: Changelog  File: README.info, Node: 044, Next: 043, Prev: 045, Up: Changelog -5.10 0.4.4 +5.11 0.4.4 ========== *Fixed* @@ -1188,7 +1203,7 @@ File: README.info, Node: 044, Next: 043, Prev: 045, Up: Changelog  File: README.info, Node: 043, Next: 042, Prev: 044, Up: Changelog -5.11 0.4.3 +5.12 0.4.3 ========== *Fixed* @@ -1198,7 +1213,7 @@ File: README.info, Node: 043, Next: 042, Prev: 044, Up: Changelog  File: README.info, Node: 042, Next: 041, Prev: 043, Up: Changelog -5.12 0.4.2 +5.13 0.4.2 ========== *Fixed* @@ -1207,7 +1222,7 @@ File: README.info, Node: 042, Next: 041, Prev: 043, Up: Changelog  File: README.info, Node: 041, Next: 04, Prev: 042, Up: Changelog -5.13 0.4.1 +5.14 0.4.1 ========== *Fixed* @@ -1217,7 +1232,7 @@ File: README.info, Node: 041, Next: 04, Prev: 042, Up: Changelog  File: README.info, Node: 04, Next: 032, Prev: 041, Up: Changelog -5.14 0.4 +5.15 0.4 ======== _Note:_ The next release, 0.5, may include changes which will require @@ -1298,7 +1313,7 @@ as they will be pushed to the master branch when ready.  File: README.info, Node: 032, Next: 031, Prev: 04, Up: Changelog -5.15 0.3.2 +5.16 0.3.2 ========== *Fixed* @@ -1311,7 +1326,7 @@ File: README.info, Node: 032, Next: 031, Prev: 04, Up: Changelog  File: README.info, Node: 031, Next: 03, Prev: 032, Up: Changelog -5.16 0.3.1 +5.17 0.3.1 ========== *Fixed* @@ -1321,7 +1336,7 @@ File: README.info, Node: 031, Next: 03, Prev: 032, Up: Changelog  File: README.info, Node: 03, Next: 023, Prev: 031, Up: Changelog -5.17 0.3 +5.18 0.3 ======== *Added* @@ -1386,7 +1401,7 @@ File: README.info, Node: 03, Next: 023, Prev: 031, Up: Changelog  File: README.info, Node: 023, Next: 022, Prev: 03, Up: Changelog -5.18 0.2.3 +5.19 0.2.3 ========== *Fixed* @@ -1396,7 +1411,7 @@ File: README.info, Node: 023, Next: 022, Prev: 03, Up: Changelog  File: README.info, Node: 022, Next: 021, Prev: 023, Up: Changelog -5.19 0.2.2 +5.20 0.2.2 ========== *Fixed* @@ -1407,7 +1422,7 @@ File: README.info, Node: 022, Next: 021, Prev: 023, Up: Changelog  File: README.info, Node: 021, Next: 02, Prev: 022, Up: Changelog -5.20 0.2.1 +5.21 0.2.1 ========== *Fixed* @@ -1417,7 +1432,7 @@ File: README.info, Node: 021, Next: 02, Prev: 022, Up: Changelog  File: README.info, Node: 02, Next: 01, Prev: 021, Up: Changelog -5.21 0.2 +5.22 0.2 ======== *Added* @@ -1500,7 +1515,7 @@ File: README.info, Node: 02, Next: 01, Prev: 021, Up: Changelog  File: README.info, Node: 01, Prev: 02, Up: Changelog -5.22 0.1 +5.23 0.1 ======== First tagged release. @@ -1558,58 +1573,59 @@ GPLv3  Tag Table: Node: Top225 -Node: Contents1689 -Node: Screenshots1812 -Node: Installation1930 -Node: Quelpa2426 -Node: Helm support2954 -Node: Usage3345 -Node: Commands3743 -Node: org-ql-search4216 -Node: helm-org-ql5866 -Node: org-ql-view6226 -Node: org-ql-view-sidebar6726 -Node: org-ql-view-recent-items7082 -Node: org-ql-sparse-tree7566 -Node: Queries8366 -Node: Non-sexp query syntax9477 -Node: General predicates11201 -Node: Ancestor/descendant predicates17422 -Node: Date/time predicates18550 -Node: Functions / Macros21638 -Node: Agenda-like views21936 -Node: Listing / acting-on results23341 -Node: Custom predicates28977 -Node: Dynamic block32636 -Node: Links35348 -Node: Tips36035 -Node: Changelog36353 -Node: 0637071 -Node: 05240070 -Node: 05140370 -Node: 0540787 -Node: 04942261 -Node: 04842535 -Node: 04742882 -Node: 04643277 -Node: 04543677 -Node: 04444036 -Node: 04344395 -Node: 04244592 -Node: 04144753 -Node: 0444994 -Node: 03248927 -Node: 03149306 -Node: 0349503 -Node: 02352478 -Node: 02252706 -Node: 02152974 -Node: 0253173 -Node: 0157208 -Node: Notes57309 -Node: Comparison with Org Agenda searches57471 -Node: org-sidebar58343 -Node: License58622 +Node: Contents1709 +Node: Screenshots1832 +Node: Installation1950 +Node: Quelpa2446 +Node: Helm support2974 +Node: Usage3365 +Node: Commands3763 +Node: org-ql-search4236 +Node: helm-org-ql5886 +Node: org-ql-view6246 +Node: org-ql-view-sidebar6746 +Node: org-ql-view-recent-items7102 +Node: org-ql-sparse-tree7586 +Node: Queries8386 +Node: Non-sexp query syntax9497 +Node: General predicates11221 +Node: Ancestor/descendant predicates17442 +Node: Date/time predicates18570 +Node: Functions / Macros21658 +Node: Agenda-like views21956 +Node: Listing / acting-on results23361 +Node: Custom predicates28997 +Node: Dynamic block32656 +Node: Links35368 +Node: Tips36055 +Node: Changelog36373 +Node: 07-pre37111 +Node: 0637481 +Node: 05240495 +Node: 05140795 +Node: 0541212 +Node: 04942686 +Node: 04842960 +Node: 04743307 +Node: 04643702 +Node: 04544102 +Node: 04444463 +Node: 04344822 +Node: 04245019 +Node: 04145180 +Node: 0445421 +Node: 03249354 +Node: 03149733 +Node: 0349930 +Node: 02352905 +Node: 02253133 +Node: 02153401 +Node: 0253600 +Node: 0157635 +Node: Notes57736 +Node: Comparison with Org Agenda searches57898 +Node: org-sidebar58770 +Node: License59049  End Tag Table diff --git a/tests/test-org-ql.el b/tests/test-org-ql.el index 0b7f2bb..e8cde6a 100644 --- a/tests/test-org-ql.el +++ b/tests/test-org-ql.el @@ -245,6 +245,13 @@ with keyword arg NOW in PLIST." :to-equal '(link :description "DESCRIPTION" :target "TARGET" :regexp-p t)))) + (describe "(logbook)" + (it "with only string argument" + (expect (org-ql--normalize-query '(logbook "String ending in a period.")) + :to-equal '(logbook "String ending in a period\\\.")) + (expect (org-ql--query-string-to-sexp "logbook:called") + :to-equal '(logbook "called")))) + (describe "(outline-path)" (it "with a regexp metacharacter" ;; Ensures that normalizer doesn't infinitely loop.