org-ql 讨论帖

org-ql 非常强大,这两天专门学习了一下它的手册,优点很多。 检索条件全面,可以按照时间、属性、标签来检索。 检索结果可以保存为 org-mode 格式的链接,方便随时调用。 还可以和 dynamic block 结合,将 heading 整理成列表形式,并且可以进行更新。

以下是我整理的部分手册内容:

definition

针对 org-mode 的 query 语法。

project url

https://github.com/alphapapa/org-ql

How to use

安装org-ql

官方推荐用 quelpa 来安装,如果不使用它的话,直接用 straight 的方式也可以。

用法

命令

org-ql 提供 3 种类型的命令,不同命令支持 non-sexp,和 sexp 两种类型的指令:

  1. 直接跳转到对应的内容

    1. org-ql-find

      【仅支持 non-sexp 类型指令】

      1. org-ql-find 在当前打开的 buffer 里进行检索
      2. org-ql-find-in-agenda 在预设好的 (org-agenda-files) 里进行检索
      3. org-ql-find-in-org-directory 在 org-directory 里的文件进行检索
  2. 检索结果将展示成类似 agenda 的视图

    1. org-ql-search

      【支持 non-sexp 和 sexp 两种类型的指令】 该指令提供如下变量:

      1. BUFFERS-FILES

        检索一系列 buffer 或 org 文件

        • buffer 从当前所有打开的 buffer 中进行检索
        • all 检 索所有的 Org 文件类型的 buffer
        • agenda 在 (org-agenda-files) 指定的文件中检索
      2. GROUPS

        从 org-super-agenda-groups 定义的分类中进行检索

      3. NARROW

        :question:When non-nil, don’t widen buffers before searching. Interactively, with prefix, leave narrowed.

      4. SORT

        一个,或一系列 org-ql 用于排序的指令,比如 datepriority

      5. Bindiings 在结果展示 buffer 里使用的键盘快捷键

        • r 当调整了搜索的设置之后,刷新展示的结果
        • v 展示弹出窗口,类似 popups
        • C-x C-s 将检索结果页保存为 org-ql-views
    2. org-ql-views

      选择储存在 org-gl-views 里的视图,并展示出来

      1. Bindings

        • gr 刷新
        • v 以 popup 的方式进行展示
        • C-c C-s 将检索的视图,保存到 org-ql-views
    3. org-ql-view-sidebar

      org-ql-views 的结果以侧边栏的方式展示出来 可用 RETmouse-1 在当前的光标位置展示特定的结果 按下 c 对光标位置展示的结果进行定义

    4. org-ql-view-recent-items

      展示 FILES 里,以 DAYS 的范围内的检索结果。 DAYS 通过 TYPE 参数进行调整,包括 tsts-activets-inactiveclockedcloseddeadlineplannning , =scheduled =

      FILES 默认是 org-agenda-files 指定的文件

  3. 检索结果以树状列表的形式在新开的 buffer 里展示

    1. org-ql-sparse-tree

      Arguments: (query &key keep-previous (buffer (current-buffer)))

      BUFFERS 里检索特定的 QUERY 条件,并以树状列表进行展示

QUERY 检索语法

  1. 原理

    An org-ql query is a Lisp expression which may contain arbitrary expressions, as well as calling certain built-in predicates. It is byte-compiled into a predicate function which is tested with point on each heading in an Org buffer; when it returns non-nil, the heading matches the query. When possible, certain built-in predicates are optimized away to whole-buffer regular expression searches, which are much faster to search for than testing the predicate on each heading.

    • 检索条件采用 < , <= , >= , = 进行比较
  2. Non-sexp 检索语法

    Sexp syntax Non-sexp syntax
    (todo) todo:
    (todo "SOMEDAY") todo:SOMEDAY
    (todo "SOMEDAY" "WAITING") todo:SOMEDAY,WAITING
    (ts :on today) ts:on=today
    (ts-active :from "2017-01-01" :to "2018-01-01") ts-active:from=2017-01-01,to=2018-01-01
    (clocked :on -1) clocked:on=-1
    (heading "quoted phrase" "word") heading:"quoted phrase",word
    (and (tags "book" "books") (priority "A")) tags:book,books priority:A
    (src :lang "elisp" :regexps ("defun")) src:defun,lang=elisp or src:lang=elisp,defun
    (and (tags "space") (not (regexp "moon"))) tags:space !moon
    (priority >= B) priority:A,B
  3. General predicates 一般检索条件

    1. category (&optional categories)
    2. done
    3. effort (&optional effort-or-comparator effort)
    4. habit
    5. heading (&rest strings)
      • 缩写 h
    6. heading-regexp (&rest regexps)
      • 缩写 h*
    7. level (level-or-comparator &optional level)
    8. link (&optional description-or-target &key description target regexp-p)
    9. outline-path (&rest strings)
      • 缩写 olp
    10. outline-path-segment (&rest strings)
      • 缩写 olps
    11. path (&rest regexps)
    12. priority (&rest args)
    13. property (property &optional value)
    14. regexp (&rest regexps)
    15. rifle (&rest strings)
    16. src (&key lang regexps)
    17. tags (&optional tags)
    18. tags-inherited (&optional tags)
    19. tags-local (&optional tags)
    20. tags-all (tags)
    21. tags-regexp (&rest regexps)
    22. todo (&optional keywords)
  4. 根据 headling 的层级进行检索

    • ancestors (&optional query) 一级
    • children (&optional query) 二级
    • descendants (&optional query)
    • parent (&optional query)
  5. 根据未来日期/时间条件进行检索

    检索语句:

    • :from 从当前的 timestamp 开始之后
    • :to 从当前的 timestamp 开始之前
    • :on 仅检索 timestamp 当天
    • :with-time 检索两个 timestamp 期间
    1. 特定时间条件的

      • ts 选取带 timestamp 的 entry
      • ts-activets-a 仅匹配仍在活跃的,带 timestamp 的 entry
      • ts-inactivets-i 仅匹配非活跃的……
    2. 面向历史的

      • clocked 检索结束计时的 entry
      • closed 检索已结束的 entry
    3. 面向未来的

      • deadline 包含 deadline 的 entry,除非提供了特定时间条件
      • planning 包含了 planing 的 timestamp 比如(deadline,scheduled 或 closed)
      • scheduled 包含了 scheduled 的 entry

Functions / Macros

  1. Agenda-like views

    1. org-ql-block

      需要与 org-agenda-custom-commands 进行结合 例子:

      (setq org-agenda-custom-commands
      	  '(("ces" "Custom: Agenda and Emacs SOMEDAY [#A] items"
      		 ((org-ql-block '(and (todo "SOMEDAY")
      							  (tags "Emacs")
      							  (priority "A"))
      						((org-ql-block-header "SOMEDAY :Emacs: High-priority")))
      		  (agenda)))))
      
  2. Listing / acting-on results

    1. org-ql-select

      (buffers-or-files query &key action narrow sort) BUFFERS-OR-FILES is a one or a list of files and/or buffers.

      QUERY is an org-ql query sexp (quoted, since this is a function).

      ACTION is a function which is called on each matching entry with point at the beginning of its heading. It may be:

      element or nil: Equivalent to org-element-headline-parser.

      element-with-markers: Equivalent to calling org-element-headline-parser, with markers added using org-ql–add-markers. Suitable for formatting with org-ql-agenda–format-element, allowing insertion into an Org Agenda-like buffer.

      A sexp, which will be byte-compiled into a lambda function.

      A function symbol.

      If NARROW is non-nil, buffers are not widened (the default is to widen and search the entire buffer).

      SORT is either nil, in which case items are not sorted; or one or a list of defined org-ql sorting methods (date, deadline, scheduled, closed, todo, priority, or random); or a user-defined comparator function that accepts two items as arguments and returns nil or non-nil.

      例子:

        ;; Return list of to-do headings in inbox file with tags and to-do keywords:
      (org-ql-select "~/org/inbox.org"
        '(todo)
        :action #'org-get-heading)
      ;; => ("TODO Practice leaping tall buildings in a single bound  :personal:" ...)
      
      ;; Without tags and to-do keywords:
      (org-ql-select "~/org/inbox.org"
        '(todo)
        :action '(org-get-heading t t))
      ;; => ("Practice leaping tall buildings in a single bound" ...)
      
      ;; Return WAITING heading elements in agenda files:
      (org-ql-select (org-agenda-files)
        '(todo "WAITING")
        :action 'element)
      ;; => ((headline (:raw-value "Visit the moon" ...) ...) ...)
      
      ;; Since `element' is the default for ACTION, it may be omitted:
      (org-ql-select (org-agenda-files)
        '(todo "WAITING"))
      ;; => ((headline (:raw-value "Visit the moon" ...) ...) ...)
      
    2. org-ql-query

      (&key (select 'element-with-markers) from where order-by narrow)

      org-ql-select 类似,但它的检索语法和 SQL 类似

      SELECT corresponds to the org-ql-select argument ACTION.

      FROM corresponds to the org-ql-select argument BUFFERS-OR-FILES.

      WHERE corresponds to the org-ql-select argument QUERY.

      ORDER-BY corresponds to the org-ql-select argument SORT, which see.

      NARROW corresponds to the org-ql-select argument NARROW.

  3. Custom predicates 自定义检索条件

    org-ql/defpred.org

    1. org-ql-defpred

      (name args docstring &key body preambles normalizers)

      org-ql–predicate-NAME. NAME may be a symbol or a list of symbols: if a list, the first is used as NAME and the rest are aliases. A function is only created for NAME, not for aliases, so a normalizer should be used to replace aliases with NAME in queries (keep reading).

      ARGS is a cl-defun-style argument list. DOCSTRING is the function’s docstring.

      BODY is the body of the predicate. It will be evaluated with point on the beginning of an Org heading and should return non-nil if the heading’s entry is a match.

      PREAMBLES and NORMALIZERS are lists of pcase forms matched against Org QL query sexps. They are spliced into pcase forms in the definitions of the functions org-ql–query-preamble and org-ql–normalize-query, which see. Those functions are redefined when this macro is expanded, unless variable org-ql-defpred-defer is non-nil, in which case those functions should be redefined manually after defining predicates by calling org-ql–define-query-preamble-fn and org-ql–define-normalize-query-fn.

      NORMALIZERS are used to normalize query expressions to standard forms. For example, when the predicate has aliases, the aliases should be replaced with predicate names using a normalizer. Also, predicate arguments may be put into a more optimal form so that the predicate has less work to do at query time. NOTE: Normalizers are applied to a query repeatedly until the query is fully normalized, so normalizers should be carefully written to avoid infinite loops.

      PREAMBLES refer to regular expressions which may be used to search through a buffer directly to a potential match rather than testing the predicate body on each heading. (Naming things is hard.) In each pcase form in PREAMBLES, the pcase expression (not the pattern) should be a plist with the following keys, each value of which should be an expression which may refer to variables bound in the pattern:

      :regexp Regular expression which searches directly to a potential match.

      :case-fold Bound to case-fold-search around the regexp search.

      :query Expression which should replace the query expression, or query if it should not be changed (e.g. if the regexp is insufficient to determine whether a heading matches, in which case the predicate’s body needs to be tested on the heading). If the regexp guarantees a match, this may be simply t, leaving the query expression with no work to do, which improves performance.

      For convenience, within the pcase patterns, the symbol predicate-names is a special form which is replaced with a pattern matching any of the predicate’s name and aliases. For example, if NAME were:

      (heading h)

      Then if NORMALIZERS were:

      ((`(,predicate-names . ,args) `(heading ,@args)))

      It would be expanded to:

      ((`(,(or 'heading 'h) . ,args) `(heading ,@args)))

Dynamic block

org-ql 可以和 org-mode 内置的 Daynamic Blocks 功能搭配使用。

:query An Org QL query expression in either sexp or non-sexp form.

:columns A list of columns, including heading, todo, property, priority, deadline, scheduled, closed. Each column may also be specified as a list with the second element being a header string. For example, to abbreviate the priority column: (priority “P”). For certain columns, like property, arguments may be passed by specifying the column type itself as a list. For example, to display a column showing the values of a property named milestone, with the header being abbreviated to M: ((property “milestone”) “M”).

:sort One or a list of Org QL sorting methods (see org-ql-select).

:take Optionally take a number of results from the front (a positive number) or the end (a negative number) of the results.

:ts-format Optional format string used to format timestamp-based columns.

例子:

#+BEGIN: org-ql :query "todo: priority:A,B" :columns (todo (priority "P") ((property "agenda-group") "Group") deadline heading) :sort (deadline priority) :take 7 :ts-format "%Y-%m-%d %H:%M"
| Todo | P | Group | Deadline         | Heading                               |
|------+---+-------+------------------+---------------------------------------|
| TODO | A |       | 2017-07-07 00:00 | Take over the world                   |
| TODO | B |       | 2017-07-10 00:00 | Renew membership in supervillain club |
| TODO | A | plans | 2017-07-15 00:00 | Take over the universe                |
| TODO | B |       | 2017-07-21 00:00 | Internet                              |
| TODO | A | bills | 2017-08-01 00:00 | Spaceship lease                       |
| TODO | A |       |                  | Skype with president of Antarctica    |
| TODO | B |       |                  | Take over Mars                        |
#+END:

Links

支持将 org-ql 与 org-mode 的 links 结合,在点击之后,直接展示 org-ql 检索的结果 你可以将当前 org-ql 检索结果的视图用 org-store-link 命令储存起来,然后再用 org-insert-link 将保存的结果取出,并记录在你想记录的位置

例子:

[[org-ql-search:todo:NEXT priority:A]]
[[org-ql-search:(and (todo "NEXT") (priority "A"))]]

Tips

org-ql view 的 buffer 可以通过 emacs 的 bookmark 命令标记为书签

example

8 个赞

初步上手 org-ql 建议使用 org-ql-serach 命令,因为它提供了交互式命令菜单,在一开始尝试 org-ql 的功能时会比较舒服,降低上手的门槛。

在用 org-ql-search 检索了相关内容之后,这些检索条件可以保存到 org-ql-view 中,下一次调用,可以直接输入 =M-x= org-ql-view,直接唤出,很方便。

org-ql有类似于table的那种嵌入org文件里随时更新的视图吗

还未测试,但从手册里看到,是有类似的,你可以直接搜索本网页「dynamic block」看看。

这是手册上的例子:

实际上,org-mode 的 dynamic block 直接就可以满足你的要求。直接按 C-c C-c 就可以更新。 而且 dynamic block 不必放在任意 org 文件里。

#+title: 书籍阅读记录
#+filetags: :bookreading:
#+COLUMNS: %25ITEM(书名) %10AUTHOR(Author) %10CATEGORY(Category) %15ADDED(Added) %15STAR(Star) %50NOTELINK(Notelink)

#+BEGIN: columnview :hlines 1 :id "file:~/我的坚果云/org-roam/book/book20220704152021-书籍阅读记录.org" :skip-empty-rows t
| 书名                           | Author              | Category | Added            | Star       | Notelink                       |
|--------------------------------+---------------------+----------+------------------+------------+--------------------------------|
| 岩田先生:企业家传奇社长如是说 | HOBO 日刊 ITOI 新闻 | 企业家   | <2022-07-04 Mon> | ⭐️⭐️⭐️⭐️⭐️ | [[id:E23B33EF-C3A7-45DC-9A7A-43E5CBBA2C47][岩田先生:企业家传奇社长如是说]] |
#+END:

orgorg-roam 分属不同的目录,org 分管 agendaorg-roam 分管笔记,如须 org-ql 只在 org-roam 笔记里查找,要怎么设置?

感谢。

你定义一个 load-path 看看行不行。简单来讲,就是你定义一个 org-ql 去检索的文件夹。

一个参考例子:

这篇文章里的代码:

 (org-ql-query
    :select 'element-with-markers
    :from '("~/commonplace/gift-economies-build-community.org")
     :where '(and (heading "Epistemic status"))

:joy:这效果很好呀,是时候重新拿起org-mode做任务管理了