特性:动态 Block 展开
背景
当前, elisp docstring 可以通过 drawer 导入代码中,然 drawer 无类似 src-block 的 header-args, 而 dynamic block 有 arguments, 故新增此特性。至此,headline, src-block, dynamic-block 都可实现某种共通的 proerties 机制。
实现
#+name: 2025-08-17-16-48
#+begin_src emacs-lisp :eval no
(!let ((expand (make-symbol "expand-dynamic-block")))
(!def expand
(lambda (ele conf)
;; conf 输入输出
;; 输入: :link.
;; 输出: :block-name, :failed, :err-msg.
(let* ((link (plist-get conf :link))
(beg (org-element-contents-begin ele))
(end (org-element-contents-end ele))
;; org-element parser 与 org.el 中
;; 的不一致,导致解析失败,所以有了这段
;; workground 代码。
(org-element-dynamic-block-open-re
org-dblock-start-re)
(ele
(save-excursion
(save-match-data
(re-search-forward
org-dblock-start-re nil t)
(forward-line 0)
(org-element-dynamic-block-parser
nil nil))))
(args (eval
(read
(format
"'(%s)" (org-element-property
:arguments ele)))))
(block-name
(org-element-property :block-name ele)))
(cond
;; 如果块参数 `:expand' 存在,且其 sexp 求值
;; 为 nil 或 "no",
((and
(plist-member args :expand)
(member (eval (plist-get args :expand))
'(nil "no")))
;; 表明该块在当前环境下拒绝展开。
(plist-put conf :failed t)
(plist-put conf :err-msg
(format "ignore %s." link))
"")
(t
;; FIXME: 等待一次重构。25/9/13
(plist-put
conf :escape (eval (plist-get args :escape)))
(plist-put conf :block-name block-name)
(setq ele (string-trim
(buffer-substring beg end)))
(with-temp-buffer
(org-mode)
(save-excursion
(insert
"#+begin_src C :noweb yes\n"
ele
"\n#+end_src"))
(org-babel-expand-noweb-references
(org-babel-get-src-block-info))))))))
(org-noweb-expand-link
'set-expander 'dynamic-block expand
'expand-dynamic-block))
#+end_src
新构建目标:
由于先前版本提供了新增特性的接口,于此在上版本尾部加入 动态 Block 展开 特性。若整体结构中的 entry 符号更名为 org-noweb-expand-link, 此特性——动态 Block 展开——才能纳入特性集中,但历史版本的变更涉及大重构,此贴暂不处理。
#+name: 2025-08-17-16-45
#+header: :tangle (org-sbe "2025-07-26-11-30" ":eval yes")
#+header: :eval (org-sbe "2025-07-26-11-30" ":eval yes" (ok \"yes\"))
#+begin_src emacs-lisp :noweb yes :results silent :lexical t
<<@([[id:org-noweb-expand-link::org-noweb-expand-link]])>>
<<@([[id:org-noweb-expand-link::feature:expand-dynamic-block]])>>
#+end_src
映射表:
#+name: 2025-08-17-16-43
#+begin_src emacs-lisp :eval no
(org-id-remap
"map-table-base"
"https://emacs-china.org/t/org-tangle/29663::2025-08-03-16-38")
#+end_src
#+name: 2025-08-17-16-42
#+header: :depend (org-sbe "2025-08-17-16-43" ":eval yes")
#+begin_src emacs-lisp :eval no
<<@([[id:map-table-base]])>>
nil nil
"org-noweb-expand-link"
"https://emacs-china.org/t/org-tangle/29663::2025-08-17-16-45"
"org-noweb-expand-link::feature:expand-dynamic-block"
"https://emacs-china.org/t/org-tangle/29663::2025-08-17-16-48"
#+end_src
构建入口:
#+name: 2025-08-17-16-44
#+header: :var tangle=(ignore) load=(ignore)
#+begin_src emacs-lisp :results silent :noweb yes :eval no
(org-id-remap 'reset)
(org-id-remap
"build-script"
"https://emacs-china.org/t/org-id-remap/29814::2025-08-03-11-27"
"build-target"
"https://emacs-china.org/t/org-tangle/29663::2025-08-17-16-45"
"map-table"
"https://emacs-china.org/t/org-tangle/29663::2025-08-17-16-42")
(org-id-remap t)
(org-exec "[[id:build-script]]" nil
:eval "yes"
'target "[[id:build-target]]"
'map-table ''("[[id:map-table]]")
'tangle (or tangle "~/org/org-noweb-expand-link.el")
'load (or load "yes"))
#+end_src