Org内联条目
概述
org-inline-entry, 一个收集内联条目的工具。
内联条目的定义
内联条目 (inline entry), 一种嵌于 Org段落 中的 Org entry, 其实现原理是将表示 Org entry 的 sexp 与 Org export-snippet 相结合:
@@entry:ENTRY-SEXP@@
或简写为
@@-:ENTRY-SEXP@@
其中,表示 Org entry 的 ENTRY-SEXP 定义为:
ENTRY-SEXP := ITEM
           := (ITEM PROPERTIES)
           := (ITEM CONTENT)
           := (ITEM PROPERTIES CONTENT)
PROPERTIES := (P V P V ...)
P|V        := STRING|SYMBOL ...
CONTENT    := STRING|SYMBOL ...
另外, @@-:ENTRY-SEXP@@ 后跟的所有非内联条目的 Org元素 也属于内联条目的内容,即:
@@-:(E1 这是一个内联条目。)@@这里也属于 E1 的内容。@@-:(E2 这是另一个内联条目。)@@这里也属于 E2 的内容。@@-:(E3 这又是一个内联条目。)@@这里也属于 E3 的内容。@@-:(E4 这还是一个内联条目。)@@这里也属于 E4 的内容。
一些 Org inline entry 所对应的 Org entry 的例子:
(!let ((+ (lambda (&rest s)
            (string-join s "\n")))
       (ie->e ;; inline entry 转 entry
        (lambda (s)
          (org-inline-entry
           'interpret-as-entry
           (with-temp-buffer
             (org-mode)
             (save-excursion
               (insert s))
             (org-inline-entry
              'at-point)))))
       ie&e)
 ;; Org inline entry 与 Org entry 的对应
 (!def ie&e
  `(;; test case 1
    (,(+ "@@entry:TITLE@@")
     ,(+ "* TITLE"))
    ;; test case 2
    (,(+ "@@entry:T@@CONTENT")
     ,(+ "* T"
         "CONTENT"))
    ;; test case 3
    (,(+ "@@-:(T C1 C2)@@C3 C4")
     ,(+ "* T"
         "C1C2C3 C4"))
    ;; test case 4
    (,(+ "@@-:(T(P1 V1 P2 V2)C1)@@C2")
     ,(+ "* T"
         ":PROPERTIES:"
         ":P1: V1"
         ":P2: V2"
         ":END:"
         "C1C2"))
    ;; test case 4
    (,(+ "@@-:(T(TAGS a:b:c)1 2)@@3")
     ,(+ "* T :a:b:c:"
         "123"))
    ;; test case 5
    (,(+ "@@-::a:b:c:@@")
     ,(+ "* :a:b:c:"))))
 (seq-every-p
  #'identity
  (seq-mapn
   #'equal
   (seq-map ie->e (seq-map #'car ie&e))
   (seq-map #'cadr ie&e))))
;; => t
衍生应用:内联标签
通过 org-inline-entry, 你可以结合 Org Match String 提取、收集匹配到的文本片段,以实现某种“内联标签”功能。比如给定如下文本:
@@-::t1:@@被 t1 标记的文本。@@-::t2:@@被 t2 标记的文本。@@-::t3:@@被 t3 标记的文本。@@-::t4:@@被 t4 标记的文本。@@-:@@[2025-01-01 Wed]时戳文本。
通过如下代码提取“被 t2 标记”或“带时间戳”的文本片段:
(let ((m "t2|TIMESTAMP_IA={2025-01}"))
  (with-temp-buffer
    (org-mode)
    (insert
     "@@-::t1:@@被 t1 标记的文本。"
     "@@-::t2:@@被 t2 标记的文本。"
     "@@-::t3:@@被 t3 标记的文本。"
     "@@-::t4:@@被 t3 标记的文本。"
     "@@-:@@[2025-01-01 Wed]时戳文本。")
    (org-element-map
        (org-element-parse-buffer)
        '(export-snippet)
      (lambda (e)
        (org-with-point-at
            (org-element-begin e)
          (and-let*
              ((ie (org-inline-entry
                    'match? m)))
            (substring-no-properties
             (string-trim
              (org-element-interpret-data
               ie)))))))))
;; =>
;; ("@@-::t2:@@被 t2 标记的文本。"
;;  "@@-:@@[2025-01-01 Wed]时戳文本。")