diff --git a/README.org b/README.org index 61995fb..457dedd 100644 --- a/README.org +++ b/README.org @@ -233,7 +233,7 @@ Note that the =effort=, =level=, and =priority= predicates do not support compar Arguments are listed next to predicate names, where applicable. + =blocked= :: Return non-nil if current heading is blocked. Calls ~org-entry-blocked-p~, which see. -+ =category (&optional categories)= :: Return non-nil if current heading is in one or more of ~CATEGORIES~ (a list of strings). ++ =category (&rest categories)= :: Return non-nil if current heading is in one or more of ~CATEGORIES~ (a list of strings). + =done= :: Return non-nil if entry's ~TODO~ keyword is in ~org-done-keywords~. + =effort (&optional effort-or-comparator effort)= :: Return non-nil if current heading's effort property matches arguments. The following forms are accepted: ~(effort DURATION)~: Matches if effort is ~DURATION~. ~(effort DURATION DURATION)~: Matches if effort is between DURATIONs, inclusive. ~(effort COMPARATOR DURATION)~: Matches if effort compares to ~DURATION~ with ~COMPARATOR~. ~COMPARATOR~ may be ~<~, ~<=~, ~>~, or ~>=~. ~DURATION~ should be an Org effort string, like =5= or =0:05=. + =habit= :: Return non-nil if entry is a habit. @@ -256,16 +256,16 @@ Arguments are listed next to predicate names, where applicable. - Aliases: ~smart~. - *Note:* By default, this is the default predicate used for plain-string query tokens (i.e. given without a specified predicate). This can be customized with the option ~org-ql-default-predicate~. + ~src (&key lang regexps)~ :: Return non-nil if current entry contains an Org Babel source block. If ~LANG~ is non-nil, match blocks of that language. If ~REGEXPS~ is non-nil, require that block's contents match all regexps. Matching is done case-insensitively. -+ =tags (&optional tags)= :: Return non-nil if current heading has one or more of ~TAGS~ (a list of strings). Tests both inherited and local tags. -+ =tags-inherited (&optional tags)= :: Return non-nil if current heading's inherited tags include one or more of ~TAGS~ (a list of strings). If ~TAGS~ is nil, return non-nil if heading has any inherited tags. ++ =tags (&rest tags)= :: Return non-nil if current heading has one or more of ~TAGS~ (a list of strings). Tests both inherited and local tags. ++ =tags-inherited (&rest tags)= :: Return non-nil if current heading's inherited tags include one or more of ~TAGS~ (a list of strings). If ~TAGS~ is nil, return non-nil if heading has any inherited tags. - Aliases: ~inherited-tags~, ~tags-i~, ~itags~. -+ =tags-local (&optional tags)= :: Return non-nil if current heading's local tags include one or more of ~TAGS~ (a list of strings). If ~TAGS~ is nil, return non-nil if heading has any local tags. ++ =tags-local (&rest tags)= :: Return non-nil if current heading's local tags include one or more of ~TAGS~ (a list of strings). If ~TAGS~ is nil, return non-nil if heading has any local tags. - Aliases: ~local-tags~, ~tags-l~, ~ltags~. -+ =tags-all (tags)= :: Return non-nil if current heading includes all of ~TAGS~. Tests both inherited and local tags. ++ =tags-all (&rest tags)= :: Return non-nil if current heading includes all of ~TAGS~. Tests both inherited and local tags. - Aliases: ~tags&~. + =tags-regexp (&rest regexps)= :: Return non-nil if current heading has tags matching one or more of ~REGEXPS~. Tests both inherited and local tags. - Aliases: ~tags*~. -+ =todo (&optional keywords)= :: Return non-nil if current heading is a ~TODO~ item. With ~KEYWORDS~, return non-nil if its keyword is one of ~KEYWORDS~ (a list of strings). When called without arguments, only matches non-done tasks (i.e. does not match keywords in ~org-done-keywords~). ++ =todo (&rest keywords)= :: Return non-nil if current heading is a ~TODO~ item. With ~KEYWORDS~, return non-nil if its keyword is one of ~KEYWORDS~ (a list of strings). When called without arguments, only matches non-done tasks (i.e. does not match keywords in ~org-done-keywords~). *** Ancestor/descendant predicates @@ -556,13 +556,46 @@ Simple links may also be written manually in either sexp or non-sexp form, like: ** 0.9-pre -*Compatibility* -+ Fix compilation error on Emacs 30. ([[https://github.com/alphapapa/org-ql/issues/433][#433]]. Thanks to [[https://github.com/akirak][Akira Komamura]] and [[https://github.com/monnier][Stefan Monnier]].) +*Additions* ++ Face ~org-ql-view-query~, applied to view queries in header line. ++ Face ~org-ql-view-title~, applied to view titles in header line. ++ Option ~org-ql-view-relative-deadline-prefix~. + +*Changes* ++ Command ~org-ql-find~ respects narrowing of the current buffer by default, allowing searching within the narrowed region. (Using one ~C-u~ argument widens the current buffer, and using two ~C-u~ arguments prompts for the buffers to search.) ++ Function ~org-ql-completing-read~ accepts a new ~NARROWP~ argument, which is passed to ~org-ql-select~. + +*Fixes* ++ Customization group for face ~org-ql-view-due-date~. ++ Apply Org syntax font-locking to items in ~org-ql-view~ buffers. *** helm-org-ql Tagged v0.6.2, fixing a compilation warning. +** 0.8.10 + +*Fixes* ++ Command ~org-ql-refile~ uses the base buffer when refiling to an indirect buffer. ([[https://github.com/alphapapa/org-ql/issues/466][#466]].) ++ Predicate ~link~ could signal an error when searching text that is mistakenly recognized as an Org link (e.g. Bash double-bracket constructs in a source block). (Thanks to [[https://github.com/jwiegley][John Wiegley]] for reporting.) + +** 0.8.9 + +*Fixes* ++ Predicate ~property~ when called with argument form ~(property "PROPERTY-NAME" :inherit t)~. ([[https://github.com/alphapapa/org-ql/issues/460][#460]]. Thanks to [[https://github.com/Stewmath][Stewmath]] for reporting.) ++ Predicate ~level~'s preamble optimizer allows expressions in place of the numeric argument. (See [[https://github.com/alphapapa/org-ql/issues/460][#460]]. Thanks to [[https://github.com/Stewmath][Stewmath]] for reporting.) ++ Reading of view settings from Org links in upcoming Emacs version. ([[https://github.com/alphapapa/org-ql/issues/461][#461]]. Thanks to [[https://github.com/snogge][Ola Nilsson]] for help debugging, and for maintaining [[https://github.com/jorgenschaefer/emacs-buttercup][Buttercup]].) + +*Compatibility* ++ Fix compilation error on Emacs 30. ([[https://github.com/alphapapa/org-ql/issues/433][#433]]. Thanks to [[https://github.com/akirak][Akira Komamura]] and [[https://github.com/monnier][Stefan Monnier]].) + +** 0.8.8 + +*Fixes* ++ Remove text properties from to-do keywords before displaying them in an ~org-ql-view~ buffer. (Such text properties could cause them to, e.g. display with extra leading spaces, depending on which other modes might be enabled in the source Org buffer.) ++ Binding of ~completion-styles-alist~ in ~org-ql-completing-read~. (This fixes compatibility with Helm's ~helm~ completion style, as well as default Emacs completion in recursive minibuffers. [[https://github.com/alphapapa/org-ql/issues/337][#337]]. Thanks to [[https://github.com/progfolio][Nicholas Vollmer]], [[https://github.com/9viz][viz]], and [[https://github.com/karthink][Karthik Chikmagalur]] for reporting and suggesting fixes.) ++ Use of the context snippet function for ~org-ql-completing-read~. ([[https://github.com/alphapapa/org-ql/issues/419][#419]]. Thanks to [[https://github.com/tpeacock19][tpeacock19]] for reporting.) + ** 0.8.7 *Fixes* diff --git a/org-ql-completing-read.el b/org-ql-completing-read.el index 18cfd7f..93dbf00 100644 --- a/org-ql-completing-read.el +++ b/org-ql-completing-read.el @@ -50,12 +50,10 @@ :type 'boolean) (defcustom org-ql-completing-read-snippet-function #'org-ql-completing-read--snippet-simple - ;; TODO: I'd like to make the -regexp one the default, but with - ;; default Emacs completion affixation, it can sometimes be a bit - ;; slow, and I don't want that to be a user's first impression. It - ;; may be possible to further optimize the -regexp one so that it - ;; can be used by default. In the meantime, the -simple one seems - ;; fast enough for general use. + ;; TODO(v0.9): Performance of completion annotations seems to be + ;; much improved now (whether due to changes in Emacs, Vertico, or + ;; both, I don't know). It may be reasonable to make the context + ;; snippet the default now. "Function used to annotate results in `org-ql-completing-read'. Function is called at entry beginning. (When set to `org-ql-completing-read--snippet-regexp', it is called with a @@ -109,11 +107,13 @@ value, or nil." ;; responsive as, e.g. Helm while typing, but it seems to ;; help a little when using the org-rifle-style snippets. (org-with-point-at marker - (or (funcall org-ql-completing-read-snippet-function) + (or (funcall org-ql-completing-read-snippet-function + org-ql-completing-read-input-regexp) (org-ql-completing-read--snippet-simple)))) (`t ;; Interrupted: return nil (which can be concatted). nil) - (else else))) + (else (propertize (concat " " else) + 'face 'org-ql-completing-read-snippet)))) (defun org-ql-completing-read-path (marker) "Return formatted outline path for entry at MARKER." @@ -134,7 +134,7 @@ value, or nil." ;;;###autoload (cl-defun org-ql-completing-read - (buffers-files &key query-prefix query-filter + (buffers-files &key query-prefix query-filter narrowp (action #'org-ql-completing-read-action) ;; FIXME: Unused argument. ;; (annotate #'org-ql-completing-read-snippet) @@ -145,6 +145,8 @@ value, or nil." "Return marker at entry in BUFFERS-FILES selected with `org-ql'. PROMPT is shown to the user. +NARROWP is passed to `org-ql-select', which see. + QUERY-PREFIX may be a string to prepend to the query entered by the user (e.g. use \"heading:\" to only search headings, easily creating a custom command that saves the user from having to type @@ -217,15 +219,7 @@ single predicate)." ;; Using `while-no-input' here doesn't make it as responsive as, ;; e.g. Helm while typing, but it seems to help a little when using the ;; org-rifle-style snippets. - (or (snippet (get-text-property 0 'org-marker candidate)) ""))) - (snippet (marker) - (when-let - ((snippet - (org-with-point-at marker - (or (funcall org-ql-completing-read-snippet-function org-ql-completing-read-input-regexp) - (org-ql-completing-read--snippet-simple))))) - (propertize (concat " " snippet) - 'face 'org-ql-completing-read-snippet))) + (or (funcall snippet (get-text-property 0 'org-marker candidate)) ""))) (group (candidate transform) (pcase transform (`nil (buffer-name (marker-buffer (get-text-property 0 'org-marker candidate)))) @@ -323,6 +317,7 @@ single predicate)." bow (or ,@query-tokens) (0+ (not space)) (optional (repeat 1 3 (0+ space) (repeat 1 15 (not space)))))))) (org-ql-select buffers-files (org-ql--query-string-to-sexp input) + :narrow narrowp :action #'action)))) (unless (listp buffers-files) ;; Since we map across this argument, we ensure it's a list. @@ -338,7 +333,8 @@ single predicate)." ;; `completing-read'. (mapc #'org-ql--ensure-buffer buffers-files) (let* ((completion-styles '(org-ql-completing-read)) - (completion-styles-alist (list (list 'org-ql-completing-read #'try #'all "Org QL Find"))) + (completion-styles-alist (cons (list 'org-ql-completing-read #'try #'all "Org QL Find") + completion-styles-alist)) (selected (minibuffer-with-setup-hook (lambda () @@ -370,7 +366,7 @@ single predicate)." (car (hash-table-values table)) (user-error "No results for input")))))) -(defun org-ql-completing-read--snippet-simple () +(defun org-ql-completing-read--snippet-simple (&optional _input-regexp) "Return a snippet of the current entry. Returns up to `org-ql-completing-read-snippet-length' characters." (save-excursion @@ -384,15 +380,15 @@ Returns up to `org-ql-completing-read-snippet-length' characters." t t) 50 nil nil t)))))) -(defun org-ql-completing-read--snippet-regexp (regexp) - "Return a snippet of the current entry's matches for REGEXP." +(defun org-ql-completing-read--snippet-regexp (&optional input-regexp) + "Return a snippet of the current entry's matches for INPUT-REGEXP." ;; REGEXP may be nil if there are no qualifying tokens in the query. - (when regexp + (when input-regexp (save-excursion (org-end-of-meta-data t) (unless (org-at-heading-p) (let* ((end (org-entry-end-position)) - (snippets (cl-loop while (re-search-forward regexp end t) + (snippets (cl-loop while (re-search-forward input-regexp end t) concat (match-string 0) concat "…" do (goto-char (match-end 0))))) (unless (string-empty-p snippets) diff --git a/org-ql-find.el b/org-ql-find.el index 820d2dd..e6c4795 100644 --- a/org-ql-find.el +++ b/org-ql-find.el @@ -54,14 +54,18 @@ See function `display-buffer'." ;;;; Commands ;;;###autoload -(cl-defun org-ql-find (buffers-files &key query-prefix query-filter +(cl-defun org-ql-find (buffers-files &key query-prefix query-filter widen (prompt "Find entry: ")) "Go to an Org entry in BUFFERS-FILES selected by searching entries with `org-ql'. Interactively, search the buffers and files relevant to the current buffer (i.e. in `org-agenda-mode', the value of `org-ql-view-buffers-files' or `org-agenda-contributing-files'; -in `org-mode', that buffer). With universal prefix, select -multiple buffers to search with completion and PROMPT. +in `org-mode', that buffer). + +With one or more universal prefix arguments, WIDEN buffers before +searching (otherwise, respect any narrowing). With two universal +prefix arguments, select multiple buffers to search with +completion and PROMPT. QUERY-PREFIX may be a string to prepend to the query (e.g. use \"heading:\" to only search headings, easily creating a custom @@ -72,11 +76,17 @@ types is filtered before execution (e.g. it could replace spaces with commas to turn multiple tokens, which would normally be treated as multiple predicates, into multiple arguments to a single predicate)." - (interactive (list (org-ql-find--buffers))) - (let ((marker (org-ql-completing-read buffers-files - :query-prefix query-prefix - :query-filter query-filter - :prompt prompt))) + (interactive (list (org-ql-find--buffers + :read-buffer-p (equal '(16) current-prefix-arg)) + :widen current-prefix-arg)) + (let ((marker (save-restriction + (when (and widen (equal (current-buffer) buffers-files)) + (widen)) + (org-ql-completing-read buffers-files + :narrowp (not widen) + :query-prefix query-prefix + :query-filter query-filter + :prompt prompt)))) (set-buffer (or (buffer-base-buffer (marker-buffer marker)) (marker-buffer marker))) (pop-to-buffer (current-buffer) org-ql-find-display-buffer-action) @@ -112,18 +122,20 @@ which see (but only the files are used)." ((and (pred listp) files) files))) (list files-spec))))))) (list (org-ql-completing-read buffers-files :prompt "Refile to: ")))) - (org-refile nil nil - ;; The RFLOC argument: - (list - ;; Name - (org-with-point-at marker - (nth 4 (org-heading-components))) - ;; File - (buffer-file-name (marker-buffer marker)) - ;; nil - nil - ;; Position - marker))) + (let ((buffer (or (buffer-base-buffer (marker-buffer marker)) + (marker-buffer marker)))) + (org-refile nil nil + ;; The RFLOC argument: + (list + ;; Name + (org-with-point-at marker + (nth 4 (org-heading-components))) + ;; File + (buffer-file-name buffer) + ;; nil + nil + ;; Position + marker)))) ;;;###autoload (defun org-ql-find-in-agenda () @@ -195,15 +207,15 @@ multiple buffers to search with completion and PROMPT." ;;;; Functions -(defun org-ql-find--buffers () - "Return list of buffers to search in. +(cl-defun org-ql-find--buffers (&key read-buffer-p) + "Return buffer or list of buffers to search in. In a mode derived from `org-agenda-mode', return the value of `org-ql-view-buffers-files' or `org-agenda-contributing-files'. -In a mode derived from `org-mode', return the current buffer. -When `current-prefix-arg', read a list of buffers in `org-mode' -with completion. To be used in `org-ql-find' commands' -interactive forms." - (if current-prefix-arg +In a mode derived from `org-mode', return the current buffer. If +READ-BUFFER-P, read a list of buffers in `org-mode' with +completion. To be used in `org-ql-find' commands' interactive +forms." + (if read-buffer-p (mapcar #'get-buffer (completing-read-multiple "Buffers: " diff --git a/org-ql-search.el b/org-ql-search.el index 9c0aa86..6fe0e55 100644 --- a/org-ql-search.el +++ b/org-ql-search.el @@ -225,19 +225,25 @@ necessary." (org-ql-view--display :buffer buffer :header header :strings strings)))) ;;;###autoload -(defun org-ql-search-block (query) - "Insert items for QUERY into current buffer. -QUERY should be an `org-ql' query form. Intended to be used as a -user-defined function in `org-agenda-custom-commands'. QUERY -corresponds to the `match' item in the custom command form. +(defun org-ql-search-block (args) + "Insert items for ARGS into current buffer. +Intended to be used as a user-defined function in +`org-agenda-custom-commands'. ARGS corresponds to the `match' +item in the custom command form. It should be a list of +arguments which may be applied to `org-ql-select', which see, but +not including its BUFFERS-FILES argument (which is supplied +through the Agenda). An additional `:header' keyword argument +may be supplied as a string, like that supplied to +`org-ql-view--display'. Like other agenda block commands, it searches files returned by function `org-agenda-files'. Inserts a newline after the block. If `org-ql-block-header' is non-nil, it is used as the header -string for the block, otherwise a the header is formed +string for the block, otherwise the header is formed automatically from the query." - (let (narrow-p old-beg old-end) + (pcase-let ((`(,query . ,(map :header :sort)) args) + (narrow-p) (old-beg) (old-end)) (when-let* ((from (pcase org-agenda-restrict ('nil (org-agenda-files nil 'ifmode)) (_ (prog1 org-agenda-restrict @@ -248,7 +254,7 @@ automatically from the query." (narrow-to-region org-agenda-restrict-begin org-agenda-restrict-end)))))) (items (org-ql-select from query :action 'element-with-markers - :narrow narrow-p))) + :narrow narrow-p :sort sort))) (when narrow-p ;; Restore buffer's previous restrictions. (with-current-buffer from @@ -258,16 +264,25 @@ automatically from the query." ;; FIXME: `org-agenda--insert-overriding-header' is from an Org version newer than ;; I'm using. Should probably declare it as a minimum Org version after upgrading. ;; (org-agenda--insert-overriding-header (or org-ql-block-header (org-ql-agenda--header-line-format from query))) - (insert (org-add-props (or org-ql-block-header (org-ql-view--header-line-format - :buffers-files from :query query)) + ;; FIXME: Should we really use `org-ql-block-header' AND `header', or just one of them? + (insert (org-add-props (or org-ql-block-header header + (org-ql-view--header-line-format + :buffers-files from :query query)) nil 'face 'org-agenda-structure) "\n") ;; Calling `org-agenda-finalize' should be unnecessary, because in a "series" agenda, ;; `org-agenda-multi' is bound non-nil, in which case `org-agenda-finalize' does nothing. ;; But we do call `org-agenda-finalize-entries', which allows `org-super-agenda' to work. - (->> items - (-map #'org-ql-view--format-element) - org-agenda-finalize-entries - insert) + ;; However, `org-agenda-finalize-entries' sorts entries with `org-entries-lessp', which + ;; overrides the sorting `org-ql' has already done, so we rebind `org-entries-lessp' to + ;; prevent it from affecting sort order. (Ideally we would let `org-entries-lessp' + ;; handle sorting, but that's not possible, because we can't add the `type' text property + ;; it uses to sort entries, because the design of org-ql and org-agenda is fundamentally + ;; different. So we have to do the sorting ourselves.) + (cl-letf (((symbol-function 'org-entries-lessp) #'ignore)) + (->> items + (-map #'org-ql-view--format-element) + org-agenda-finalize-entries + insert)) (insert "\n")))) ;;;###autoload diff --git a/org-ql-view.el b/org-ql-view.el index 04e7383..8d65582 100644 --- a/org-ql-view.el +++ b/org-ql-view.el @@ -57,7 +57,18 @@ (defface org-ql-view-due-date '((t (:slant italic :weight bold))) "Face for due dates in `org-ql-view' views." - :group 'org-ql) + :group 'org-ql-view) + +(defface org-ql-view-query nil + "View query in header line. +This face is added to the formatted query after font-lock faces +are applied to it. It may be used, e.g. to reduce the height so +more of it is visible." + :group 'org-ql-view) + +(defface org-ql-view-title '((t :weight bold)) + "View title in header line." + :group 'org-ql-view) ;;;; Variables @@ -238,6 +249,12 @@ See info node `(elisp)Cyclic Window Ordering'." (sexp :tag "org-super-agenda grouping expression") (variable :tag "Variable holding org-super-agenda grouping expression")))))))) +(defcustom org-ql-view-relative-deadline-prefix "due " + ;; TODO(v0.9): Add one for scheduled, too. + "Prefix for relative deadlines. +Relative deadlines are, e.g. \"in 5d\", \"5d ago\"." + :type 'string) + ;;;; Commands ;;;###autoload @@ -459,7 +476,8 @@ subsequent refreshing of the buffer: `org-ql-view-buffers-files', If TITLE, prepend it to the header." (let* ((title (if title (concat (propertize "View:" 'face 'transient-argument) - title " ") + (propertize title 'face 'org-ql-view-title) + " ") "")) (query-formatted (when query (org-ql-view--format-query query))) @@ -478,6 +496,7 @@ If TITLE, prepend it to the header." (org-ql-view--font-lock-string 'emacs-lisp-mode) (s-truncate available-width)) 'help-echo buffers-files-formatted)))) + (add-face-text-property 0 (length query-propertized) 'org-ql-view-query 'append query-propertized) (concat title (when query (propertize "Query:" 'face 'transient-argument)) (when query query-propertized) @@ -509,6 +528,22 @@ with human-readable strings." (font-lock-ensure) (buffer-string)))) +(defun org-ql-view--font-lock-as-org (s) + "Return string S font-locked as in `org-mode'." + ;; This works like `org-fontify-like-in-org-mode', but uses a single + ;; buffer instead of a new one every time. + ;; TODO(C): Submit these improvements upstream. + (let ((buffer (or (get-buffer " *org-ql-view--font-lock-as-org*") + (with-current-buffer (get-buffer-create " *org-ql-view--font-lock-as-org*") + (buffer-disable-undo) + (org-mode) + (current-buffer))))) + (with-current-buffer buffer + (insert s) + (font-lock-ensure) + (prog1 (buffer-string) + (erase-buffer))))) + (defun org-ql-view--buffer (&optional name) "Return `org-ql-view' buffer, creating it if necessary. If NAME is non-nil, return buffer by that name instead of using @@ -645,6 +680,8 @@ purposes of compatibility with changes in Org 9.4." (stringp buffers-files) (cl-every #'stringp buffers-files)) (error "CAUTION: Link not opened because unsafe buffers-files parameter detected: %s" buffers-files)) + (unless (or (stringp title) (null title)) + (error "CAUTION: Link not opened because unsafe title parameter detected: %S" title)) (when (or (listp query) (string-match (rx bol (0+ space) "(") query)) ;; SAFETY: Query is in sexp form: ask for confirmation, because it could contain arbitrary code. @@ -877,8 +914,14 @@ return an empty string." ;; (which would also make it easier to do it independently of faces, etc). (title (--> (org-ql-view--add-faces element) (org-element-property :raw-value it))) + ;; TODO(B): Needs refactoring. A function like `org-ql-view--add-faces' + ;; should return a list of faces to be added. + (title-faces (get-text-property 0 'face title)) + (title (org-ql-view--font-lock-as-org title)) + (_ (add-face-text-property 0 (length title) title-faces t title)) (todo-keyword (-some--> (org-element-property :todo-keyword element) - (org-ql-view--add-todo-face it))) + (org-ql-view--add-todo-face + (substring-no-properties it)))) (tag-list (if org-use-tag-inheritance ;; MAYBE: Use our own variable instead of `org-use-tag-inheritance'. (if-let ((marker (or (org-element-property :org-hd-marker element) @@ -1013,7 +1056,9 @@ property." (deadline-day-number (org-time-string-to-absolute (org-element-timestamp-interpreter deadline-date 'ignore))) (difference-days (- today-day-number deadline-day-number)) - (relative-due-date (org-add-props (org-ql-view--format-relative-date difference-days) nil + (relative-due-date (org-add-props + (concat org-ql-view-relative-deadline-prefix + (org-ql-view--format-relative-date difference-days)) nil 'help-echo (org-element-property :raw-value deadline-date))) ;; FIXME: Unused for now: (todo-keyword (org-element-property :todo-keyword element)) ;; FIXME: Unused for now: (done-p (member todo-keyword org-done-keywords)) diff --git a/org-ql.el b/org-ql.el index 811bd92..f3b7715 100644 --- a/org-ql.el +++ b/org-ql.el @@ -1144,7 +1144,7 @@ defined in `org-ql-predicates' by calling `org-ql-defpred'." (byte-compile 'org-ql--query-preamble))) (cl-defmacro org-ql-defpred (name args docstring &key body preambles normalizers coalesce) - "Define an Org QL selector predicate `org-ql--predicate-NAME'. + "Define an Org QL selector predicate \\=`org-ql--predicate-NAME'. NAME may be a symbol or a list of symbols: if a list, the first is used as NAME and the rest are aliases. A function is only created for NAME, not for aliases, so a normalizer should be used @@ -1537,7 +1537,8 @@ COMPARATOR may be `<', `<=', `>', or `>='." ;; is "h:" while the user is typing. (list :regexp (rx bol (1+ "*") " ") :case-fold t)) - (`(,predicate-names ,comparator-or-num ,num) + ((and `(,predicate-names ,comparator-or-num ,num) + (guard (numberp num))) (let ((repeat (pcase comparator-or-num ('< `(repeat 1 ,(1- num) "*")) ('<= `(repeat 1 ,num "*")) @@ -1546,7 +1547,8 @@ COMPARATOR may be `<', `<=', `>', or `>='." ((pred integerp) `(repeat ,comparator-or-num ,num "*"))))) (list :regexp (rx-to-string `(seq bol ,repeat " ") t) :case-fold t))) - (`(,predicate-names ,num) + ((and `(,predicate-names ,num) + (guard (numberp num))) (list :regexp (rx-to-string `(seq bol (repeat ,num "*") " ") t) :case-fold t))) ;; NOTE: It might be necessary to take into account `org-odd-levels'; see docstring for @@ -1624,11 +1626,15 @@ any link is found." (or (null description) (string-match-p description (match-string org-ql-link-description-group))))) (_ (if (and description target) - (and (string-match-p target (match-string 1)) - (string-match-p description (match-string org-ql-link-description-group))) - (or (string-match-p description-or-target (match-string 1)) - (string-match-p description-or-target - (match-string org-ql-link-description-group))))))))) + (and (and (match-string 1) + (string-match-p target (match-string 1))) + (and (match-string org-ql-link-description-group) + (string-match-p description (match-string org-ql-link-description-group)))) + (or (and (match-string 1) + (string-match-p description-or-target (match-string 1))) + (and (match-string org-ql-link-description-group) + (string-match-p description-or-target + (match-string org-ql-link-description-group)))))))))) (org-ql-defpred (rifle smart) (&rest strings) "Return non-nil if each of strings is found in the entry or its outline path. @@ -1802,34 +1808,62 @@ interpreted as nil or non-nil)." ;; predicate test for whether an entry has local ;; properties when no arguments are given. (list 'property "")) - (`(,predicate-names ,property ,value . ,plist) + (`(,predicate-names ,property) ;; Convert keyword property arguments to strings. Non-sexp ;; queries result in keyword property arguments (because to do ;; otherwise would require ugly special-casing in the parsing). (when (keywordp property) (setf property (substring (symbol-name property) 1))) - (list 'property property value - :inherit (cond ((plist-member plist :inherit) (plist-get plist :inherit)) - ((listp org-use-property-inheritance) ''selective) - (t org-use-property-inheritance))))) + (list 'property property)) + (`(,predicate-names ,property . ,rest) + (pcase rest + (`(,value) + ;; Convert keyword property arguments to strings. Non-sexp + ;; queries result in keyword property arguments (because to do + ;; otherwise would require ugly special-casing in the parsing). + (when (keywordp property) + (setf property (substring (symbol-name property) 1))) + (list 'property property value)) + ((and `(,value . ,plist) + (guard (not (keywordp value)))) + ;; Convert keyword property arguments to strings. Non-sexp + ;; queries result in keyword property arguments (because to do + ;; otherwise would require ugly special-casing in the parsing). + (when (keywordp property) + (setf property (substring (symbol-name property) 1))) + (list 'property property value + :inherit (cond ((plist-member plist :inherit) (plist-get plist :inherit)) + ((listp org-use-property-inheritance) ''selective) + (t org-use-property-inheritance)))) + ((and plist (guard (keywordp (car rest)))) + ;; Convert keyword property arguments to strings. Non-sexp + ;; queries result in keyword property arguments (because to do + ;; otherwise would require ugly special-casing in the parsing). + (when (keywordp property) + (setf property (substring (symbol-name property) 1))) + (list 'property property nil + :inherit (cond ((plist-member plist :inherit) (plist-get plist :inherit)) + ((listp org-use-property-inheritance) ''selective) + (t org-use-property-inheritance))))))) ;; MAYBE: Should case folding be disabled for properties? What about values? ;; MAYBE: Support (property) without args. ;; NOTE: When inheritance is enabled, the preamble can't be used, ;; which will make the search slower. - :preambles ((`(,predicate-names ,property ,value . ,(map :inherit)) + :preambles (((and `(,predicate-names ,property ,value) + (guard (atom value))) ;; We do NOT return nil, because the predicate still needs to be tested, ;; because the regexp could match a string not inside a property drawer. - (list :regexp (unless inherit - (rx-to-string `(seq bol (0+ space) ":" ,property ":" - (1+ space) ,value (0+ space) eol))) + (list :regexp (rx-to-string `(seq bol (0+ space) ":" ,property ":" + (1+ space) ,value (0+ space) eol)) :query query)) - (`(,predicate-names ,property . ,(map :inherit)) - ;; We do NOT return nil, because the predicate still needs to be tested, + ((and `(,predicate-names ,property ,value . ,plist) + (guard (keywordp (car plist)))) + ;; WE do NOT return nil, because the predicate still needs to be tested, ;; because the regexp could match a string not inside a property drawer. ;; NOTE: The preamble only matches if there appears to be a value. ;; A line like ":ID: " without any other text does not match. - (list :regexp (unless inherit + (list :regexp (unless (plist-get plist :inherit) (rx-to-string `(seq bol (0+ space) ":" ,property ":" (1+ space) (minimal-match (1+ not-newline)) eol))) :query query))) @@ -1841,7 +1875,7 @@ interpreted as nil or non-nil)." ;; Check that PROPERTY exists (org-ql--value-at (point) (lambda () - (org-entry-get (point) property)))) + (org-entry-get (point) property inherit)))) (_ ;; Check that PROPERTY has VALUE. diff --git a/org-ql.info b/org-ql.info index c2641b7..7f08c68 100644 --- a/org-ql.info +++ b/org-ql.info @@ -74,6 +74,9 @@ Functions / Macros Changelog * 0.9-pre: 09-pre. +* 0.8.10: 0810. +* 0.8.9: 089. +* 0.8.8: 088. * 0.8.7: 087. * 0.8.6: 086. * 0.8.5: 085. @@ -1046,6 +1049,9 @@ releases. * Menu: * 0.9-pre: 09-pre. +* 0.8.10: 0810. +* 0.8.9: 089. +* 0.8.8: 088. * 0.8.7: 087. * 0.8.6: 086. * 0.8.5: 085. @@ -1086,16 +1092,27 @@ releases. * 0.1: 01.  -File: README.info, Node: 09-pre, Next: 087, Up: Changelog +File: README.info, Node: 09-pre, Next: 0810, Up: Changelog 5.1 0.9-pre =========== -*Compatibility* - • Fix compilation error on Emacs 30. (#433 - (https://github.com/alphapapa/org-ql/issues/433). Thanks to Akira - Komamura (https://github.com/akirak) and Stefan Monnier - (https://github.com/monnier).) +*Additions* + • Face ‘org-ql-view-query’, applied to view queries in header line. + • Face ‘org-ql-view-title’, applied to view titles in header line. + • Option ‘org-ql-view-relative-deadline-prefix’. + + *Changes* + • Command ‘org-ql-find’ respects narrowing of the current buffer by + default, allowing searching within the narrowed region. (Using one + ‘C-u’ argument widens the current buffer, and using two ‘C-u’ + arguments prompts for the buffers to search.) + • Function ‘org-ql-completing-read’ accepts a new ‘NARROWP’ argument, + which is passed to ‘org-ql-select’. + + *Fixes* + • Customization group for face ‘org-ql-view-due-date’. + • Apply Org syntax font-locking to items in ‘org-ql-view’ buffers. * Menu: @@ -1110,9 +1127,73 @@ File: README.info, Node: helm-org-ql (1), Up: 09-pre Tagged v0.6.2, fixing a compilation warning.  -File: README.info, Node: 087, Next: 086, Prev: 09-pre, Up: Changelog +File: README.info, Node: 0810, Next: 089, Prev: 09-pre, Up: Changelog -5.2 0.8.7 +5.2 0.8.10 +========== + +*Fixes* + • Command ‘org-ql-refile’ uses the base buffer when refiling to an + indirect buffer. (#466 + (https://github.com/alphapapa/org-ql/issues/466).) + • Predicate ‘link’ could signal an error when searching text that is + mistakenly recognized as an Org link (e.g. Bash double-bracket + constructs in a source block). (Thanks to John Wiegley + (https://github.com/jwiegley) for reporting.) + + +File: README.info, Node: 089, Next: 088, Prev: 0810, Up: Changelog + +5.3 0.8.9 +========= + +*Fixes* + • Predicate ‘property’ when called with argument form ‘(property + "PROPERTY-NAME" :inherit t)’. (#460 + (https://github.com/alphapapa/org-ql/issues/460). Thanks to + Stewmath (https://github.com/Stewmath) for reporting.) + • Predicate ‘level’’s preamble optimizer allows expressions in place + of the numeric argument. (See #460 + (https://github.com/alphapapa/org-ql/issues/460). Thanks to + Stewmath (https://github.com/Stewmath) for reporting.) + • Reading of view settings from Org links in upcoming Emacs version. + (#461 (https://github.com/alphapapa/org-ql/issues/461). Thanks to + Ola Nilsson (https://github.com/snogge) for help debugging, and for + maintaining Buttercup + (https://github.com/jorgenschaefer/emacs-buttercup).) + + *Compatibility* + • Fix compilation error on Emacs 30. (#433 + (https://github.com/alphapapa/org-ql/issues/433). Thanks to Akira + Komamura (https://github.com/akirak) and Stefan Monnier + (https://github.com/monnier).) + + +File: README.info, Node: 088, Next: 087, Prev: 089, Up: Changelog + +5.4 0.8.8 +========= + +*Fixes* + • Remove text properties from to-do keywords before displaying them + in an ‘org-ql-view’ buffer. (Such text properties could cause them + to, e.g. display with extra leading spaces, depending on which + other modes might be enabled in the source Org buffer.) + • Binding of ‘completion-styles-alist’ in ‘org-ql-completing-read’. + (This fixes compatibility with Helm’s ‘helm’ completion style, as + well as default Emacs completion in recursive minibuffers. #337 + (https://github.com/alphapapa/org-ql/issues/337). Thanks to + Nicholas Vollmer (https://github.com/progfolio), viz + (https://github.com/9viz), and Karthik Chikmagalur + (https://github.com/karthink) for reporting and suggesting fixes.) + • Use of the context snippet function for ‘org-ql-completing-read’. + (#419 (https://github.com/alphapapa/org-ql/issues/419). Thanks to + tpeacock19 (https://github.com/tpeacock19) for reporting.) + + +File: README.info, Node: 087, Next: 086, Prev: 088, Up: Changelog + +5.5 0.8.7 ========= *Fixes* @@ -1140,7 +1221,7 @@ File: README.info, Node: 087, Next: 086, Prev: 09-pre, Up: Changelog  File: README.info, Node: 086, Next: 085, Prev: 087, Up: Changelog -5.3 0.8.6 +5.6 0.8.6 ========= *Fixes* @@ -1150,7 +1231,7 @@ File: README.info, Node: 086, Next: 085, Prev: 087, Up: Changelog  File: README.info, Node: 085, Next: 084, Prev: 086, Up: Changelog -5.4 0.8.5 +5.7 0.8.5 ========= *Fixes* @@ -1167,7 +1248,7 @@ File: README.info, Node: 085, Next: 084, Prev: 086, Up: Changelog  File: README.info, Node: 084, Next: 083, Prev: 085, Up: Changelog -5.5 0.8.4 +5.8 0.8.4 ========= *Fixes* @@ -1181,7 +1262,7 @@ File: README.info, Node: 084, Next: 083, Prev: 085, Up: Changelog  File: README.info, Node: 083, Next: 082, Prev: 084, Up: Changelog -5.6 0.8.3 +5.9 0.8.3 ========= *Fixes* @@ -1194,8 +1275,8 @@ File: README.info, Node: 083, Next: 082, Prev: 084, Up: Changelog  File: README.info, Node: 082, Next: 081, Prev: 083, Up: Changelog -5.7 0.8.2 -========= +5.10 0.8.2 +========== *Fixes* @@ -1208,8 +1289,8 @@ File: README.info, Node: 082, Next: 081, Prev: 083, Up: Changelog  File: README.info, Node: 081, Next: 08, Prev: 082, Up: Changelog -5.8 0.8.1 -========= +5.11 0.8.1 +========== *Fixes* @@ -1223,8 +1304,8 @@ File: README.info, Node: 081, Next: 08, Prev: 082, Up: Changelog  File: README.info, Node: 08, Next: 074, Prev: 081, Up: Changelog -5.9 0.8 -======= +5.12 0.8 +======== *Additions* @@ -1279,7 +1360,7 @@ File: README.info, Node: 08, Next: 074, Prev: 081, Up: Changelog  File: README.info, Node: 074, Next: 073, Prev: 08, Up: Changelog -5.10 0.7.4 +5.13 0.7.4 ========== *Fixes* @@ -1289,7 +1370,7 @@ File: README.info, Node: 074, Next: 073, Prev: 08, Up: Changelog  File: README.info, Node: 073, Next: 072, Prev: 074, Up: Changelog -5.11 0.7.3 +5.14 0.7.3 ========== *Fixes* @@ -1307,7 +1388,7 @@ File: README.info, Node: 073, Next: 072, Prev: 074, Up: Changelog  File: README.info, Node: 072, Next: 071, Prev: 073, Up: Changelog -5.12 0.7.2 +5.15 0.7.2 ========== *Fixes* @@ -1328,7 +1409,7 @@ File: README.info, Node: 072, Next: 071, Prev: 073, Up: Changelog  File: README.info, Node: 071, Next: 07, Prev: 072, Up: Changelog -5.13 0.7.1 +5.16 0.7.1 ========== *Fixes* @@ -1347,7 +1428,7 @@ File: README.info, Node: 071, Next: 07, Prev: 072, Up: Changelog  File: README.info, Node: 07, Next: 063, Prev: 071, Up: Changelog -5.14 0.7 +5.17 0.7 ======== *Added* @@ -1406,7 +1487,7 @@ File: README.info, Node: 07, Next: 063, Prev: 071, Up: Changelog  File: README.info, Node: 063, Next: 062, Prev: 07, Up: Changelog -5.15 0.6.3 +5.18 0.6.3 ========== *Fixed* @@ -1422,7 +1503,7 @@ File: README.info, Node: 063, Next: 062, Prev: 07, Up: Changelog  File: README.info, Node: 062, Next: 061, Prev: 063, Up: Changelog -5.16 0.6.2 +5.19 0.6.2 ========== *Fixed* @@ -1433,7 +1514,7 @@ File: README.info, Node: 062, Next: 061, Prev: 063, Up: Changelog  File: README.info, Node: 061, Next: 06, Prev: 062, Up: Changelog -5.17 0.6.1 +5.20 0.6.1 ========== *Fixed* @@ -1451,7 +1532,7 @@ File: README.info, Node: 061, Next: 06, Prev: 062, Up: Changelog  File: README.info, Node: 06, Next: 052, Prev: 061, Up: Changelog -5.18 0.6 +5.21 0.6 ======== *Added* @@ -1518,7 +1599,7 @@ File: README.info, Node: 06, Next: 052, Prev: 061, Up: Changelog  File: README.info, Node: 052, Next: 051, Prev: 06, Up: Changelog -5.19 0.5.2 +5.22 0.5.2 ========== *Fixed* @@ -1529,7 +1610,7 @@ File: README.info, Node: 052, Next: 051, Prev: 06, Up: Changelog  File: README.info, Node: 051, Next: 05, Prev: 052, Up: Changelog -5.20 0.5.1 +5.23 0.5.1 ========== *Fixed* @@ -1542,7 +1623,7 @@ File: README.info, Node: 051, Next: 05, Prev: 052, Up: Changelog  File: README.info, Node: 05, Next: 049, Prev: 051, Up: Changelog -5.21 0.5 +5.24 0.5 ======== *Added* @@ -1583,7 +1664,7 @@ File: README.info, Node: 05, Next: 049, Prev: 051, Up: Changelog  File: README.info, Node: 049, Next: 048, Prev: 05, Up: Changelog -5.22 0.4.9 +5.25 0.4.9 ========== *Fixed* @@ -1594,7 +1675,7 @@ File: README.info, Node: 049, Next: 048, Prev: 05, Up: Changelog  File: README.info, Node: 048, Next: 047, Prev: 049, Up: Changelog -5.23 0.4.8 +5.26 0.4.8 ========== *Fixed* @@ -1606,7 +1687,7 @@ File: README.info, Node: 048, Next: 047, Prev: 049, Up: Changelog  File: README.info, Node: 047, Next: 046, Prev: 048, Up: Changelog -5.24 0.4.7 +5.27 0.4.7 ========== *Fixed* @@ -1619,7 +1700,7 @@ File: README.info, Node: 047, Next: 046, Prev: 048, Up: Changelog  File: README.info, Node: 046, Next: 045, Prev: 047, Up: Changelog -5.25 0.4.6 +5.28 0.4.6 ========== *Fixed* @@ -1632,7 +1713,7 @@ File: README.info, Node: 046, Next: 045, Prev: 047, Up: Changelog  File: README.info, Node: 045, Next: 044, Prev: 046, Up: Changelog -5.26 0.4.5 +5.29 0.4.5 ========== *Fixed* @@ -1644,7 +1725,7 @@ File: README.info, Node: 045, Next: 044, Prev: 046, Up: Changelog  File: README.info, Node: 044, Next: 043, Prev: 045, Up: Changelog -5.27 0.4.4 +5.30 0.4.4 ========== *Fixed* @@ -1656,7 +1737,7 @@ File: README.info, Node: 044, Next: 043, Prev: 045, Up: Changelog  File: README.info, Node: 043, Next: 042, Prev: 044, Up: Changelog -5.28 0.4.3 +5.31 0.4.3 ========== *Fixed* @@ -1666,7 +1747,7 @@ File: README.info, Node: 043, Next: 042, Prev: 044, Up: Changelog  File: README.info, Node: 042, Next: 041, Prev: 043, Up: Changelog -5.29 0.4.2 +5.32 0.4.2 ========== *Fixed* @@ -1675,7 +1756,7 @@ File: README.info, Node: 042, Next: 041, Prev: 043, Up: Changelog  File: README.info, Node: 041, Next: 04, Prev: 042, Up: Changelog -5.30 0.4.1 +5.33 0.4.1 ========== *Fixed* @@ -1685,7 +1766,7 @@ File: README.info, Node: 041, Next: 04, Prev: 042, Up: Changelog  File: README.info, Node: 04, Next: 032, Prev: 041, Up: Changelog -5.31 0.4 +5.34 0.4 ======== _Note:_ The next release, 0.5, may include changes which will require @@ -1766,7 +1847,7 @@ automatically, as they will be pushed to the ‘master’ branch when ready.  File: README.info, Node: 032, Next: 031, Prev: 04, Up: Changelog -5.32 0.3.2 +5.35 0.3.2 ========== *Fixed* @@ -1779,7 +1860,7 @@ File: README.info, Node: 032, Next: 031, Prev: 04, Up: Changelog  File: README.info, Node: 031, Next: 03, Prev: 032, Up: Changelog -5.33 0.3.1 +5.36 0.3.1 ========== *Fixed* @@ -1789,7 +1870,7 @@ File: README.info, Node: 031, Next: 03, Prev: 032, Up: Changelog  File: README.info, Node: 03, Next: 023, Prev: 031, Up: Changelog -5.34 0.3 +5.37 0.3 ======== *Added* @@ -1857,7 +1938,7 @@ File: README.info, Node: 03, Next: 023, Prev: 031, Up: Changelog  File: README.info, Node: 023, Next: 022, Prev: 03, Up: Changelog -5.35 0.2.3 +5.38 0.2.3 ========== *Fixed* @@ -1867,7 +1948,7 @@ File: README.info, Node: 023, Next: 022, Prev: 03, Up: Changelog  File: README.info, Node: 022, Next: 021, Prev: 023, Up: Changelog -5.36 0.2.2 +5.39 0.2.2 ========== *Fixed* @@ -1878,7 +1959,7 @@ File: README.info, Node: 022, Next: 021, Prev: 023, Up: Changelog  File: README.info, Node: 021, Next: 02, Prev: 022, Up: Changelog -5.37 0.2.1 +5.40 0.2.1 ========== *Fixed* @@ -1888,7 +1969,7 @@ File: README.info, Node: 021, Next: 02, Prev: 022, Up: Changelog  File: README.info, Node: 02, Next: 01, Prev: 021, Up: Changelog -5.38 0.2 +5.41 0.2 ======== *Added* @@ -1971,7 +2052,7 @@ File: README.info, Node: 02, Next: 01, Prev: 021, Up: Changelog  File: README.info, Node: 01, Prev: 02, Up: Changelog -5.39 0.1 +5.42 0.1 ======== First tagged release. @@ -2056,87 +2137,90 @@ GPLv3  Tag Table: Node: Top225 -Node: Contents2065 -Node: Screenshots2192 -Node: Installation2310 -Node: Quelpa2824 -Node: Helm support3352 -Node: Usage3755 -Node: Commands4153 -Node: org-ql-find4618 -Node: org-ql-open-link5526 -Node: org-ql-refile6381 -Node: org-ql-search6709 -Node: helm-org-ql8640 -Node: org-ql-view9018 -Node: org-ql-view-sidebar9548 -Node: org-ql-view-recent-items9928 -Node: org-ql-sparse-tree10424 -Node: Queries11224 -Node: Non-sexp query syntax12341 -Node: General predicates14100 -Node: Ancestor/descendant predicates21025 -Node: Date/time predicates22153 -Node: Functions / Macros25277 -Node: Agenda-like views25575 -Ref: Function org-ql-block25737 -Node: Listing / acting-on results26998 -Ref: Caching27206 -Ref: Function org-ql-select28119 -Ref: Function org-ql-query30545 -Ref: Macro org-ql (deprecated)32319 -Node: Custom predicates32634 -Ref: Macro org-ql-defpred32858 -Node: Dynamic block36299 -Node: Links39023 -Node: Tips39710 -Node: Changelog40034 -Node: 09-pre40973 -Node: helm-org-ql (1)41339 -Node: 08741480 -Node: 08642711 -Node: 08542945 -Node: 08443601 -Node: 08344053 -Node: 08244394 -Node: 08144787 -Node: 0845208 -Node: 07447932 -Node: 07348157 -Node: 07248891 -Node: 07149812 -Node: 0750623 -Node: 06353489 -Node: 06254022 -Node: 06154329 -Node: 0654899 -Node: 05257955 -Node: 05158257 -Node: 0558682 -Node: 04960213 -Node: 04860495 -Node: 04760844 -Node: 04661253 -Node: 04561661 -Node: 04462022 -Node: 04362381 -Node: 04262584 -Node: 04162745 -Node: 0462992 -Node: 03267093 -Node: 03167496 -Node: 0367693 -Node: 02370993 -Node: 02271227 -Node: 02171507 -Node: 0271712 -Node: 0175790 -Node: Development75891 -Node: Copyright assignment76124 -Node: Notes76714 -Node: Comparison with Org Agenda searches76878 -Node: org-sidebar77767 -Node: License78046 +Node: Contents2109 +Node: Screenshots2236 +Node: Installation2354 +Node: Quelpa2868 +Node: Helm support3396 +Node: Usage3799 +Node: Commands4197 +Node: org-ql-find4662 +Node: org-ql-open-link5570 +Node: org-ql-refile6425 +Node: org-ql-search6753 +Node: helm-org-ql8684 +Node: org-ql-view9062 +Node: org-ql-view-sidebar9592 +Node: org-ql-view-recent-items9972 +Node: org-ql-sparse-tree10468 +Node: Queries11268 +Node: Non-sexp query syntax12385 +Node: General predicates14144 +Node: Ancestor/descendant predicates21069 +Node: Date/time predicates22197 +Node: Functions / Macros25321 +Node: Agenda-like views25619 +Ref: Function org-ql-block25781 +Node: Listing / acting-on results27042 +Ref: Caching27250 +Ref: Function org-ql-select28163 +Ref: Function org-ql-query30589 +Ref: Macro org-ql (deprecated)32363 +Node: Custom predicates32678 +Ref: Macro org-ql-defpred32902 +Node: Dynamic block36343 +Node: Links39067 +Node: Tips39754 +Node: Changelog40078 +Node: 09-pre41061 +Node: helm-org-ql (1)41987 +Node: 081042128 +Node: 08942657 +Node: 08843797 +Node: 08744873 +Node: 08646101 +Node: 08546335 +Node: 08446991 +Node: 08347443 +Node: 08247784 +Node: 08148179 +Node: 0848602 +Node: 07451328 +Node: 07351553 +Node: 07252287 +Node: 07153208 +Node: 0754019 +Node: 06356885 +Node: 06257418 +Node: 06157725 +Node: 0658295 +Node: 05261351 +Node: 05161653 +Node: 0562078 +Node: 04963609 +Node: 04863891 +Node: 04764240 +Node: 04664649 +Node: 04565057 +Node: 04465418 +Node: 04365777 +Node: 04265980 +Node: 04166141 +Node: 0466388 +Node: 03270489 +Node: 03170892 +Node: 0371089 +Node: 02374389 +Node: 02274623 +Node: 02174903 +Node: 0275108 +Node: 0179186 +Node: Development79287 +Node: Copyright assignment79520 +Node: Notes80110 +Node: Comparison with Org Agenda searches80274 +Node: org-sidebar81163 +Node: License81442  End Tag Table diff --git a/tests/test-org-ql.el b/tests/test-org-ql.el index 7618327..923ec66 100644 --- a/tests/test-org-ql.el +++ b/tests/test-org-ql.el @@ -638,6 +638,11 @@ with keyword arg NOW in PLIST." :to-equal (list :query t :preamble (rx bol (repeat 2 4 "*") " ") :preamble-case-fold t))) + (it "with an expression in level number's place" + (expect (org-ql--query-preamble '(level <= (string-to-number (property "PROPERTY")))) + :to-equal (list :query '(level <= (string-to-number (property "PROPERTY"))) + :preamble nil + :preamble-case-fold t))) (it "<" (expect (org-ql--query-preamble '(level < 3)) :to-equal (list :query t @@ -1339,7 +1344,15 @@ with keyword arg NOW in PLIST." (org-ql-it "with a property and a value" (org-ql-expect ('(property "agenda-group" "plans")) - '("Take over the universe" "Write a symphony")))) + '("Take over the universe" "Write a symphony"))) + + (org-ql-it "with a property and \"nil :inherit t\"" + (org-ql-expect ('(property "agenda-group" nil :inherit t)) + '("Take over the universe" "Take over the world" "Skype with president of Antarctica" "Take over Mars" "Visit Mars" "Take over the moon" "Visit the moon" "Practice leaping tall buildings in a single bound" "Renew membership in supervillain club" "Learn universal sign language" "Spaceship lease" "Recurring" "/r/emacs" "Shop for groceries" "Sunrise/sunset" "Write a symphony"))) + + (org-ql-it "with a property and \":inherit t\"" + (org-ql-expect ('(property "agenda-group" :inherit t)) + '("Take over the universe" "Take over the world" "Skype with president of Antarctica" "Take over Mars" "Visit Mars" "Take over the moon" "Visit the moon" "Practice leaping tall buildings in a single bound" "Renew membership in supervillain club" "Learn universal sign language" "Spaceship lease" "Recurring" "/r/emacs" "Shop for groceries" "Sunrise/sunset" "Write a symphony")))) (describe "(regexp)" @@ -1973,13 +1986,13 @@ with keyword arg NOW in PLIST." (expression-link "[[org-ql-search:todo:?title%3D%28error%20%22UNSAFE%22%29]]")) (it "Errors for a quoted lambda" (expect (open-link quoted-lambda-link) - :to-throw 'wrong-type-argument '(characterp lambda))) + :to-throw 'error '("CAUTION: Link not opened because unsafe title parameter detected: (lambda (_ _) (error \"UNSAFE\"))"))) (it "Errors for an unquoted lambda" (expect (open-link unquoted-lambda-link) - :to-throw 'wrong-type-argument '(characterp lambda))) + :to-throw 'error '("CAUTION: Link not opened because unsafe title parameter detected: (lambda (_ _) (error \"UNSAFE\"))"))) (it "Errors for an expression" (expect (open-link expression-link) - :to-throw 'wrong-type-argument '(characterp error)))) + :to-throw 'error '("CAUTION: Link not opened because unsafe title parameter detected: (error \"UNSAFE\")")))) (describe "sort parameter" :var ((quoted-lambda-link "[[org-ql-search:todo:?sort%3D%28lambda%20%28_%20_%29%20%28error%20%22UNSAFE%22%29%29]]") @@ -2005,7 +2018,7 @@ with keyword arg NOW in PLIST." (describe "View saving/loading" :var* ((temp-dir (make-temp-file "test-org-ql-" 'dir)) (temp-filenames (cl-loop for file in '("test1.org" "test2.org") - collect (expand-file-name file temp-dir))) + collect (abbreviate-file-name (expand-file-name file temp-dir)))) (file-contents (with-temp-buffer (insert "#+TITLE: Test data\n\n" "* TODO Heading 1\n" @@ -2111,31 +2124,21 @@ with keyword arg NOW in PLIST." (describe "Buffers/Files" :var ((query '(and (todo "TODO") (regexp "heading"))) (one-filename (car temp-filenames))) - ;; NOTE: Inexplicably, on GitHub CI, the filenames are being - ;; abbreviated (i.e. "/home/FOO" is replaced with "~/FOO"); - ;; I can only guess it's something to do with the way the - ;; Emacs instance is built in the Nix images we use there. - ;; So we have to compare the filenames in abbreviated form. - (cl-labels ((filenames-equal-p (a b) - (seq-set-equal-p (mapcar #'abbreviate-file-name a) - (mapcar #'abbreviate-file-name b)))) - (it "One filename matches" - (should (equal (abbreviate-file-name - (var-after-bookmark-set-and-jump 'org-ql-view-buffers-files one-filename query)) - (abbreviate-file-name one-filename)))) - (it "A list of filenames matches" - (should (filenames-equal-p (var-after-bookmark-set-and-jump 'org-ql-view-buffers-files temp-filenames query) - temp-filenames))) - ;; NOTE: These actually bookmark the filenames backing the buffers. - (it "One buffer matches" - (should (equal (abbreviate-file-name - (var-after-bookmark-set-and-jump 'org-ql-view-buffers-files - (find-file-noselect (car temp-filenames)) query)) - (abbreviate-file-name one-filename)))) - (it "A list of buffers matches" - (should (filenames-equal-p (var-after-bookmark-set-and-jump 'org-ql-view-buffers-files - (mapcar #'find-file-noselect temp-filenames) query) - temp-filenames))))))) + (it "One filename matches" + (expect (var-after-bookmark-set-and-jump 'org-ql-view-buffers-files one-filename query) + :to-equal one-filename)) + (it "A list of filenames matches" + (expect (var-after-bookmark-set-and-jump 'org-ql-view-buffers-files temp-filenames query) + :to-equal temp-filenames)) + ;; NOTE: These actually bookmark the filenames backing the buffers. + (it "One buffer matches" + (expect (var-after-bookmark-set-and-jump 'org-ql-view-buffers-files + (find-file-noselect (car temp-filenames)) query) + :to-equal one-filename)) + (it "A list of buffers matches" + (expect (var-after-bookmark-set-and-jump 'org-ql-view-buffers-files + (mapcar #'find-file-noselect temp-filenames) query) + :to-equal temp-filenames))))) (describe "Dynamic blocks" (describe "warn about sexp queries"