Merge remote-tracking branch 'gh/master' into HEAD
This commit is contained in:
commit
8b3bb74c94
13 changed files with 1084 additions and 492 deletions
59
README.org
59
README.org
|
|
@ -1,7 +1,6 @@
|
|||
#+TITLE: org-ql
|
||||
|
||||
# NOTE: Using =BEGIN_HTML= for this causes TeX/info export to fail, but this HTML block works.
|
||||
# #+HTML: <a href=https://alphapapa.github.io/dont-tread-on-emacs/><img src="images/dont-tread-on-emacs-150.png" align="right"></a>
|
||||
#+HTML: <img src="images/dog.png" align="right">
|
||||
|
||||
# NOTE: To avoid having this in the info manual, we use HTML rather than Org syntax; it still appears with the GitHub renderer.
|
||||
|
|
@ -112,11 +111,20 @@ Lisp code examples are in [[examples.org]].
|
|||
These commands jump to a heading selected using Emacs's built-in completion facilities with an Org QL query:
|
||||
|
||||
- ~org-ql-find~ searches in the current buffer.
|
||||
- ~org-ql-find-path~ searches outline paths in the current buffer.
|
||||
- ~org-ql-find-in-agenda~ searches in ~(org-agenda-files)~.
|
||||
- ~org-ql-find-in-org-directory~ searches in ~org-directory~.
|
||||
|
||||
Note that these commands are compatible with [[https://github.com/oantolin/embark][Embark]]: the ~embark-act~ command can be called on a completion candidate (i.e. a search result) to act on it immediately, without having to visit the entry in its source Org buffer.
|
||||
|
||||
[[images/org-ql-find.png]]
|
||||
|
||||
*** org-ql-open-link
|
||||
|
||||
This command finds links in entries matching the input query and offers them for selection; the selected link is then opened with ~org-open-at-point~.
|
||||
|
||||
The input is matched using the default predicate, which means it searches both entry content and outline paths. This is helpful when a collection of links are kept in Org files: rather than having to first visit the entry containing the desired link, then locate it within the entry, and then open it, the user can simply select the link and open it directly. For example, if an entry with the heading =Emacs= contained a link named =mailing list=, one could search for =Emacs list= and open the link to the mailing list directly.
|
||||
|
||||
*** org-ql-refile
|
||||
|
||||
This command refiles the current Org entry to one selected by searching with Org QL completion. It searches files listed in ~org-refile-targets~ as well as the current buffer.
|
||||
|
|
@ -147,6 +155,8 @@ Read ~QUERY~ and search with ~org-ql~. Interactively, prompt for these variable
|
|||
|
||||
*Note:* The view buffer is currently put in ~org-agenda-mode~, which means that /some/ Org Agenda commands work, such as jumping to entries and changing item priorities (without necessarily updating the view). This feature is experimental and not guaranteed to work correctly with all commands. (It works to the extent it does because the appropriate text properties are placed on each item, imitating an Agenda buffer.)
|
||||
|
||||
*Note:* Also, this buffer is compatible with [[https://github.com/oantolin/embark][Embark]]: the ~embark-act~ command can be called on an entry to act on it immediately, without having to visit the entry in its source Org buffer.
|
||||
|
||||
*** helm-org-ql
|
||||
|
||||
/Note: This command uses [[#non-sexp-query-syntax][non-sexp queries]]. It is available separately in the package =helm-org-ql=./
|
||||
|
|
@ -221,6 +231,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).
|
||||
+ =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=.
|
||||
|
|
@ -542,7 +553,43 @@ 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
|
||||
** 0.8-pre
|
||||
|
||||
*Additions*
|
||||
|
||||
+ Function ~org-ql-completing-read~, used by command ~org-ql-find~, now specifies the completion category as ~org-heading~, providing compatibility with [[https://github.com/oantolin/embark][Embark]]. (This is a powerful feature, as it means any ~org-ql-find~ result can be acted on from inside the search results with Embark, which provides common actions from Org Agenda and Org speed keys bindings.) ([[https://github.com/alphapapa/org-ql/issues/299][#299]]. Thanks to [[https://github.com/oantolin][Omar Antolín Camarena]], [[https://github.com/minad][Daniel Mendler]], and [[https://github.com/akirak][Akira Komamura]].)
|
||||
+ Command ~org-ql-find~ may be called in an ~org-agenda~ or ~org-ql-view~ buffer to search the buffers which contributed to the agenda/view buffer.
|
||||
+ Command ~org-ql-find-path~, which searches outline paths in the current buffer.
|
||||
+ Command ~org-ql-open-link~, which finds links in entries matching the given query, and opens the selected one with ~org-open-at-point~. (This is helpful when a collection of links are kept in Org files: rather than having to first visit the entry containing the desired link, then locate it within the entry, and then open it, the user can simply select the link and open it directly.)
|
||||
|
||||
*Compatibility*
|
||||
|
||||
+ Org v9.7's ~org-element~ API changes required some adjustments. ([[https://github.com/alphapapa/org-ql/issues/364][#364]]. Thanks to several users for reporting, and to [[https://github.com/yantar92][Ihor Radchenko]] for his feedback.)
|
||||
|
||||
** 0.7.3
|
||||
|
||||
*Fixes*
|
||||
+ Disable ~case-fold-search~ when collecting headings in outline paths. (Headings that started with a word that is also a to-do keyword but with different capitalization would be matched incorrectly.)
|
||||
+ Saving of ~org-ql-view~ views. ([[https://github.com/alphapapa/org-ql/issues/378][#378]]. Thanks to [[https://github.com/Pentaquark1][Pentaquark1]] for reporting.)
|
||||
+ Command ~org-ql-find~ didn't move point to the selected entry. ([[https://github.com/alphapapa/org-ql/issues/380][#380]]. Thanks to [[https://github.com/oantolin][Omar Antolín Camarena]] for reporting.)
|
||||
|
||||
** 0.7.2
|
||||
|
||||
*Fixes*
|
||||
+ Timestamp predicates are more tolerant of partial input (e.g. preventing errors while the user is typing a query into ~org-ql-find~).
|
||||
+ Query parser ignores leading whitespace (e.g. preventing errors while the user is typing a query into ~org-ql-find~).
|
||||
+ Use of ~org-ql-find~ with ~:query-prefix~ argument prevented selection of results. ([[https://github.com/alphapapa/org-ql/issues/351][#351]]. Thanks to [[https://github.com/danielfleischer][Daniel Fleischer]] for reporting.)
|
||||
+ Handle narrowed buffers correctly in ~org-ql-find~.
|
||||
+ Warn about empty headings in ~org-ql-completing-read~ (the Org format allows a heading line to have no text, but it's useless for this purpose, and usually indicates unnoticed corruption).
|
||||
|
||||
** 0.7.1
|
||||
|
||||
*Fixes*
|
||||
+ Function ~org-ql-completing-read~ is more compatible with default Emacs completion. (See [[https://github.com/alphapapa/org-ql/issues/338][#338]]. Thanks to [[https://github.com/arozbiz][arozbiz]] for reporting.)
|
||||
+ Function ~org-ql-completing-read~ would sometimes stop updating with changes in input. (See [[https://github.com/alphapapa/org-ql/issues/350][#350]]. Thanks to [[https://github.com/anpandey][Ankit Raj Pandey]] for reporting and fixing, and to [[https://github.com/minad][Daniel Mendler]] for advising.)
|
||||
+ In ~org-ql-completing-read~, format links for display, and use ~org-entry-get~ internally rather than ~org-get-heading~.
|
||||
|
||||
** 0.7
|
||||
|
||||
*Added*
|
||||
+ Commands ~org-ql-find~, ~org-ql-find-heading~, and ~org-ql-find-path~, which jump to entries selected using Emacs's built-in completion facilities and Org QL queries (like ~helm-org-ql~, but doesn't require Helm.).
|
||||
|
|
@ -551,17 +598,23 @@ Simple links may also be written manually in either sexp or non-sexp form, like:
|
|||
+ Option ~org-ql-default-predicate~, applied to plain-string query tokens (before, the ~regexp~ predicate was always used, but now it may be customized).
|
||||
+ Alias ~c~ for predicate ~category~.
|
||||
+ Predicate ~property~ now accepts the argument ~:inherit~ to match entries with property inheritance, and when unspecified, the option ~org-use-property-inheritance~ controls whether inheritance is used.
|
||||
+ Predicate ~blocked~. (Thanks to [[https://github.com/akirak][Akira Komamura]].)
|
||||
|
||||
*Changed*
|
||||
+ Give more useful error message for invalid queries.
|
||||
+ Predicate ~src~ now matches case-insensitively.
|
||||
+ Command ~org-ql-sparse-tree~ accepts both string and sexp queries. (Thanks to [[https://github.com/akirak][Akira Komamura]].)
|
||||
|
||||
*Fixed*
|
||||
+ Predicate ~src~'s matching of begin/end block lines, normalization of arguments, and handling in non-sexp queries.
|
||||
+ Predicate ~link~ matches links whose descriptions contain escaped brackets (changed in Org 9.3). (Thanks to [[https://github.com/exot][Daniel Borchmann]] for reporting.)
|
||||
+ Predicate ~src~'s matching of begin/end block lines, normalization of arguments, and handling in non-sexp queries. (Thanks to [[https://github.com/akirak][Akira Komamura]] for reporting.)
|
||||
+ Predicate ~src~'s behavior with various arguments.
|
||||
+ Various compilation warnings.
|
||||
|
||||
*Internal*
|
||||
+ Certain query predicates, when called multiple times in an ~and~ sub-expression, are optimized to a single call.
|
||||
+ Use ~buffer-chars-modified-tick~ instead of ~buffer-modified-tick~. (Thanks to [[https://github.com/yantar92][Ihor Radchenko]].)
|
||||
+ Implemented tests for ~src~ predicate.
|
||||
|
||||
*Credits*
|
||||
+ Thanks to [[https://github.com/chasecaleb][Caleb Chase]] for help with [[https://github.com/alphapapa/org-ql/pull/285][#285]], fixed in [[https://github.com/alphapapa/org-ql/commit/91908186fcca4b5fd2e9d26da5bc0375c2b41acf][9190818]].
|
||||
|
|
|
|||
|
|
@ -98,6 +98,8 @@ Based on `helm-map'.")
|
|||
Interactively, search the current buffer. Note that this command
|
||||
only accepts non-sexp, \"plain\" queries.
|
||||
|
||||
NAME is passed to `helm-org-ql-source', which see.
|
||||
|
||||
NOTE: Atoms in the query are turned into strings where
|
||||
appropriate, which makes it unnecessary to type quotation marks
|
||||
around words that are intended to be searched for as indepenent
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 5.5 KiB |
|
|
@ -73,14 +73,59 @@ For an experience like `org-rifle', use a newline."
|
|||
(defface org-ql-completing-read-snippet '((t (:inherit font-lock-comment-face)))
|
||||
"Snippets.")
|
||||
|
||||
(defvar org-ql-completing-read-input-regexp nil
|
||||
"Current regexp for `org-ql-completing-read' input.
|
||||
To be used in, e.g. annotation functions.")
|
||||
|
||||
;;;; Functions
|
||||
|
||||
(defun org-ql-completing-read-action ()
|
||||
"Default action for `org-ql-completing-read'.
|
||||
Returns (STRING . MARKER) cons for entry at point."
|
||||
(font-lock-ensure (point-at-bol) (point-at-eol))
|
||||
(cons (org-link-display-format (org-entry-get nil "ITEM")) (point-marker)))
|
||||
|
||||
(defun org-ql-completing-read-snippet (marker)
|
||||
"Return snippet for entry at MARKER.
|
||||
Returns value returned by function
|
||||
`org-ql-completing-read-snippet-function' or
|
||||
`org-ql-completing-read--snippet-simple', whichever returns a
|
||||
value, or nil."
|
||||
(pcase (while-no-input
|
||||
;; 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.
|
||||
(org-with-point-at marker
|
||||
(or (funcall org-ql-completing-read-snippet-function)
|
||||
(org-ql-completing-read--snippet-simple))))
|
||||
(`t ;; Interrupted: return nil (which can be concatted).
|
||||
nil)
|
||||
(else else)))
|
||||
|
||||
(defun org-ql-completing-read-path (marker)
|
||||
"Return formatted outline path for entry at MARKER."
|
||||
(org-with-point-at marker
|
||||
(let ((path (thread-first (org-get-outline-path nil t)
|
||||
(org-format-outline-path (window-width) nil "")
|
||||
(org-split-string ""))))
|
||||
(if org-ql-completing-read-reverse-paths
|
||||
(concat "\\" (string-join (reverse path) "\\"))
|
||||
(concat "/" (string-join path "/"))))))
|
||||
|
||||
;;;;; Completing read
|
||||
|
||||
;;;###autoload
|
||||
(cl-defun org-ql-completing-read (buffers-files &key query-prefix query-filter
|
||||
(cl-defun org-ql-completing-read
|
||||
(buffers-files &key query-prefix query-filter
|
||||
(action #'org-ql-completing-read-action)
|
||||
;; FIXME: Unused argument.
|
||||
(annotate #'org-ql-completing-read-snippet)
|
||||
(snippet #'org-ql-completing-read-snippet)
|
||||
(path #'org-ql-completing-read-path)
|
||||
(action-filter #'list)
|
||||
(prompt "Find entry: "))
|
||||
"Return marker at Org entry in BUFFERS-FILES selected with `org-ql'.
|
||||
"Return marker at entry in BUFFERS-FILES selected with `org-ql'.
|
||||
PROMPT is shown to the user.
|
||||
|
||||
QUERY-PREFIX may be a string to prepend to the query entered by
|
||||
the user (e.g. use \"heading:\" to only search headings, easily
|
||||
|
|
@ -93,105 +138,206 @@ with commas to turn multiple tokens, which would normally be
|
|||
treated as multiple predicates, into multiple arguments to a
|
||||
single predicate)."
|
||||
(declare (indent defun))
|
||||
;; Emacs's completion API is not always easy to understand,
|
||||
;; especially when using "programmed completion." This code was
|
||||
;; made possible by the example Clemens Radermacher shared at
|
||||
;; Emacs's completion API is not always easy to understand, especially when using "programmed
|
||||
;; completion." This code was made possible by the example Clemens Radermacher shared at
|
||||
;; <https://github.com/radian-software/selectrum/issues/114#issuecomment-744041532>.
|
||||
|
||||
;; NOTE: I don't usually leave commented-out debugging code, but due to the incredibly tedious
|
||||
;; complexity of the "Programmed Completion" API and the time spent trying to get this reasonably
|
||||
;; close to "correct," I'm leaving it in, because I will undoubtedly have to go through this
|
||||
;; process again.
|
||||
|
||||
;; (message "ORG-QL-COMPLETING-READ: Starts.")
|
||||
(let ((table (make-hash-table :test #'equal))
|
||||
(disambiguations (make-hash-table :test #'equal))
|
||||
(window-width (window-width))
|
||||
query-tokens snippet-regexp)
|
||||
(cl-labels ((action
|
||||
() (font-lock-ensure (point-at-bol) (point-at-eol))
|
||||
(let* ((path (thread-first (org-get-outline-path t t)
|
||||
last-input org-outline-path-cache query-tokens)
|
||||
(cl-labels (;; (debug-message
|
||||
;; (f &rest args) (apply #'message (concat "ORG-QL-COMPLETING-READ: " f) args))
|
||||
(action ()
|
||||
(font-lock-ensure (point-at-bol) (point-at-eol))
|
||||
;; This function needs to handle multiple candidates per
|
||||
;; call, so we loop over a list of values by default.
|
||||
(pcase-dolist (`(,string . ,marker) (funcall action-filter (funcall action)))
|
||||
(when string
|
||||
(if (string-empty-p string)
|
||||
;; A heading's string can be empty, but we can't use one because it
|
||||
;; wouldn't be useful to the user; and if one is found, it's very
|
||||
;; likely to indicate an unnoticed mistake or corruption in the
|
||||
;; file: so display a warning and don't record it as a candidate.
|
||||
(display-warning 'org-ql-completing-read (format-message "Empty heading at %S" marker))
|
||||
(when (gethash string table)
|
||||
;; Disambiguate string (even adding the path isn't enough, because that could
|
||||
;; also be duplicated).
|
||||
(if-let ((suffix (gethash string disambiguations)))
|
||||
(setf string (format "%s <%s>" string (cl-incf suffix)))
|
||||
(setf string (format "%s <%s>" string (puthash string 2 disambiguations)))))
|
||||
(puthash (propertize string 'org-marker marker) marker table)))))
|
||||
|
||||
(path (marker)
|
||||
(org-with-point-at marker
|
||||
(let* ((path (thread-first (org-get-outline-path nil t)
|
||||
(org-format-outline-path window-width nil "")
|
||||
(org-split-string "")))
|
||||
(path (if org-ql-completing-read-reverse-paths
|
||||
(string-join (nreverse path) "\\")
|
||||
(string-join path "/"))))
|
||||
(puthash path (point-marker) table)
|
||||
path))
|
||||
(formatted-path (if org-ql-completing-read-reverse-paths
|
||||
(concat "\\" (string-join (reverse path) "\\"))
|
||||
(concat "/" (string-join path "/")))))
|
||||
formatted-path)))
|
||||
(todo
|
||||
(marker) (if-let (it (org-entry-get marker "TODO"))
|
||||
(concat (propertize it 'face (org-get-todo-face it)) " ")
|
||||
""))
|
||||
(affix (completions)
|
||||
;; (debug-message "AFFIX:%S" completions)
|
||||
(cl-loop for completion in completions
|
||||
for marker = (gethash completion table)
|
||||
for todo-state = (if-let (it (org-entry-get marker "TODO"))
|
||||
(concat (propertize it
|
||||
'face (org-get-todo-face it))
|
||||
" ")
|
||||
"")
|
||||
for snippet = (if-let (it (snippet marker))
|
||||
(propertize (concat " " it)
|
||||
'face 'org-ql-completing-read-snippet)
|
||||
"")
|
||||
collect (list completion todo-state snippet)))
|
||||
for marker = (get-text-property 0 'org-marker completion)
|
||||
for prefix = (todo marker)
|
||||
for suffix = (concat (funcall path marker) " " (funcall snippet marker))
|
||||
collect (list completion prefix suffix)))
|
||||
(annotate (candidate)
|
||||
;; (debug-message "ANNOTATE:%S" candidate)
|
||||
(while-no-input
|
||||
;; 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 (gethash candidate table)) "")))
|
||||
(snippet (marker)
|
||||
;; 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 snippet-regexp)
|
||||
(org-ql-completing-read--snippet-simple))))
|
||||
(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)))
|
||||
(group (candidate transform)
|
||||
(pcase transform
|
||||
(`nil (buffer-name (marker-buffer (gethash candidate table))))
|
||||
(`nil (buffer-name (marker-buffer (get-text-property 0 'org-marker candidate))))
|
||||
(_ candidate)))
|
||||
(try (string _table _pred point &optional _metadata)
|
||||
(try (string _collection _pred point &optional _metadata)
|
||||
;; (debug-message "TRY: STRING:%S" string)
|
||||
(cons string point))
|
||||
(all (string table pred _point)
|
||||
;; (debug-message "all: STRING:%S" string)
|
||||
;; (debug-message "all-completions RETURNS: %S" (all-completions string table pred))
|
||||
(all-completions string table pred))
|
||||
(collection (str _pred flag)
|
||||
(when query-prefix
|
||||
(setf str (concat query-prefix str)))
|
||||
(collection (input _pred flag)
|
||||
(pcase flag
|
||||
('metadata (list 'metadata
|
||||
(cons 'category 'org-heading)
|
||||
(cons 'group-function #'group)
|
||||
(cons 'affixation-function #'affix)
|
||||
(cons 'annotation-function #'annotate)))
|
||||
(`t (unless (string-empty-p str)
|
||||
(cons 'annotation-function #'annotate)
|
||||
(cons 'display-sort-function
|
||||
(lambda (strings)
|
||||
(let ((quoted-tokens (mapcar #'regexp-quote query-tokens)))
|
||||
(sort strings
|
||||
(lambda (a b)
|
||||
(cl-labels ((matches
|
||||
(s) (cl-loop for token in quoted-tokens
|
||||
count (string-match-p token s))))
|
||||
(> (matches a) (matches b))))))))))
|
||||
(`t
|
||||
;; (debug-message "COLLECTION:t INPUT:%S KEYS:%S"
|
||||
;; input (hash-table-keys table))
|
||||
;; It's not ideal to call `run-query' unconditionally here, but due to
|
||||
;; the complexity of the "Programmed Completion" API, it's basically
|
||||
;; necessary, and org-ql's caching should make it nearly free.
|
||||
(run-query input)
|
||||
(hash-table-keys table))
|
||||
('lambda
|
||||
;; (debug-message "COLLECTION:lambda INPUT:%S KEYS:%S"
|
||||
;; input (hash-table-keys table))
|
||||
(if (not (hash-table-empty-p table))
|
||||
(when (gethash input table)
|
||||
t)
|
||||
(run-query input)
|
||||
(when (gethash input table)
|
||||
;; (debug-message "COLLECTION:lambda INPUT:%S FOUND" input)
|
||||
t)))
|
||||
(`nil
|
||||
;; (debug-message "COLLECTION:nil INPUT:%S" input)
|
||||
(if (not (hash-table-empty-p table))
|
||||
(when (gethash input table)
|
||||
t)
|
||||
(run-query input)
|
||||
;; (debug-message "COLLECTION:nil INPUT:%S KEYS:%S"
|
||||
;; input (hash-table-keys table))
|
||||
(cond ((hash-table-empty-p table)
|
||||
nil)
|
||||
((gethash input table)
|
||||
t)
|
||||
(t
|
||||
;; FIXME: "it should return the longest common prefix
|
||||
;; substring of all matches otherwise"...but there's no
|
||||
;; function to compute that? At least returning an empty
|
||||
;; string doesn't seem to break anything.
|
||||
input))))
|
||||
(`(boundaries . ,suffix)
|
||||
;; (debug-message "COLLECTION:boundaries INPUT:%S SUFFIX:%S KEYS:%S"
|
||||
;; input suffix (hash-table-keys table))
|
||||
;; FIXME: This is unlikely to be correct, but I'm not even sure if it
|
||||
;; can be correct in this case since the input (e.g. "todo: foo")
|
||||
;; usually won't match a completion candidate directly.
|
||||
`(boundaries 0 . ,(length suffix)))))
|
||||
(run-query (input)
|
||||
;; (debug-message "RUN-QUERY:%S" input)
|
||||
(when query-prefix
|
||||
(setf input (concat query-prefix input)))
|
||||
(unless (or (string-empty-p input)
|
||||
(equal last-input input))
|
||||
;; (debug-message "RUN-QUERY:%S RUNNING" input)
|
||||
(setf last-input input)
|
||||
;; Clear hash table each time the user changes the input.
|
||||
(clrhash table)
|
||||
(clrhash disambiguations)
|
||||
(when query-filter
|
||||
(setf str (funcall query-filter str)))
|
||||
(pcase org-ql-completing-read-snippet-function
|
||||
('org-ql-completing-read--snippet-regexp
|
||||
(setf input (funcall query-filter input)))
|
||||
(setf query-tokens
|
||||
;; Remove any tokens that specify predicates or are too short.
|
||||
(--select (not (or (string-match-p (rx bos (1+ (not (any ":"))) ":") it)
|
||||
(< (length it) org-ql-completing-read-snippet-minimum-token-length)))
|
||||
(split-string str nil t (rx space)))
|
||||
snippet-regexp
|
||||
(split-string input nil t (rx blank)))
|
||||
org-ql-completing-read-input-regexp
|
||||
(when query-tokens
|
||||
;; Limiting each context word to 15 characters
|
||||
;; prevents excessively long, non-word strings
|
||||
;; from ending up in snippets, which can
|
||||
;; adversely affect performance.
|
||||
;; Limiting each context word to 15 characters prevents
|
||||
;; excessively long, non-word strings from ending up in
|
||||
;; snippets, which can adversely affect performance.
|
||||
(rx-to-string `(seq (optional (repeat 1 3 (repeat 1 15 (not space)) (0+ space)))
|
||||
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 str)
|
||||
:action #'action))))))
|
||||
;; NOTE: It seems that the `completing-read' machinery can call,
|
||||
;; abort, and re-call the collection function while the user is
|
||||
;; typing, which can interrupt the machinery Org uses to prepare
|
||||
;; an Org buffer when an Org file is loaded. This results in,
|
||||
;; e.g. the buffer being left in fundamental-mode, unprepared to
|
||||
;; be used as an Org buffer, which breaks many things and is
|
||||
;; very confusing for the user. Ideally, of course, we would
|
||||
;; solve this in `org-ql-select', and we already attempt to, but
|
||||
;; that function is called by the `completing-read' machinery,
|
||||
;; which interrupts it, so we must work around this problem by
|
||||
;; ensuring all of the BUFFERS-FILES are loaded and initialized
|
||||
;; before calling `completing-read'.
|
||||
(optional (repeat 1 3 (0+ space) (repeat 1 15 (not space))))))))
|
||||
(org-ql-select buffers-files (org-ql--query-string-to-sexp input)
|
||||
:action #'action))))
|
||||
(unless (listp buffers-files)
|
||||
;; Since we map across this argument, we ensure it's a list.
|
||||
(setf buffers-files (list buffers-files)))
|
||||
;; NOTE: It seems that the `completing-read' machinery can call, abort, and re-call the
|
||||
;; collection function while the user is typing, which can interrupt the machinery Org uses to
|
||||
;; prepare an Org buffer when an Org file is loaded. This results in, e.g. the buffer being
|
||||
;; left in fundamental-mode, unprepared to be used as an Org buffer, which breaks many things
|
||||
;; and is very confusing for the user. Ideally, of course, we would solve this in
|
||||
;; `org-ql-select', and we already attempt to, but that function is called by the
|
||||
;; `completing-read' machinery, which interrupts it, so we must work around this problem by
|
||||
;; ensuring all of the BUFFERS-FILES are loaded and initialized before calling
|
||||
;; `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")))
|
||||
(selected (completing-read prompt #'collection nil)))
|
||||
(gethash selected table)))))
|
||||
(selected (completing-read prompt #'collection nil t)))
|
||||
;; (debug-message "SELECTED:%S KEYS:%S" selected (hash-table-keys table))
|
||||
(or (gethash selected table)
|
||||
;; If there are completions in the table, but none of them exactly match the user input
|
||||
;; (e.g. a heading "foo" that matches a query "todo:"), `completing-read' will not
|
||||
;; select it automatically, so we return it ourselves. But note that this is not
|
||||
;; necessarily correct. For example, if the user types "todo:" and gets a list of
|
||||
;; completions ("foo" "bar"), and then changes the input to "ba" and presses RET
|
||||
;; immediately (without getting a new list of completions), the table will include "foo"
|
||||
;; and "bar", and we will return "foo"'s value rather than the first match for the query
|
||||
;; "ba", because `completing-read' will not cause the COLLECTION function to run a new
|
||||
;; query for the new input.
|
||||
(car (hash-table-values table))
|
||||
(user-error "No results for input"))))))
|
||||
|
||||
(defun org-ql-completing-read--snippet-simple (&optional _regexp)
|
||||
(defun org-ql-completing-read--snippet-simple ()
|
||||
"Return a snippet of the current entry.
|
||||
Returns up to `org-ql-completing-read-snippet-length' characters."
|
||||
(save-excursion
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
(defcustom org-ql-find-goto-hook '(org-show-entry org-reveal)
|
||||
"Functions called when selecting an entry."
|
||||
;; TODO: Add common choices, including `org-tree-to-indirect-buffer'.
|
||||
:type 'hook)
|
||||
|
||||
(defcustom org-ql-find-display-buffer-action '(display-buffer-same-window)
|
||||
|
|
@ -54,8 +55,11 @@ See function `display-buffer'."
|
|||
(cl-defun org-ql-find (buffers-files &key query-prefix query-filter
|
||||
(prompt "Find entry: "))
|
||||
"Go to an Org entry in BUFFERS-FILES selected by searching entries with `org-ql'.
|
||||
Interactively, with universal prefix, select multiple buffers to
|
||||
search with completion.
|
||||
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.
|
||||
|
||||
QUERY-PREFIX may be a string to prepend to the query (e.g. use
|
||||
\"heading:\" to only search headings, easily creating a custom
|
||||
|
|
@ -75,19 +79,19 @@ single predicate)."
|
|||
when (eq 'org-mode (buffer-local-value 'major-mode buffer))
|
||||
collect (buffer-name buffer))
|
||||
nil t))
|
||||
(progn
|
||||
(unless (eq major-mode 'org-mode)
|
||||
(user-error "This is not an Org buffer: %S" (current-buffer)))
|
||||
(current-buffer)))))
|
||||
(cond ((derived-mode-p 'org-agenda-mode) (or org-ql-view-buffers-files
|
||||
org-agenda-contributing-files))
|
||||
((derived-mode-p 'org-mode) (current-buffer))
|
||||
(t (user-error "This is not an Org-related buffer: %S" (current-buffer)))))))
|
||||
(let ((marker (org-ql-completing-read buffers-files
|
||||
:query-prefix query-prefix
|
||||
:query-filter query-filter
|
||||
:prompt prompt)))
|
||||
(with-current-buffer (marker-buffer marker)
|
||||
(set-buffer (marker-buffer marker))
|
||||
(goto-char marker)
|
||||
(display-buffer (current-buffer) org-ql-find-display-buffer-action)
|
||||
(select-window (get-buffer-window (current-buffer)))
|
||||
(run-hook-with-args 'org-ql-find-goto-hook))))
|
||||
(run-hook-with-args 'org-ql-find-goto-hook)))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-ql-refile (marker)
|
||||
|
|
@ -130,6 +134,64 @@ which see (but only the files are used)."
|
|||
(interactive)
|
||||
(org-ql-find (org-ql-search-directories-files)))
|
||||
|
||||
;;;###autoload
|
||||
(defun org-ql-find-path ()
|
||||
"Call `org-ql-find' to search outline paths in the current buffer."
|
||||
(interactive)
|
||||
(let ((org-ql-default-predicate 'outline-path))
|
||||
(org-ql-find (current-buffer))))
|
||||
|
||||
;;;###autoload
|
||||
(cl-defun org-ql-open-link (buffers-files &key query-prefix query-filter
|
||||
(prompt "Open link: "))
|
||||
"Open a link selected with `org-ql-completing-read'.
|
||||
Links found in entries matching the input query are offered as
|
||||
candidates, and the selected one is opened with
|
||||
`org-open-at-point'. Arguments BUFFERS-FILES, QUERY-FILTER,
|
||||
QUERY-PREFIX, and PROMPT are passed to `org-ql-completing-read',
|
||||
which see."
|
||||
(interactive
|
||||
;; FIXME: Factor this out.
|
||||
(list (if current-prefix-arg
|
||||
(mapcar #'get-buffer
|
||||
(completing-read-multiple
|
||||
"Buffers: "
|
||||
(cl-loop for buffer in (buffer-list)
|
||||
when (eq 'org-mode (buffer-local-value 'major-mode buffer))
|
||||
collect (buffer-name buffer))
|
||||
nil t))
|
||||
(progn
|
||||
(unless (eq major-mode 'org-mode)
|
||||
(user-error "This is not an Org buffer: %S" (current-buffer)))
|
||||
(current-buffer)))))
|
||||
(let* ((marker (org-ql-completing-read buffers-files
|
||||
:query-prefix query-prefix
|
||||
:query-filter query-filter
|
||||
:prompt prompt
|
||||
:action-filter #'identity
|
||||
:action (lambda ()
|
||||
(save-excursion
|
||||
(cl-loop with limit = (org-entry-end-position)
|
||||
while (re-search-forward org-link-any-re limit t)
|
||||
for link = (string-trim (match-string 0))
|
||||
do (progn
|
||||
(set-text-properties 0 (length link) '(face org-link) link)
|
||||
(setf link (org-link-display-format link)))
|
||||
collect (cons link (copy-marker (match-beginning 0))))))
|
||||
:snippet (lambda (&rest _)
|
||||
"")
|
||||
:path (lambda (marker)
|
||||
(org-with-point-at marker
|
||||
(let* ((path (thread-first (org-get-outline-path t t)
|
||||
(org-format-outline-path (window-width) nil "")
|
||||
(org-split-string "")))
|
||||
(formatted-path (if org-ql-completing-read-reverse-paths
|
||||
(concat "\\" (string-join (reverse path) "\\"))
|
||||
(concat "/" (string-join path "/")))))
|
||||
formatted-path))))))
|
||||
(org-with-point-at marker
|
||||
(org-open-at-point))))
|
||||
|
||||
(provide 'org-ql-find)
|
||||
|
||||
;;; org-ql-find.el ends here
|
||||
|
|
|
|||
|
|
@ -44,13 +44,22 @@
|
|||
(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)))
|
||||
(t (error "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"))))
|
||||
|
||||
(defalias 'org-ql-search--org-make-link-string
|
||||
(cond ((fboundp 'org-link-make-string) #'org-link-make-string)
|
||||
((fboundp 'org-make-link-string) #'org-make-link-string)
|
||||
(t (error "org-ql: Unable to define alias `org-ql-search--org-make-link-string'. Please report this as a bug"))))
|
||||
|
||||
(defalias 'org-ql-search--org-link-store-props
|
||||
(cond ((fboundp 'org-link-store-props) #'org-link-store-props)
|
||||
((fboundp 'org-store-link-props) #'org-store-link-props)
|
||||
(t (error "org-ql: Unable to define alias `org-ql-search--org-link-store-props'. Please report this as a bug"))))
|
||||
|
||||
;;;; Variables
|
||||
|
||||
(defvar org-ql-block-header nil
|
||||
"An optional string to override the default header in `org-ql-block' agenda blocks.")
|
||||
"Optional string overriding default header in `org-ql-block' agenda blocks.")
|
||||
|
||||
;;;; Customization
|
||||
|
||||
|
|
@ -84,8 +93,8 @@ directories, etc, which would make it slow to list the
|
|||
The tree will show the lines where the query matches, and any
|
||||
other context defined in `org-show-context-detail', which see.
|
||||
|
||||
QUERY is an `org-ql' query sexp (quoted, since this is a
|
||||
function). BUFFER defaults to the current buffer.
|
||||
QUERY is an `org-ql' query in either sexp or string form (see
|
||||
Info node `(org-ql)Queries').
|
||||
|
||||
When KEEP-PREVIOUS is non-nil (interactively, with prefix), the
|
||||
outline is not reset to the overview state before finding
|
||||
|
|
@ -93,7 +102,7 @@ matches, which allows stacking calls to this command.
|
|||
|
||||
Runs `org-occur-hook' after making the sparse tree."
|
||||
;; Code based on `org-occur'.
|
||||
(interactive (list (read-minibuffer "Query: ")
|
||||
(interactive (list (read-string "Query: ")
|
||||
:keep-previous current-prefix-arg))
|
||||
(with-current-buffer buffer
|
||||
(unless keep-previous
|
||||
|
|
@ -101,8 +110,18 @@ Runs `org-occur-hook' after making the sparse tree."
|
|||
;; we remove existing `org-occur' highlights, just in case.
|
||||
(org-remove-occur-highlights nil nil t)
|
||||
(org-overview))
|
||||
(let ((num-results 0))
|
||||
;; FIXME: Accept plain queries as well.
|
||||
(let ((num-results 0)
|
||||
(query (pcase-exhaustive query
|
||||
((and (pred stringp)
|
||||
(rx bos (0+ blank) (or "(" "\"")))
|
||||
;; Read sexp query from string.
|
||||
(read query))
|
||||
((pred stringp)
|
||||
;; Parse string query into sexp query.
|
||||
(org-ql--query-string-to-sexp query))
|
||||
((pred listp)
|
||||
;; Sexp query.
|
||||
query))))
|
||||
(org-ql-select buffer query
|
||||
:action (lambda ()
|
||||
(org-show-context 'occur-tree)
|
||||
|
|
@ -277,9 +296,12 @@ Valid parameters include:
|
|||
:ts-format Optional format string used to format
|
||||
timestamp-based columns.
|
||||
|
||||
For example, an org-ql dynamic block header could look like:
|
||||
For example, an org-ql dynamic block header could look like
|
||||
this (must be a single line in the Org buffer):
|
||||
|
||||
#+BEGIN: org-ql :query (todo \"UNDERWAY\") :columns (priority todo heading) :sort (priority date) :ts-format \"%Y-%m-%d %H:%M\""
|
||||
#+BEGIN: org-ql :query (todo \"UNDERWAY\")
|
||||
:columns (priority todo heading) :sort (priority date)
|
||||
:ts-format \"%Y-%m-%d %H:%M\""
|
||||
(-let* (((&plist :query :columns :sort :ts-format :take) params)
|
||||
(query (cl-etypecase query
|
||||
(string (org-ql--query-string-to-sexp query))
|
||||
|
|
@ -296,7 +318,7 @@ For example, an org-ql dynamic block header could look like:
|
|||
(cons 'heading (lambda (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)))))
|
||||
(org-ql-search--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))))
|
||||
|
|
@ -345,13 +367,19 @@ For example, an org-ql dynamic block header could look like:
|
|||
|
||||
;;;; Functions
|
||||
|
||||
(defvar org-ql-search-directories-files-error
|
||||
;; Workaround to silence byte-compiler which thinks having this string in an
|
||||
;; argument's default value form is a too-long docstring.
|
||||
"No DIRECTORIES given, and `org-directory' doesn't exist")
|
||||
|
||||
(cl-defun org-ql-search-directories-files
|
||||
(&key (directories (if (file-exists-p org-directory)
|
||||
(&key (directories
|
||||
(if (file-exists-p org-directory)
|
||||
(list org-directory)
|
||||
(user-error "Org-ql-search-directories-files: No DIRECTORIES given, and `org-directory' doesn't exist")))
|
||||
(user-error org-ql-search-directories-files-error)))
|
||||
(recurse org-ql-search-directories-files-recursive)
|
||||
(regexp org-ql-search-directories-files-regexp))
|
||||
"Return list of matching files in DIRECTORIES, a list of directory paths.
|
||||
"Return list of matching files in DIRECTORIES.
|
||||
When RECURSE is non-nil, recurse into subdirectories. When
|
||||
REGEXP is non-nil, only return files that match REGEXP."
|
||||
(let ((files (->> directories
|
||||
|
|
|
|||
|
|
@ -40,10 +40,8 @@
|
|||
|
||||
(require 'org-ql)
|
||||
|
||||
;; FIXME: check-declare declares "function not found", even though it
|
||||
;; clearly is. It seems to not handle cl-defun, even though its code
|
||||
;; appears to account for it.
|
||||
(declare-function org-ql-search "org-ql-search" t)
|
||||
(declare-function org-ql-search--org-link-store-props "org-ql-search" t)
|
||||
|
||||
(require 'dash)
|
||||
(require 's)
|
||||
|
|
@ -288,7 +286,8 @@ TYPE may be `ts', `ts-active', `ts-inactive', `clocked', or
|
|||
|
||||
;;;###autoload
|
||||
(cl-defun org-ql-view-sidebar (&key (slot org-ql-view-list-slot))
|
||||
"Show `org-ql-view' view list sidebar."
|
||||
"Show `org-ql-view' view list sidebar.
|
||||
SLOT is passed to `display-buffer-in-side-window', which see."
|
||||
;; TODO: Update sidebar when `org-ql-views' changes.
|
||||
(interactive)
|
||||
(select-window
|
||||
|
|
@ -353,7 +352,8 @@ update search arguments."
|
|||
(yes-or-no-p (format "Overwrite view \"%s\"?" name)))
|
||||
(setf (map-elt org-ql-views name nil #'equal) plist)
|
||||
(customize-set-variable 'org-ql-views org-ql-views)
|
||||
(customize-mark-to-save 'org-ql-views))))
|
||||
(customize-mark-to-save 'org-ql-views)
|
||||
(custom-save-all))))
|
||||
|
||||
(defun org-ql-view-delete ()
|
||||
"Delete current view (with confirmation)."
|
||||
|
|
@ -363,7 +363,8 @@ update search arguments."
|
|||
(--remove (equal (car it) org-ql-view-title)
|
||||
org-ql-views))
|
||||
(customize-set-variable 'org-ql-views org-ql-views)
|
||||
(customize-mark-to-save 'org-ql-views)))
|
||||
(customize-mark-to-save 'org-ql-views)
|
||||
(custom-save-all)))
|
||||
|
||||
(defun org-ql-view-customize ()
|
||||
"Customize view at point in `org-ql-view-sidebar' buffer."
|
||||
|
|
@ -672,7 +673,7 @@ When opened, the link searches the buffer it's opened from."
|
|||
(when (buffer-base-buffer thing)
|
||||
(buffer-file-name (buffer-base-buffer thing))))))))
|
||||
(unless (strings-or-file-buffers-p org-ql-view-buffers-files)
|
||||
(user-error "Views that search non-file-backed buffers can't be linked to"))
|
||||
(user-error "%s" "Views that search non-file-backed buffers can't be linked to"))
|
||||
(let* ((query-string (--if-let (org-ql--query-sexp-to-string org-ql-view-query)
|
||||
it (org-ql-view--format-query org-ql-view-query)))
|
||||
(buffers-files (prompt-for (org-ql-view--contract-buffers-files org-ql-view-buffers-files)))
|
||||
|
|
@ -688,8 +689,7 @@ When opened, the link searches the buffer it's opened from."
|
|||
"?" (url-build-query-string (delete nil params))))
|
||||
(url (url-recreate-url (url-parse-make-urlobj "org-ql-search" nil nil nil nil
|
||||
filename))))
|
||||
;; FIXME: "Warning: ‘org-store-link-props’ is an obsolete function (as of Org 9.3); use ‘org-link-store-props’ instead"
|
||||
(org-store-link-props
|
||||
(org-ql-search--org-link-store-props
|
||||
:type "org-ql-search"
|
||||
:link url
|
||||
:description (concat "org-ql-search: " org-ql-view-title))))
|
||||
|
|
@ -820,6 +820,20 @@ When opened, the link searches the buffer it's opened from."
|
|||
|
||||
;;;; Faces/properties
|
||||
|
||||
(defalias 'org-ql-view--resolve-element-properties
|
||||
;; It would be preferable to define this as an inline function, but
|
||||
;; that would mean that users would have to recompile org-ql when
|
||||
;; upgrading to Org 9.7 or else get weird errors.
|
||||
;; TODO(someday): Define `org-ql-view--resolve-element-properties' as inline.
|
||||
(if (version<= "9.7" org-version)
|
||||
(lambda (node)
|
||||
"Resolve NODE's properties using `org-element-properties-resolve'."
|
||||
;; Silence warnings about `org-element-properties-resolve'
|
||||
;; being unresolved on earlier Org versions.
|
||||
(with-no-warnings
|
||||
(org-element-properties-resolve node 'force-undefer)))
|
||||
#'identity))
|
||||
|
||||
(defun org-ql-view--format-element (element)
|
||||
;; This essentially needs to do what `org-agenda-format-item' does,
|
||||
;; which is a lot. We are a long way from that, but it's a start.
|
||||
|
|
@ -829,6 +843,7 @@ returned by `org-element-parse-buffer'. If ELEMENT is nil,
|
|||
return an empty string."
|
||||
(if (not element)
|
||||
""
|
||||
(setf element (org-ql-view--resolve-element-properties element))
|
||||
(let* ((properties (cadr element))
|
||||
;; Remove the :parent property, which so bloats the size of
|
||||
;; the properties list that it makes it essentially
|
||||
|
|
@ -866,8 +881,7 @@ return an empty string."
|
|||
(not type))
|
||||
append type)))
|
||||
;; No marker found
|
||||
;; TODO: Use `display-warning' with `org-ql' as the type.
|
||||
(warn "No marker found for item: %s" title)
|
||||
(display-warning 'org-ql (format "No marker found for item: %s" title))
|
||||
(org-element-property :tags element))
|
||||
(org-element-property :tags element)))
|
||||
(tag-string (when tag-list
|
||||
|
|
@ -890,7 +904,8 @@ return an empty string."
|
|||
(char-to-string)
|
||||
(format "[#%s]")
|
||||
(org-ql-view--add-priority-face)))
|
||||
(habit-property (org-with-point-at (org-element-property :begin element)
|
||||
(habit-property (org-with-point-at (or (org-element-property :org-hd-marker element)
|
||||
(org-element-property :org-marker element))
|
||||
(when (org-is-habit-p)
|
||||
(org-habit-parse-todo))))
|
||||
(due-string (pcase (org-element-property :relative-due-date element)
|
||||
|
|
@ -1024,10 +1039,6 @@ property."
|
|||
;; These functions are somewhat regrettable because of the need to keep them
|
||||
;; in sync, but it seems worth it to provide users with the flexibility.
|
||||
|
||||
;; FIXME: `check-declare' declares that this function is not in org-ql-search, even though
|
||||
;; it is. It appears to happen because `org-ql-search-directories-files' is declared with
|
||||
;; `cl-defun', because when I remove "cl-", it finds it. This makes no sense, because the
|
||||
;; source code of `check-declare' shows that it searches for "cl-defun" declarations.
|
||||
(declare-function org-ql-search-directories-files "org-ql-search" t)
|
||||
|
||||
(defun org-ql-view--contract-buffers-files (buffers-files)
|
||||
|
|
|
|||
127
org-ql.el
127
org-ql.el
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
;; Author: Adam Porter <adam@alphapapa.net>
|
||||
;; Url: https://github.com/alphapapa/org-ql
|
||||
;; Version: 0.7-pre
|
||||
;; Version: 0.8-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.1") (s "1.12.0") (transient "0.1") (ts "0.2-pre"))
|
||||
;; Keywords: hypermedia, outlines, Org, agenda
|
||||
|
||||
|
|
@ -75,10 +75,11 @@ That is, \"CLOSED:\", \"DEADLINE:\", or \"SCHEDULED:\".")
|
|||
Tags are stored in match group 1. Match group 2 stores the tags
|
||||
without the enclosing colons.")
|
||||
|
||||
(defconst org-ql-link-regexp
|
||||
(defvaralias 'org-ql-link-regexp
|
||||
;; FIXME: `org-link-bracket-re' is void until `org-link-make-regexps' is called.
|
||||
(if (bound-and-true-p org-link-bracket-re)
|
||||
org-link-bracket-re
|
||||
org-bracket-link-regexp)
|
||||
'org-link-bracket-re
|
||||
'org-bracket-link-regexp)
|
||||
"Regexp used to match Org bracket links.
|
||||
Necessary because of changes in Org 9.something.")
|
||||
|
||||
|
|
@ -229,7 +230,8 @@ regexps.")
|
|||
(group-n 1 (regexp ,org-ql-regexp-ts-inactive)))
|
||||
(seq (or "DEADLINE" "SCHEDULED") ":" (0+ " ")
|
||||
(group-n 1 (regexp ,org-ql-regexp-ts-active))))))
|
||||
"Matches CLOSED, DEADLINE or SCHEDULED keyword with timestamp, with or without time.")
|
||||
"Matches CLOSED, DEADLINE or SCHEDULED keyword with timestamp.
|
||||
Matches with or without time.")
|
||||
|
||||
(defvar org-ql-regexp-planning-with-time
|
||||
(rx-to-string `(seq bow (or (seq "CLOSED" ":" (0+ " ")
|
||||
|
|
@ -503,8 +505,14 @@ NARROW corresponds to the `org-ql-select' argument NARROW."
|
|||
|
||||
(cl-defun org-ql--select (&key preamble preamble-case-fold predicate action narrow
|
||||
&allow-other-keys)
|
||||
"Return results of mapping function ACTION across entries in current buffer matching function PREDICATE.
|
||||
If NARROW is non-nil, buffer will not be widened."
|
||||
"Return results for given arguments.
|
||||
Return results of mapping function ACTION across entries in
|
||||
current buffer matching function PREDICATE. If NARROW is
|
||||
non-nil, buffer will not be widened.
|
||||
|
||||
PREAMBLE may be a regexp to search for before calling PREDICATE.
|
||||
When doing so, `case-fold-search' is bound to
|
||||
PREAMBLE-CASE-FOLD."
|
||||
;; Since the mappings are stored in the variable `org-ql-predicates', macros like `flet'
|
||||
;; can't be used, so we do it manually (this is same as the equivalent `flet' expansion).
|
||||
;; Mappings are stored in the variable because it allows predicates to be defined with a
|
||||
|
|
@ -616,9 +624,10 @@ Returns cons (INHERITED-TAGS . LOCAL-TAGS)."
|
|||
"Return outline path for heading at point."
|
||||
(save-excursion
|
||||
(let ((heading (save-match-data
|
||||
(let (case-fold-search)
|
||||
(if (looking-at org-complex-heading-regexp)
|
||||
(or (match-string 4) "")
|
||||
""))))
|
||||
(or (match-string-no-properties 4) "")
|
||||
"")))))
|
||||
(if (org-up-heading-safe)
|
||||
;; MAYBE: It seems wrong to call the cache function from
|
||||
;; inside this function, like a violation of separation of
|
||||
|
|
@ -768,7 +777,7 @@ be coalesced."
|
|||
"Signal error if any forms in FORM do not have preconditions met.
|
||||
Or, when possible, fix the problem."
|
||||
(cl-flet ((check (symbol)
|
||||
(cl-case symbol
|
||||
(pcase symbol
|
||||
('done (unless org-done-keywords
|
||||
;; NOTE: This check needs to be done from within the Org buffer being checked.
|
||||
(error "Variable `org-done-keywords' is nil. Are you running this from an Org buffer?"))))))
|
||||
|
|
@ -787,28 +796,33 @@ DESCRIPTION-OR-TARGET, match it in either description or target.
|
|||
If DESCRIPTION, match it in the description. If TARGET, match it
|
||||
in the target. If both DESCRIPTION and TARGET, match both,
|
||||
respectively."
|
||||
;; This `rx' part is borrowed from `org-make-link-regexps'. It matches the interior of an
|
||||
;; Org link target (i.e. the parts between the brackets, including any escaped brackets).
|
||||
(let ((link-target-part '(0+ (or (not (any "[]\\"))
|
||||
(and "\\" (0+ "\\\\") (any "[]"))
|
||||
(and (1+ "\\") (not (any "[]")))))))
|
||||
(cl-labels
|
||||
((no-desc
|
||||
(match) (rx-to-string `(seq (or bol (1+ blank))
|
||||
"[[" (0+ (not (any "]"))) (regexp ,match) (0+ (not (any "]")))
|
||||
"[[" ,link-target-part (regexp ,match) ,link-target-part
|
||||
"]]")))
|
||||
(match-both
|
||||
(description target)
|
||||
(rx-to-string `(seq (or bol (1+ blank))
|
||||
"[[" (0+ (not (any "]"))) (regexp ,target) (0+ (not (any "]")))
|
||||
"][" (0+ (not (any "]"))) (regexp ,description) (0+ (not (any "]")))
|
||||
"[[" ,link-target-part (regexp ,target) ,link-target-part
|
||||
"][" (*? anything) (regexp ,description) (*? anything)
|
||||
"]]")))
|
||||
;; Note that these actually allow empty descriptions
|
||||
;; or targets, depending on what they are matching.
|
||||
(match-desc
|
||||
(match) (rx-to-string `(seq (or bol (1+ blank))
|
||||
"[[" (0+ (not (any "]")))
|
||||
"][" (0+ (not (any "]"))) (regexp ,match) (0+ (not (any "]")))
|
||||
"[[" ,link-target-part
|
||||
"][" (*? anything) (regexp ,match) (*? anything)
|
||||
"]]")))
|
||||
(match-target
|
||||
(match) (rx-to-string `(seq (or bol (1+ blank))
|
||||
"[[" (0+ (not (any "]"))) (regexp ,match) (0+ (not (any "]")))
|
||||
"][" (0+ (not (any "]")))
|
||||
"[[" ,link-target-part (regexp ,match) ,link-target-part
|
||||
"][" (*? anything)
|
||||
"]]"))))
|
||||
(cond (description-or-target
|
||||
(rx-to-string `(or (regexp ,(no-desc description-or-target))
|
||||
|
|
@ -818,7 +832,7 @@ respectively."
|
|||
(match-both description target))
|
||||
(description (match-desc description))
|
||||
(target (rx-to-string `(or (regexp ,(no-desc target))
|
||||
(regexp ,(match-target target))))))))
|
||||
(regexp ,(match-target target)))))))))
|
||||
|
||||
(defun org-ql--format-src-block-regexp (&optional lang)
|
||||
"Return regexp equivalent to `org-babel-src-block-regexp' with LANG filled in."
|
||||
|
|
@ -932,7 +946,7 @@ value of `org-ql-predicates')."
|
|||
;; obscure bug in `peg': when one keyword is a substring of another,
|
||||
;; and the shorter one is listed first, the shorter one fails to match.
|
||||
(-sort (-on #'> #'length))))
|
||||
(pexs `((query (+ (and term (* [blank]))))
|
||||
(pexs `((query (and (* [blank]) (+ (and term (* [blank])))))
|
||||
(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))))
|
||||
|
|
@ -1273,6 +1287,9 @@ result form."
|
|||
to on))
|
||||
(when from
|
||||
(setq from (pcase from
|
||||
("-"
|
||||
;; Ignore, because it means the user is typing a negative number.
|
||||
nil)
|
||||
((or 'today "today") (->> (ts-now)
|
||||
(ts-apply :hour 0 :minute 0 :second 0)))
|
||||
((pred numberp) (->> (ts-now)
|
||||
|
|
@ -1289,6 +1306,9 @@ result form."
|
|||
((pred ts-p) from))))
|
||||
(when to
|
||||
(setq to (pcase to
|
||||
("-"
|
||||
;; Ignore, because it means the user is typing a negative number.
|
||||
nil)
|
||||
((or 'today "today") (->> (ts-now)
|
||||
(ts-apply :hour 23 :minute 59 :second 59)))
|
||||
((pred numberp) (->> (ts-now)
|
||||
|
|
@ -1326,8 +1346,13 @@ result form."
|
|||
;; redefinitions until all of the predicates have been defined.
|
||||
(setf org-ql-defpred-defer t)
|
||||
|
||||
(org-ql-defpred blocked ()
|
||||
"Return non-nil if entry is blocked.
|
||||
Calls `org-entry-blocked-p', which see."
|
||||
:body (org-entry-blocked-p))
|
||||
|
||||
(org-ql-defpred (category c) (&rest categories)
|
||||
"Return non-nil if current heading is in one or more of CATEGORIES (a list of strings)."
|
||||
"Return non-nil if current heading is in one or more of CATEGORIES."
|
||||
:normalizers ((`(,predicate-names . ,rest)
|
||||
`(category ,@rest)))
|
||||
:body (when-let ((category (org-get-category (point))))
|
||||
|
|
@ -1340,18 +1365,16 @@ result form."
|
|||
;; NOTE: This was a defsubst before being defined with the macro. Might be good to make it a defsubst again.
|
||||
:body (or (apply #'org-ql--predicate-todo org-done-keywords)))
|
||||
|
||||
(defun org-ql--duration-to-minutes (duration)
|
||||
(defalias 'org-ql--duration-to-minutes
|
||||
;; TODO: Remove when compatibility with Org 9.0 is dropped.
|
||||
(cond ((fboundp 'org-duration-to-minutes) #'org-duration-to-minutes)
|
||||
((fboundp 'org-duration-string-to-minutes) #'org-duration-string-to-minutes)
|
||||
(t (error "org-ql: Unable to define alias `org-ql-search--link-heading-search-string'. Please report this as a bug")))
|
||||
"Return DURATION string as a number of minutes.
|
||||
For compatibility, since Org 9.1 deprecated
|
||||
`org-duration-string-to-minutes', replacing it with
|
||||
`org-duration-to-minutes', which seems to return floats instead
|
||||
of integers."
|
||||
;; FIXME: Define this as an alias instead.
|
||||
;; MAYBE: Remove if compatibility with Org 9.0 is dropped.
|
||||
(funcall (if (fboundp 'org-duration-to-minutes)
|
||||
#'org-duration-to-minutes
|
||||
#'org-duration-string-to-minutes)
|
||||
duration))
|
||||
of integers.")
|
||||
|
||||
(org-ql-defpred effort (&optional effort-or-comparator effort)
|
||||
"Return non-nil if current heading's effort property matches arguments.
|
||||
|
|
@ -1359,7 +1382,8 @@ 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.
|
||||
(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\"."
|
||||
|
|
@ -1492,8 +1516,10 @@ Matching is done case-insensitively."
|
|||
The following forms are accepted:
|
||||
|
||||
(level NUMBER): Matches if heading level is NUMBER.
|
||||
(level NUMBER NUMBER): Matches if heading level is equal to or between NUMBERs.
|
||||
(level COMPARATOR NUMBER): Matches if heading level compares to NUMBER with COMPARATOR.
|
||||
(level NUMBER NUMBER): Matches if heading level is equal to or between
|
||||
NUMBERs.
|
||||
(level COMPARATOR NUMBER): Matches if heading level compares to NUMBER with
|
||||
COMPARATOR.
|
||||
|
||||
COMPARATOR may be `<', `<=', `>', or `>='."
|
||||
:normalizers ((`(,predicate-names . ,args)
|
||||
|
|
@ -1550,12 +1576,8 @@ any link is found."
|
|||
;; enabled nearly all of the time, in which case this function won't be called anyway, it's
|
||||
;; probably not worth rewriting code all over the place to fix this.
|
||||
:preambles ((`(,predicate-names)
|
||||
(list :regexp ;; Match a link with a target and optionally a description.
|
||||
(rx (or bol (1+ blank))
|
||||
"[[" (1+ (not (any "]"))) "]"
|
||||
(optional (seq "[" (0+ (not (any "]"))) "]"))
|
||||
"]"
|
||||
(or eol blank))))
|
||||
;; Match a link with a target and optionally a description.
|
||||
(list :regexp (org-ql--link-regexp :target ".*")))
|
||||
(`(,predicate-names ,(and description-or-target
|
||||
(guard (not (keywordp description-or-target))))
|
||||
. ,plist)
|
||||
|
|
@ -1610,7 +1632,7 @@ any link is found."
|
|||
(match-string org-ql-link-description-group)))))))))
|
||||
|
||||
(org-ql-defpred (rifle smart) (&rest strings)
|
||||
"Return non-nil if each string argument is found in either the entry or its outline path.
|
||||
"Return non-nil if each of strings is found in the entry or its outline path.
|
||||
Works like `org-rifle'. This is probably the most useful,
|
||||
intuitive, general-purpose predicate."
|
||||
;; NOTE: This predicate advertises that it takes strings, but they
|
||||
|
|
@ -1677,7 +1699,7 @@ contiguous segment of the outline path:
|
|||
:body (org-ql--infix-p regexps (org-ql--value-at (point) #'org-ql--outline-path)))
|
||||
|
||||
(org-ql-defpred path (&rest regexps)
|
||||
"Return non-nil if current heading's buffer's filename path matches any of REGEXPS (regexp strings).
|
||||
"Return non-nil if current heading's buffer's file path matches any of REGEXPS.
|
||||
Without arguments, return non-nil if buffer is file-backed."
|
||||
;; FIXME: This should AND the regexps together, not OR them.
|
||||
:body (when (buffer-file-name)
|
||||
|
|
@ -1764,7 +1786,7 @@ priority B)."
|
|||
thereis (= item-priority (* 1000 (- org-lowest-priority (string-to-char priority-arg)))))))))
|
||||
|
||||
(org-ql-defpred property (property &optional value &key inherit)
|
||||
"Return non-nil if current entry has PROPERTY (a string), and optionally VALUE (a string).
|
||||
"Return non-nil if current entry has PROPERTY, and optionally VALUE.
|
||||
If INHERIT is nil, only match entries with PROPERTY set on the
|
||||
entry; if t, also match entries with inheritance. If INHERIT is
|
||||
not specified, use the Boolean value of
|
||||
|
|
@ -1856,7 +1878,7 @@ interpreted as nil or non-nil)."
|
|||
(re-search-forward regexp end t))))))
|
||||
|
||||
(org-ql-defpred src (&key regexps lang)
|
||||
"Return non-nil if current entry contains an Org source block matching all of REGEXPS.
|
||||
"Return non-nil if current entry has an Org source block matching all REGEXPS.
|
||||
If keyword argument LANG is non-nil, the block must be in that
|
||||
language. Matching is done case-insensitively."
|
||||
:coalesce (lambda (coalesced-args current-args)
|
||||
|
|
@ -1925,14 +1947,12 @@ language. Matching is done case-insensitively."
|
|||
;; Always check contents with predicate.
|
||||
:query query)))
|
||||
:body
|
||||
(catch 'return
|
||||
(save-excursion
|
||||
(save-match-data
|
||||
(when (re-search-forward org-babel-src-block-regexp (org-entry-end-position) t)
|
||||
(when lang
|
||||
(unless (string= lang (match-string 2))
|
||||
(throw 'return nil)))
|
||||
(if regexps
|
||||
(cl-loop while (re-search-forward org-babel-src-block-regexp (org-entry-end-position) t)
|
||||
thereis (when (or (not lang) (equal lang (match-string 2)))
|
||||
(or (not regexps)
|
||||
(save-excursion
|
||||
(let ((contents-beg (progn
|
||||
(goto-char (match-beginning 0))
|
||||
(forward-line 1)
|
||||
|
|
@ -1942,9 +1962,7 @@ language. Matching is done case-insensitively."
|
|||
(point-at-bol))))
|
||||
(cl-loop for re in regexps
|
||||
do (goto-char contents-beg)
|
||||
always (re-search-forward re contents-end t)))
|
||||
;; No regexps to check: return non-nil.
|
||||
t))))))
|
||||
always (re-search-forward re contents-end t))))))))))
|
||||
|
||||
(org-ql-defpred (tags) (&rest tags)
|
||||
"Return non-nil if current heading has one or more of TAGS (a list of strings).
|
||||
|
|
@ -1972,7 +1990,7 @@ Tests both inherited and local tags."
|
|||
:body (apply #'org-ql--predicate-tags tags))
|
||||
|
||||
(org-ql-defpred (tags-inherited inherited-tags tags-i itags) (&rest tags)
|
||||
"Return non-nil if current heading's inherited tags include one or more of TAGS (a list of strings).
|
||||
"Return non-nil if current heading's inherited tags include any of TAGS.
|
||||
If TAGS is nil, return non-nil if heading has any inherited tags."
|
||||
:normalizers ((`(,predicate-names . ,tags)
|
||||
`(tags-inherited ,@tags)))
|
||||
|
|
@ -1986,7 +2004,7 @@ If TAGS is nil, return non-nil if heading has any inherited tags."
|
|||
(seq-intersection tags inherited)))))))
|
||||
|
||||
(org-ql-defpred (tags-local local-tags tags-l ltags) (&rest tags)
|
||||
"Return non-nil if current heading's local tags include one or more of TAGS (a list of strings).
|
||||
"Return non-nil if current heading's local tags include any of TAGS.
|
||||
If TAGS is nil, return non-nil if heading has any local tags."
|
||||
:normalizers ((`(,predicate-names . ,tags)
|
||||
`(tags-local ,@tags)))
|
||||
|
|
@ -2029,7 +2047,7 @@ Tests both inherited and local tags."
|
|||
|
||||
(org-ql-defpred 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)."
|
||||
With KEYWORDS, return non-nil if its keyword is one of KEYWORDS."
|
||||
;; TODO: Can we make a preamble for plain (todo) queries?
|
||||
:preambles ((`(,predicate-names . ,(and todo-keywords (guard todo-keywords)))
|
||||
(list :case-fold nil :regexp (rx-to-string `(seq bol (1+ "*") (1+ space) (or ,@todo-keywords) (or " " eol)) t))))
|
||||
|
|
@ -2243,7 +2261,8 @@ non-nil if entry has a deadline."
|
|||
(org-ql-defpred deadline-warning (&key from to)
|
||||
;; TODO: Should this also accept a WITH-TIME argument?
|
||||
;; MAYBE: Use the new org-ql-regexps?
|
||||
"Internal predicate used to handle `org-deadline-warning-days' and deadlines with warning periods."
|
||||
"Internal predicate.
|
||||
Used to handle `org-deadline-warning-days' and deadlines with warning periods."
|
||||
:preambles ((`(,predicate-names . ,_)
|
||||
(list :regexp org-deadline-time-regexp :query query)))
|
||||
:body
|
||||
|
|
|
|||
375
org-ql.info
375
org-ql.info
|
|
@ -1,4 +1,4 @@
|
|||
This is README.info, produced by makeinfo version 5.2 from README.texi.
|
||||
This is README.info, produced by makeinfo version 6.7 from README.texi.
|
||||
|
||||
INFO-DIR-SECTION Emacs
|
||||
START-INFO-DIR-ENTRY
|
||||
|
|
@ -48,6 +48,7 @@ Usage
|
|||
Commands
|
||||
|
||||
* org-ql-find::
|
||||
* org-ql-open-link::
|
||||
* org-ql-refile::
|
||||
* org-ql-search::
|
||||
* helm-org-ql::
|
||||
|
|
@ -71,7 +72,11 @@ Functions / Macros
|
|||
|
||||
Changelog
|
||||
|
||||
* 0.7-pre: 07-pre.
|
||||
* 0.8-pre: 08-pre.
|
||||
* 0.7.3: 073.
|
||||
* 0.7.2: 072.
|
||||
* 0.7.1: 071.
|
||||
* 0.7: 07.
|
||||
* 0.6.3: 063.
|
||||
* 0.6.2: 062.
|
||||
* 0.6.1: 061.
|
||||
|
|
@ -203,6 +208,7 @@ File: README.info, Node: Commands, Next: Queries, Up: Usage
|
|||
* Menu:
|
||||
|
||||
* org-ql-find::
|
||||
* org-ql-open-link::
|
||||
* org-ql-refile::
|
||||
* org-ql-search::
|
||||
* helm-org-ql::
|
||||
|
|
@ -212,7 +218,7 @@ File: README.info, Node: Commands, Next: Queries, Up: Usage
|
|||
* org-ql-sparse-tree::
|
||||
|
||||
|
||||
File: README.info, Node: org-ql-find, Next: org-ql-refile, Up: Commands
|
||||
File: README.info, Node: org-ql-find, Next: org-ql-open-link, Up: Commands
|
||||
|
||||
4.1.1 org-ql-find
|
||||
-----------------
|
||||
|
|
@ -223,13 +229,38 @@ _Note: These commands use ._
|
|||
completion facilities with an Org QL query:
|
||||
|
||||
• ‘org-ql-find’ searches in the current buffer.
|
||||
• ‘org-ql-find-path’ searches outline paths in the current buffer.
|
||||
• ‘org-ql-find-in-agenda’ searches in ‘(org-agenda-files)’.
|
||||
• ‘org-ql-find-in-org-directory’ searches in ‘org-directory’.
|
||||
|
||||
|
||||
File: README.info, Node: org-ql-refile, Next: org-ql-search, Prev: org-ql-find, Up: Commands
|
||||
Note that these commands are compatible with Embark
|
||||
(https://github.com/oantolin/embark): the ‘embark-act’ command can be
|
||||
called on a completion candidate (i.e. a search result) to act on it
|
||||
immediately, without having to visit the entry in its source Org buffer.
|
||||
|
||||
4.1.2 org-ql-refile
|
||||
|
||||
File: README.info, Node: org-ql-open-link, Next: org-ql-refile, Prev: org-ql-find, Up: Commands
|
||||
|
||||
4.1.2 org-ql-open-link
|
||||
----------------------
|
||||
|
||||
This command finds links in entries matching the input query and offers
|
||||
them for selection; the selected link is then opened with
|
||||
‘org-open-at-point’.
|
||||
|
||||
The input is matched using the default predicate, which means it
|
||||
searches both entry content and outline paths. This is helpful when a
|
||||
collection of links are kept in Org files: rather than having to first
|
||||
visit the entry containing the desired link, then locate it within the
|
||||
entry, and then open it, the user can simply select the link and open it
|
||||
directly. For example, if an entry with the heading ‘Emacs’ contained a
|
||||
link named ‘mailing list’, one could search for ‘Emacs list’ and open
|
||||
the link to the mailing list directly.
|
||||
|
||||
|
||||
File: README.info, Node: org-ql-refile, Next: org-ql-search, Prev: org-ql-open-link, Up: Commands
|
||||
|
||||
4.1.3 org-ql-refile
|
||||
-------------------
|
||||
|
||||
This command refiles the current Org entry to one selected by searching
|
||||
|
|
@ -239,7 +270,7 @@ with Org QL completion. It searches files listed in
|
|||
|
||||
File: README.info, Node: org-ql-search, Next: helm-org-ql, Prev: org-ql-refile, Up: Commands
|
||||
|
||||
4.1.3 org-ql-search
|
||||
4.1.4 org-ql-search
|
||||
-------------------
|
||||
|
||||
_Note: This command supports both sexp queries and ._
|
||||
|
|
@ -279,10 +310,15 @@ This feature is experimental and not guaranteed to work correctly with
|
|||
all commands. (It works to the extent it does because the appropriate
|
||||
text properties are placed on each item, imitating an Agenda buffer.)
|
||||
|
||||
*Note:* Also, this buffer is compatible with Embark
|
||||
(https://github.com/oantolin/embark): the ‘embark-act’ command can be
|
||||
called on an entry to act on it immediately, without having to visit the
|
||||
entry in its source Org buffer.
|
||||
|
||||
|
||||
File: README.info, Node: helm-org-ql, Next: org-ql-view, Prev: org-ql-search, Up: Commands
|
||||
|
||||
4.1.4 helm-org-ql
|
||||
4.1.5 helm-org-ql
|
||||
-----------------
|
||||
|
||||
_Note: This command uses . It is available separately in the package
|
||||
|
|
@ -296,7 +332,7 @@ _Note: This command uses . It is available separately in the package
|
|||
|
||||
File: README.info, Node: org-ql-view, Next: org-ql-view-sidebar, Prev: helm-org-ql, Up: Commands
|
||||
|
||||
4.1.5 org-ql-view
|
||||
4.1.6 org-ql-view
|
||||
-----------------
|
||||
|
||||
Choose and display a view stored in ‘org-ql-views’.
|
||||
|
|
@ -311,7 +347,7 @@ Choose and display a view stored in ‘org-ql-views’.
|
|||
|
||||
File: README.info, Node: org-ql-view-sidebar, Next: org-ql-view-recent-items, Prev: org-ql-view, Up: Commands
|
||||
|
||||
4.1.6 org-ql-view-sidebar
|
||||
4.1.7 org-ql-view-sidebar
|
||||
-------------------------
|
||||
|
||||
Show a sidebar window listing views stored in ‘org-ql-views’ for easy
|
||||
|
|
@ -321,7 +357,7 @@ point, and press ‘c’ to customize the view at point.
|
|||
|
||||
File: README.info, Node: org-ql-view-recent-items, Next: org-ql-sparse-tree, Prev: org-ql-view-sidebar, Up: Commands
|
||||
|
||||
4.1.7 org-ql-view-recent-items
|
||||
4.1.8 org-ql-view-recent-items
|
||||
------------------------------
|
||||
|
||||
Show items in ‘FILES’ from last ‘DAYS’ days with timestamps of ‘TYPE’.
|
||||
|
|
@ -332,7 +368,7 @@ returned by the function ‘org-agenda-files’.
|
|||
|
||||
File: README.info, Node: org-ql-sparse-tree, Prev: org-ql-view-recent-items, Up: Commands
|
||||
|
||||
4.1.8 org-ql-sparse-tree
|
||||
4.1.9 org-ql-sparse-tree
|
||||
------------------------
|
||||
|
||||
Arguments: ‘(query &key keep-previous (buffer (current-buffer)))’
|
||||
|
|
@ -415,6 +451,9 @@ File: README.info, Node: General predicates, Next: Ancestor/descendant predica
|
|||
|
||||
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).
|
||||
|
|
@ -987,7 +1026,11 @@ releases.
|
|||
|
||||
* Menu:
|
||||
|
||||
* 0.7-pre: 07-pre.
|
||||
* 0.8-pre: 08-pre.
|
||||
* 0.7.3: 073.
|
||||
* 0.7.2: 072.
|
||||
* 0.7.1: 071.
|
||||
* 0.7: 07.
|
||||
* 0.6.3: 063.
|
||||
* 0.6.2: 062.
|
||||
* 0.6.1: 061.
|
||||
|
|
@ -1015,11 +1058,107 @@ releases.
|
|||
* 0.1: 01.
|
||||
|
||||
|
||||
File: README.info, Node: 07-pre, Next: 063, Up: Changelog
|
||||
File: README.info, Node: 08-pre, Next: 073, Up: Changelog
|
||||
|
||||
5.1 0.7-pre
|
||||
5.1 0.8-pre
|
||||
===========
|
||||
|
||||
*Additions*
|
||||
|
||||
• Function ‘org-ql-completing-read’, used by command ‘org-ql-find’,
|
||||
now specifies the completion category as ‘org-heading’, providing
|
||||
compatibility with Embark (https://github.com/oantolin/embark).
|
||||
(This is a powerful feature, as it means any ‘org-ql-find’ result
|
||||
can be acted on from inside the search results with Embark, which
|
||||
provides common actions from Org Agenda and Org speed keys
|
||||
bindings.) (#299 (https://github.com/alphapapa/org-ql/issues/299).
|
||||
Thanks to Omar Antolín Camarena (https://github.com/oantolin),
|
||||
Daniel Mendler (https://github.com/minad), and Akira Komamura
|
||||
(https://github.com/akirak).)
|
||||
• Command ‘org-ql-find’ may be called in an ‘org-agenda’ or
|
||||
‘org-ql-view’ buffer to search the buffers which contributed to the
|
||||
agenda/view buffer.
|
||||
• Command ‘org-ql-find-path’, which searches outline paths in the
|
||||
current buffer.
|
||||
• Command ‘org-ql-open-link’, which finds links in entries matching
|
||||
the given query, and opens the selected one with
|
||||
‘org-open-at-point’. (This is helpful when a collection of links
|
||||
are kept in Org files: rather than having to first visit the entry
|
||||
containing the desired link, then locate it within the entry, and
|
||||
then open it, the user can simply select the link and open it
|
||||
directly.)
|
||||
|
||||
*Compatibility*
|
||||
|
||||
• Org v9.7’s ‘org-element’ API changes required some adjustments.
|
||||
(#364 (https://github.com/alphapapa/org-ql/issues/364). Thanks to
|
||||
several users for reporting, and to Ihor Radchenko
|
||||
(https://github.com/yantar92) for his feedback.)
|
||||
|
||||
|
||||
File: README.info, Node: 073, Next: 072, Prev: 08-pre, Up: Changelog
|
||||
|
||||
5.2 0.7.3
|
||||
=========
|
||||
|
||||
*Fixes*
|
||||
• Disable ‘case-fold-search’ when collecting headings in outline
|
||||
paths. (Headings that started with a word that is also a to-do
|
||||
keyword but with different capitalization would be matched
|
||||
incorrectly.)
|
||||
• Saving of ‘org-ql-view’ views. (#378
|
||||
(https://github.com/alphapapa/org-ql/issues/378). Thanks to
|
||||
Pentaquark1 (https://github.com/Pentaquark1) for reporting.)
|
||||
• Command ‘org-ql-find’ didn’t move point to the selected entry.
|
||||
(#380 (https://github.com/alphapapa/org-ql/issues/380). Thanks to
|
||||
Omar Antolín Camarena (https://github.com/oantolin) for reporting.)
|
||||
|
||||
|
||||
File: README.info, Node: 072, Next: 071, Prev: 073, Up: Changelog
|
||||
|
||||
5.3 0.7.2
|
||||
=========
|
||||
|
||||
*Fixes*
|
||||
• Timestamp predicates are more tolerant of partial input (e.g.
|
||||
preventing errors while the user is typing a query into
|
||||
‘org-ql-find’).
|
||||
• Query parser ignores leading whitespace (e.g. preventing errors
|
||||
while the user is typing a query into ‘org-ql-find’).
|
||||
• Use of ‘org-ql-find’ with ‘:query-prefix’ argument prevented
|
||||
selection of results. (#351
|
||||
(https://github.com/alphapapa/org-ql/issues/351). Thanks to Daniel
|
||||
Fleischer (https://github.com/danielfleischer) for reporting.)
|
||||
• Handle narrowed buffers correctly in ‘org-ql-find’.
|
||||
• Warn about empty headings in ‘org-ql-completing-read’ (the Org
|
||||
format allows a heading line to have no text, but it’s useless for
|
||||
this purpose, and usually indicates unnoticed corruption).
|
||||
|
||||
|
||||
File: README.info, Node: 071, Next: 07, Prev: 072, Up: Changelog
|
||||
|
||||
5.4 0.7.1
|
||||
=========
|
||||
|
||||
*Fixes*
|
||||
• Function ‘org-ql-completing-read’ is more compatible with default
|
||||
Emacs completion. (See #338
|
||||
(https://github.com/alphapapa/org-ql/issues/338). Thanks to
|
||||
arozbiz (https://github.com/arozbiz) for reporting.)
|
||||
• Function ‘org-ql-completing-read’ would sometimes stop updating
|
||||
with changes in input. (See #350
|
||||
(https://github.com/alphapapa/org-ql/issues/350). Thanks to Ankit
|
||||
Raj Pandey (https://github.com/anpandey) for reporting and fixing,
|
||||
and to Daniel Mendler (https://github.com/minad) for advising.)
|
||||
• In ‘org-ql-completing-read’, format links for display, and use
|
||||
‘org-entry-get’ internally rather than ‘org-get-heading’.
|
||||
|
||||
|
||||
File: README.info, Node: 07, Next: 063, Prev: 071, Up: Changelog
|
||||
|
||||
5.5 0.7
|
||||
=======
|
||||
|
||||
*Added*
|
||||
• Commands ‘org-ql-find’, ‘org-ql-find-heading’, and
|
||||
‘org-ql-find-path’, which jump to entries selected using Emacs’s
|
||||
|
|
@ -1042,20 +1181,31 @@ File: README.info, Node: 07-pre, Next: 063, Up: Changelog
|
|||
entries with property inheritance, and when unspecified, the option
|
||||
‘org-use-property-inheritance’ controls whether inheritance is
|
||||
used.
|
||||
• Predicate ‘blocked’. (Thanks to Akira Komamura
|
||||
(https://github.com/akirak).)
|
||||
|
||||
*Changed*
|
||||
• Give more useful error message for invalid queries.
|
||||
• Predicate ‘src’ now matches case-insensitively.
|
||||
• Command ‘org-ql-sparse-tree’ accepts both string and sexp queries.
|
||||
(Thanks to Akira Komamura (https://github.com/akirak).)
|
||||
|
||||
*Fixed*
|
||||
• Predicate ‘link’ matches links whose descriptions contain escaped
|
||||
brackets (changed in Org 9.3). (Thanks to Daniel Borchmann
|
||||
(https://github.com/exot) for reporting.)
|
||||
• Predicate ‘src’’s matching of begin/end block lines, normalization
|
||||
of arguments, and handling in non-sexp queries.
|
||||
of arguments, and handling in non-sexp queries. (Thanks to Akira
|
||||
Komamura (https://github.com/akirak) for reporting.)
|
||||
• Predicate ‘src’’s behavior with various arguments.
|
||||
• Various compilation warnings.
|
||||
|
||||
*Internal*
|
||||
• Certain query predicates, when called multiple times in an ‘and’
|
||||
sub-expression, are optimized to a single call.
|
||||
• Use ‘buffer-chars-modified-tick’ instead of ‘buffer-modified-tick’.
|
||||
(Thanks to Ihor Radchenko (https://github.com/yantar92).)
|
||||
• Implemented tests for ‘src’ predicate.
|
||||
|
||||
*Credits*
|
||||
• Thanks to Caleb Chase (https://github.com/chasecaleb) for help with
|
||||
|
|
@ -1064,9 +1214,9 @@ File: README.info, Node: 07-pre, Next: 063, Up: Changelog
|
|||
(https://github.com/alphapapa/org-ql/commit/91908186fcca4b5fd2e9d26da5bc0375c2b41acf).
|
||||
|
||||
|
||||
File: README.info, Node: 063, Next: 062, Prev: 07-pre, Up: Changelog
|
||||
File: README.info, Node: 063, Next: 062, Prev: 07, Up: Changelog
|
||||
|
||||
5.2 0.6.3
|
||||
5.6 0.6.3
|
||||
=========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1082,7 +1232,7 @@ File: README.info, Node: 063, Next: 062, Prev: 07-pre, Up: Changelog
|
|||
|
||||
File: README.info, Node: 062, Next: 061, Prev: 063, Up: Changelog
|
||||
|
||||
5.3 0.6.2
|
||||
5.7 0.6.2
|
||||
=========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1093,7 +1243,7 @@ File: README.info, Node: 062, Next: 061, Prev: 063, Up: Changelog
|
|||
|
||||
File: README.info, Node: 061, Next: 06, Prev: 062, Up: Changelog
|
||||
|
||||
5.4 0.6.1
|
||||
5.8 0.6.1
|
||||
=========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1111,7 +1261,7 @@ File: README.info, Node: 061, Next: 06, Prev: 062, Up: Changelog
|
|||
|
||||
File: README.info, Node: 06, Next: 052, Prev: 061, Up: Changelog
|
||||
|
||||
5.5 0.6
|
||||
5.9 0.6
|
||||
=======
|
||||
|
||||
*Added*
|
||||
|
|
@ -1178,8 +1328,8 @@ File: README.info, Node: 06, Next: 052, Prev: 061, Up: Changelog
|
|||
|
||||
File: README.info, Node: 052, Next: 051, Prev: 06, Up: Changelog
|
||||
|
||||
5.6 0.5.2
|
||||
=========
|
||||
5.10 0.5.2
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
• Predicate ‘link’’s ‘:target’ and ‘:regexp-p’ arguments. (#220
|
||||
|
|
@ -1189,8 +1339,8 @@ File: README.info, Node: 052, Next: 051, Prev: 06, Up: Changelog
|
|||
|
||||
File: README.info, Node: 051, Next: 05, Prev: 052, Up: Changelog
|
||||
|
||||
5.7 0.5.1
|
||||
=========
|
||||
5.11 0.5.1
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
• Custom sorting functions could corrupt the cache, causing items to
|
||||
|
|
@ -1202,8 +1352,8 @@ File: README.info, Node: 051, Next: 05, Prev: 052, Up: Changelog
|
|||
|
||||
File: README.info, Node: 05, Next: 049, Prev: 051, Up: Changelog
|
||||
|
||||
5.8 0.5
|
||||
=======
|
||||
5.12 0.5
|
||||
========
|
||||
|
||||
*Added*
|
||||
• View dispatcher using ‘transient.el’ (like Magit), bound to ‘v’ in
|
||||
|
|
@ -1243,8 +1393,8 @@ File: README.info, Node: 05, Next: 049, Prev: 051, Up: Changelog
|
|||
|
||||
File: README.info, Node: 049, Next: 048, Prev: 05, Up: Changelog
|
||||
|
||||
5.9 0.4.9
|
||||
=========
|
||||
5.13 0.4.9
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
• Agenda restriction in ‘org-ql-block’. (Fixes #84
|
||||
|
|
@ -1254,7 +1404,7 @@ File: README.info, Node: 049, Next: 048, Prev: 05, Up: Changelog
|
|||
|
||||
File: README.info, Node: 048, Next: 047, Prev: 049, Up: Changelog
|
||||
|
||||
5.10 0.4.8
|
||||
5.14 0.4.8
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1266,7 +1416,7 @@ File: README.info, Node: 048, Next: 047, Prev: 049, Up: Changelog
|
|||
|
||||
File: README.info, Node: 047, Next: 046, Prev: 048, Up: Changelog
|
||||
|
||||
5.11 0.4.7
|
||||
5.15 0.4.7
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1279,7 +1429,7 @@ File: README.info, Node: 047, Next: 046, Prev: 048, Up: Changelog
|
|||
|
||||
File: README.info, Node: 046, Next: 045, Prev: 047, Up: Changelog
|
||||
|
||||
5.12 0.4.6
|
||||
5.16 0.4.6
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1292,7 +1442,7 @@ File: README.info, Node: 046, Next: 045, Prev: 047, Up: Changelog
|
|||
|
||||
File: README.info, Node: 045, Next: 044, Prev: 046, Up: Changelog
|
||||
|
||||
5.13 0.4.5
|
||||
5.17 0.4.5
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1304,7 +1454,7 @@ File: README.info, Node: 045, Next: 044, Prev: 046, Up: Changelog
|
|||
|
||||
File: README.info, Node: 044, Next: 043, Prev: 045, Up: Changelog
|
||||
|
||||
5.14 0.4.4
|
||||
5.18 0.4.4
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1316,7 +1466,7 @@ File: README.info, Node: 044, Next: 043, Prev: 045, Up: Changelog
|
|||
|
||||
File: README.info, Node: 043, Next: 042, Prev: 044, Up: Changelog
|
||||
|
||||
5.15 0.4.3
|
||||
5.19 0.4.3
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1326,7 +1476,7 @@ File: README.info, Node: 043, Next: 042, Prev: 044, Up: Changelog
|
|||
|
||||
File: README.info, Node: 042, Next: 041, Prev: 043, Up: Changelog
|
||||
|
||||
5.16 0.4.2
|
||||
5.20 0.4.2
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1335,7 +1485,7 @@ File: README.info, Node: 042, Next: 041, Prev: 043, Up: Changelog
|
|||
|
||||
File: README.info, Node: 041, Next: 04, Prev: 042, Up: Changelog
|
||||
|
||||
5.17 0.4.1
|
||||
5.21 0.4.1
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1345,7 +1495,7 @@ File: README.info, Node: 041, Next: 04, Prev: 042, Up: Changelog
|
|||
|
||||
File: README.info, Node: 04, Next: 032, Prev: 041, Up: Changelog
|
||||
|
||||
5.18 0.4
|
||||
5.22 0.4
|
||||
========
|
||||
|
||||
_Note:_ The next release, 0.5, may include changes which will require
|
||||
|
|
@ -1426,7 +1576,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.19 0.3.2
|
||||
5.23 0.3.2
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1439,7 +1589,7 @@ File: README.info, Node: 032, Next: 031, Prev: 04, Up: Changelog
|
|||
|
||||
File: README.info, Node: 031, Next: 03, Prev: 032, Up: Changelog
|
||||
|
||||
5.20 0.3.1
|
||||
5.24 0.3.1
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1449,7 +1599,7 @@ File: README.info, Node: 031, Next: 03, Prev: 032, Up: Changelog
|
|||
|
||||
File: README.info, Node: 03, Next: 023, Prev: 031, Up: Changelog
|
||||
|
||||
5.21 0.3
|
||||
5.25 0.3
|
||||
========
|
||||
|
||||
*Added*
|
||||
|
|
@ -1517,7 +1667,7 @@ File: README.info, Node: 03, Next: 023, Prev: 031, Up: Changelog
|
|||
|
||||
File: README.info, Node: 023, Next: 022, Prev: 03, Up: Changelog
|
||||
|
||||
5.22 0.2.3
|
||||
5.26 0.2.3
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1527,7 +1677,7 @@ File: README.info, Node: 023, Next: 022, Prev: 03, Up: Changelog
|
|||
|
||||
File: README.info, Node: 022, Next: 021, Prev: 023, Up: Changelog
|
||||
|
||||
5.23 0.2.2
|
||||
5.27 0.2.2
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1538,7 +1688,7 @@ File: README.info, Node: 022, Next: 021, Prev: 023, Up: Changelog
|
|||
|
||||
File: README.info, Node: 021, Next: 02, Prev: 022, Up: Changelog
|
||||
|
||||
5.24 0.2.1
|
||||
5.28 0.2.1
|
||||
==========
|
||||
|
||||
*Fixed*
|
||||
|
|
@ -1548,7 +1698,7 @@ File: README.info, Node: 021, Next: 02, Prev: 022, Up: Changelog
|
|||
|
||||
File: README.info, Node: 02, Next: 01, Prev: 021, Up: Changelog
|
||||
|
||||
5.25 0.2
|
||||
5.29 0.2
|
||||
========
|
||||
|
||||
*Added*
|
||||
|
|
@ -1631,7 +1781,7 @@ File: README.info, Node: 02, Next: 01, Prev: 021, Up: Changelog
|
|||
|
||||
File: README.info, Node: 01, Prev: 02, Up: Changelog
|
||||
|
||||
5.26 0.1
|
||||
5.30 0.1
|
||||
========
|
||||
|
||||
First tagged release.
|
||||
|
|
@ -1689,70 +1839,75 @@ GPLv3
|
|||
|
||||
Tag Table:
|
||||
Node: Top225
|
||||
Node: Contents1797
|
||||
Node: Screenshots1920
|
||||
Node: Installation2038
|
||||
Node: Quelpa2552
|
||||
Node: Helm support3080
|
||||
Node: Usage3483
|
||||
Node: Commands3881
|
||||
Node: org-ql-find4325
|
||||
Node: org-ql-refile4791
|
||||
Node: org-ql-search5114
|
||||
Node: helm-org-ql6810
|
||||
Node: org-ql-view7188
|
||||
Node: org-ql-view-sidebar7718
|
||||
Node: org-ql-view-recent-items8098
|
||||
Node: org-ql-sparse-tree8594
|
||||
Node: Queries9394
|
||||
Node: Non-sexp query syntax10511
|
||||
Node: General predicates12270
|
||||
Node: Ancestor/descendant predicates19142
|
||||
Node: Date/time predicates20270
|
||||
Node: Functions / Macros23394
|
||||
Node: Agenda-like views23692
|
||||
Ref: Function ‘org-ql-block’23854
|
||||
Node: Listing / acting-on results25115
|
||||
Ref: Caching25323
|
||||
Ref: Function ‘org-ql-select’26236
|
||||
Ref: Function ‘org-ql-query’28662
|
||||
Ref: Macro ‘org-ql’ (deprecated)30436
|
||||
Node: Custom predicates30751
|
||||
Ref: Macro ‘org-ql-defpred’30975
|
||||
Node: Dynamic block34416
|
||||
Node: Links37140
|
||||
Node: Tips37827
|
||||
Node: Changelog38151
|
||||
Node: 07-pre38934
|
||||
Node: 06341209
|
||||
Node: 06241744
|
||||
Node: 06142049
|
||||
Node: 0642617
|
||||
Node: 05245671
|
||||
Node: 05145971
|
||||
Node: 0546394
|
||||
Node: 04947923
|
||||
Node: 04848203
|
||||
Node: 04748552
|
||||
Node: 04648961
|
||||
Node: 04549369
|
||||
Node: 04449730
|
||||
Node: 04350089
|
||||
Node: 04250292
|
||||
Node: 04150453
|
||||
Node: 0450700
|
||||
Node: 03254801
|
||||
Node: 03155204
|
||||
Node: 0355401
|
||||
Node: 02358701
|
||||
Node: 02258935
|
||||
Node: 02159215
|
||||
Node: 0259420
|
||||
Node: 0163498
|
||||
Node: Notes63599
|
||||
Node: Comparison with Org Agenda searches63761
|
||||
Node: org-sidebar64650
|
||||
Node: License64929
|
||||
Node: Contents1845
|
||||
Node: Screenshots1968
|
||||
Node: Installation2086
|
||||
Node: Quelpa2600
|
||||
Node: Helm support3128
|
||||
Node: Usage3531
|
||||
Node: Commands3929
|
||||
Node: org-ql-find4394
|
||||
Node: org-ql-open-link5212
|
||||
Node: org-ql-refile6067
|
||||
Node: org-ql-search6395
|
||||
Node: helm-org-ql8326
|
||||
Node: org-ql-view8704
|
||||
Node: org-ql-view-sidebar9234
|
||||
Node: org-ql-view-recent-items9614
|
||||
Node: org-ql-sparse-tree10110
|
||||
Node: Queries10910
|
||||
Node: Non-sexp query syntax12027
|
||||
Node: General predicates13786
|
||||
Node: Ancestor/descendant predicates20773
|
||||
Node: Date/time predicates21901
|
||||
Node: Functions / Macros25025
|
||||
Node: Agenda-like views25323
|
||||
Ref: Function org-ql-block25485
|
||||
Node: Listing / acting-on results26746
|
||||
Ref: Caching26954
|
||||
Ref: Function org-ql-select27867
|
||||
Ref: Function org-ql-query30293
|
||||
Ref: Macro org-ql (deprecated)32067
|
||||
Node: Custom predicates32382
|
||||
Ref: Macro org-ql-defpred32606
|
||||
Node: Dynamic block36047
|
||||
Node: Links38771
|
||||
Node: Tips39458
|
||||
Node: Changelog39782
|
||||
Node: 08-pre40592
|
||||
Node: 07342357
|
||||
Node: 07243092
|
||||
Node: 07144011
|
||||
Node: 0744820
|
||||
Node: 06347744
|
||||
Node: 06248275
|
||||
Node: 06148580
|
||||
Node: 0649148
|
||||
Node: 05252202
|
||||
Node: 05152504
|
||||
Node: 0552929
|
||||
Node: 04954460
|
||||
Node: 04854742
|
||||
Node: 04755091
|
||||
Node: 04655500
|
||||
Node: 04555908
|
||||
Node: 04456269
|
||||
Node: 04356628
|
||||
Node: 04256831
|
||||
Node: 04156992
|
||||
Node: 0457239
|
||||
Node: 03261340
|
||||
Node: 03161743
|
||||
Node: 0361940
|
||||
Node: 02365240
|
||||
Node: 02265474
|
||||
Node: 02165754
|
||||
Node: 0265959
|
||||
Node: 0170037
|
||||
Node: Notes70138
|
||||
Node: Comparison with Org Agenda searches70300
|
||||
Node: org-sidebar71189
|
||||
Node: License71468
|
||||
|
||||
End Tag Table
|
||||
|
||||
|
|
|
|||
10
tests/data-links.org
Normal file
10
tests/data-links.org
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
* Alpha
|
||||
|
||||
Let us link to: [[id:74d357ac-fb9c-40d1-a63f-eca8a227321d][Bravo [a phrase in brackets]]].
|
||||
|
||||
* Bravo [a phrase in brackets]
|
||||
:PROPERTIES:
|
||||
:ID: 74d357ac-fb9c-40d1-a63f-eca8a227321d
|
||||
:END:
|
||||
|
||||
* Charlie
|
||||
29
tests/data-src.org
Normal file
29
tests/data-src.org
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#+title: org-ql test data for ~src~ predicate
|
||||
|
||||
* Alpha
|
||||
|
||||
#+begin_src elisp
|
||||
(message "foo")
|
||||
#+end_src
|
||||
|
||||
#+begin_src python
|
||||
print("foo")
|
||||
#+end_src
|
||||
|
||||
#+begin_src js
|
||||
console.log("foo")
|
||||
#+end_src
|
||||
|
||||
* Bravo
|
||||
|
||||
#+begin_src elisp
|
||||
(message "bar")
|
||||
#+end_src
|
||||
|
||||
#+begin_src python
|
||||
print("bar")
|
||||
#+end_src
|
||||
|
||||
* Charlie
|
||||
|
||||
This entry has no source block.
|
||||
|
|
@ -30,8 +30,11 @@
|
|||
(require 'with-simulated-input)
|
||||
|
||||
(require 'org-ql)
|
||||
(require 'org-ql-search)
|
||||
(require 'org-ql-view)
|
||||
|
||||
(require 'xr)
|
||||
|
||||
;;;; Variables
|
||||
|
||||
(defvar org-ql-test-buffer nil
|
||||
|
|
@ -112,20 +115,17 @@ FILENAME should be a file in the \"tests\" directory."
|
|||
;;;; Macros
|
||||
|
||||
(defmacro org-ql-it (description &rest body)
|
||||
"Expand to two specs, one of which tests with preambles and the other without.
|
||||
Based on Buttercup macro `it'."
|
||||
"Expand to two specs, one of which tests with preambles and the other without."
|
||||
(declare (indent 1) (debug (&define sexp def-body)))
|
||||
(if body
|
||||
`(progn
|
||||
(buttercup-it ,(concat description " (preamble) ")
|
||||
(lambda ()
|
||||
(let ((org-ql-use-preamble t))
|
||||
(it ,(concat description " (preamble) ")
|
||||
,(when body
|
||||
`(let ((org-ql-use-preamble t))
|
||||
,@body)))
|
||||
(buttercup-it ,(concat description " (no preamble)")
|
||||
(lambda ()
|
||||
(let ((org-ql-use-preamble nil))
|
||||
,@body))))
|
||||
`(buttercup-xit ,description)))
|
||||
(it ,(concat description " (no preamble) ")
|
||||
,(when body
|
||||
`(let ((org-ql-use-preamble nil))
|
||||
,@body)))) )
|
||||
|
||||
(cl-defmacro org-ql-expect (ql-args results &key (buffer 'org-ql-test-buffer))
|
||||
"Expand to `expect' test form that expects QL-ARGS to equal RESULTS.
|
||||
|
|
@ -164,8 +164,9 @@ with keyword arg NOW in PLIST."
|
|||
(substring-no-properties (org-get-heading t t)))
|
||||
(defun org-ql-test-org-get-heading ()
|
||||
;; For Org 9.1.9.
|
||||
(substring-no-properties (org-get-heading t t t t))))
|
||||
(substring-no-properties (org-get-heading t t t t)))) )
|
||||
|
||||
(before-each
|
||||
(setq org-ql-test-buffer (org-ql-test-data-buffer "data.org")
|
||||
;; For manual testing:
|
||||
;; org-ql-test-buffer (find-file-noselect "data.org")
|
||||
|
|
@ -202,7 +203,7 @@ with keyword arg NOW in PLIST."
|
|||
(insert "* Heading 1")
|
||||
;; FIXME: `--value-at' does not actually move point, so we do it here.
|
||||
(goto-char (point-min))
|
||||
(expect (org-ql--value-at (point-min) #'org-get-local-tags)
|
||||
(expect (org-ql--value-at (point-min) #'ignore)
|
||||
:to-be nil))))
|
||||
|
||||
(describe "Query pre-processing"
|
||||
|
|
@ -327,11 +328,17 @@ with keyword arg NOW in PLIST."
|
|||
(it "normalizes non-keyword args with a :lang keyword arg to keywords"
|
||||
(expect (org-ql--normalize-query '(src "foo" "bar" :lang "baz"))
|
||||
:to-equal '(src :lang "baz" :regexps '("foo" "bar"))))
|
||||
(it "normalizes zero args without looping"
|
||||
(expect (org-ql--normalize-query '(src))
|
||||
:to-equal '(src)))
|
||||
(it "normalizes all-keyword args without looping"
|
||||
(expect (org-ql--normalize-query '(src :regexps ("foo") :lang "bar"))
|
||||
:to-equal '(src :lang "bar" :regexps '("foo")))
|
||||
(expect (org-ql--normalize-query '(src :regexps ("foo") :lang))
|
||||
:to-equal '(src :regexps '("foo")))))
|
||||
:to-equal '(src :regexps '("foo"))))
|
||||
(it "normalizes just the :lang keyword arg"
|
||||
(expect (org-ql--normalize-query '(src :lang "bar"))
|
||||
:to-equal '(src :lang "bar" :regexps 'nil))))
|
||||
|
||||
(describe "(tags-inherited)"
|
||||
(it "handles 0 arguments"
|
||||
|
|
@ -1136,7 +1143,41 @@ with keyword arg NOW in PLIST."
|
|||
'("/r/emacs")))
|
||||
(org-ql-it "with :description and :target regexp"
|
||||
(org-ql-expect ('(link :description "em.cs" :target "em.cs" :regexp-p t))
|
||||
'("/r/emacs"))))
|
||||
'("/r/emacs")))
|
||||
|
||||
(describe "matches links whose descriptions contain brackets"
|
||||
(before-each
|
||||
(setq org-ql-test-buffer (org-ql-test-data-buffer "data-links.org")))
|
||||
|
||||
(unless (version< org-version "9.3")
|
||||
;; Earlier Org versions don't allow escaped brackets in descriptions.
|
||||
(org-ql-it "without arguments"
|
||||
(org-ql-expect ('(link))
|
||||
'("Alpha")))
|
||||
(org-ql-it "with description-or-target"
|
||||
(org-ql-expect ('(link "phrase"))
|
||||
'("Alpha")))
|
||||
(org-ql-it "with :description"
|
||||
(org-ql-expect ('(link :description "phrase"))
|
||||
'("Alpha")))
|
||||
(org-ql-it "with :target"
|
||||
(org-ql-expect ('(link :target "id:"))
|
||||
'("Alpha")))
|
||||
(org-ql-it "with :description and :target"
|
||||
(org-ql-expect ('(link :description "phrase" :target "id"))
|
||||
'("Alpha")))
|
||||
(org-ql-it "with description-or-target regexp"
|
||||
(org-ql-expect ('(link "id:.*" :regexp-p t))
|
||||
'("Alpha")))
|
||||
(org-ql-it "with :description regexp"
|
||||
(org-ql-expect ('(link :description "phr.se" :regexp-p t))
|
||||
'("Alpha")))
|
||||
(org-ql-it "with :target regexp"
|
||||
(org-ql-expect ('(link :target "id:.*" :regexp-p t))
|
||||
'("Alpha")))
|
||||
(org-ql-it "with :description and :target regexp"
|
||||
(org-ql-expect ('(link :description "phr.se" :target "id:.*" :regexp-p t))
|
||||
'("Alpha"))))))
|
||||
|
||||
(describe "(outline-path)"
|
||||
(org-ql-it "with one argument"
|
||||
|
|
@ -1366,9 +1407,45 @@ with keyword arg NOW in PLIST."
|
|||
(org-ql-expect ('(scheduled :on 0))
|
||||
'("Practice leaping tall buildings in a single bound" "Order a pizza" "Get haircut" "Fix flux capacitor" "Shop for groceries" "Rewrite Emacs in Common Lisp")))))
|
||||
|
||||
;; ;; TODO: Test (src) predicate. That will require modifying test data, which will be a
|
||||
;; ;; significant hassle. Manual testing shows that the predicate appears to work properly.
|
||||
;;
|
||||
(describe "(src)"
|
||||
(before-each
|
||||
;; It would seem preferable to use :var for this, but this seems more reliable.
|
||||
(setq org-ql-test-buffer (org-ql-test-data-buffer "data-src.org")))
|
||||
|
||||
(org-ql-it "without arguments"
|
||||
(org-ql-expect ('(src))
|
||||
'("Alpha" "Bravo")))
|
||||
|
||||
(org-ql-it "with plain argument"
|
||||
;; Finds in first source block in entry.
|
||||
(org-ql-expect ('(src "foo"))
|
||||
'("Alpha"))
|
||||
(org-ql-expect ('(src "bar"))
|
||||
'("Bravo"))
|
||||
(org-ql-expect ('(src "print"))
|
||||
;; Finds in subsequent source block in entry.
|
||||
'("Alpha" "Bravo")))
|
||||
|
||||
(org-ql-it "with :regexps argument"
|
||||
(org-ql-expect ('(src :regexps ("foo")))
|
||||
'("Alpha"))
|
||||
(org-ql-expect ('(src :regexps ("bar")))
|
||||
'("Bravo"))
|
||||
(org-ql-expect ('(src :regexps ("print" "foo")))
|
||||
'("Alpha"))
|
||||
(org-ql-expect ('(src :regexps ("foo" "bar")))
|
||||
nil))
|
||||
|
||||
(org-ql-it "with :lang argument"
|
||||
;; Finds in first source block in entry.
|
||||
(org-ql-expect ('(src :lang "elisp"))
|
||||
'("Alpha" "Bravo"))
|
||||
;; Finds in subsequent source block in entry.
|
||||
(org-ql-expect ('(src :lang "python"))
|
||||
'("Alpha" "Bravo"))
|
||||
(org-ql-expect ('(src :lang "js"))
|
||||
'("Alpha"))))
|
||||
|
||||
(describe "(todo)"
|
||||
|
||||
(org-ql-it "without arguments"
|
||||
|
|
@ -1409,10 +1486,10 @@ with keyword arg NOW in PLIST."
|
|||
(org-ql-it "with file tags"
|
||||
(org-ql-expect ('(tags "food"))
|
||||
'("Fruit" "Blueberry" "Strawberry" "Vegetable" "Broccoli" "Potato")
|
||||
:buffer (org-ql-test-data-buffer "data2.org"))
|
||||
:buffer (org-ql-test-data-buffer "data-file-tags.org"))
|
||||
(org-ql-expect ('(tags "fruit"))
|
||||
'("Fruit" "Blueberry" "Strawberry")
|
||||
:buffer (org-ql-test-data-buffer "data2.org"))))
|
||||
:buffer (org-ql-test-data-buffer "data-file-tags.org"))))
|
||||
|
||||
(describe "(tags-inherited)"
|
||||
|
||||
|
|
@ -1440,10 +1517,10 @@ with keyword arg NOW in PLIST."
|
|||
(org-ql-it "with file tags"
|
||||
(org-ql-expect ('(tags-inherited "food"))
|
||||
'("Fruit" "Blueberry" "Strawberry" "Vegetable" "Broccoli" "Potato")
|
||||
:buffer (org-ql-test-data-buffer "data2.org"))
|
||||
:buffer (org-ql-test-data-buffer "data-file-tags.org"))
|
||||
(org-ql-expect ('(tags-inherited "fruit"))
|
||||
'("Blueberry" "Strawberry")
|
||||
:buffer (org-ql-test-data-buffer "data2.org"))))
|
||||
:buffer (org-ql-test-data-buffer "data-file-tags.org"))))
|
||||
|
||||
(describe "(tags-local)"
|
||||
|
||||
|
|
@ -1470,10 +1547,10 @@ with keyword arg NOW in PLIST."
|
|||
(org-ql-it "with file tags"
|
||||
(org-ql-expect ('(tags-local "food"))
|
||||
nil
|
||||
:buffer (org-ql-test-data-buffer "data2.org"))
|
||||
:buffer (org-ql-test-data-buffer "data-file-tags.org"))
|
||||
(org-ql-expect ('(tags-local "fruit"))
|
||||
'("Fruit")
|
||||
:buffer (org-ql-test-data-buffer "data2.org"))))
|
||||
:buffer (org-ql-test-data-buffer "data-file-tags.org"))))
|
||||
|
||||
(describe "(tags-all), (tags&)"
|
||||
|
||||
|
|
@ -1486,7 +1563,7 @@ with keyword arg NOW in PLIST."
|
|||
(org-ql-it "with file tags"
|
||||
(org-ql-expect ('(tags-all "food" "fruit"))
|
||||
'("Fruit" "Blueberry" "Strawberry")
|
||||
:buffer (org-ql-test-data-buffer "data2.org"))))
|
||||
:buffer (org-ql-test-data-buffer "data-file-tags.org"))))
|
||||
|
||||
(describe "(tags-regexp), (tags*)"
|
||||
|
||||
|
|
@ -1511,10 +1588,10 @@ with keyword arg NOW in PLIST."
|
|||
(org-ql-it "with regexp matching file tags"
|
||||
(org-ql-expect ('(tags-regexp "foo"))
|
||||
'("Fruit" "Blueberry" "Strawberry" "Vegetable" "Broccoli" "Potato")
|
||||
:buffer (org-ql-test-data-buffer "data2.org"))
|
||||
:buffer (org-ql-test-data-buffer "data-file-tags.org"))
|
||||
(org-ql-expect ('(tags* "frui"))
|
||||
'("Fruit" "Blueberry" "Strawberry")
|
||||
:buffer (org-ql-test-data-buffer "data2.org"))))
|
||||
:buffer (org-ql-test-data-buffer "data-file-tags.org"))))
|
||||
|
||||
(describe "(ts)"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue