这两天变成了重度Typst用户,因为在搞点文学编程,就做了一个导出代码块的函数:
(defvar typst--initialized-files nil
"List of files that have been initialized for the current tangle operation.")
(defun typst--initialize-file (path)
"Initialize a temporary file for the PATH and return the temp file's path."
(let ((temp-path (make-temp-file "typst" nil ".tmp")))
(push (cons temp-path path) typst--initialized-files)
temp-path))
(defun typst--tangle (node)
"Recursively process each raw_blck NODE in the treesit parsed tree."
(if (equal (treesit-node-type node) "raw_blck")
(let* ((beg (treesit-node-start node))
(path-line (treesit-node-text (treesit-node-on (- beg 2) (- beg 1))))
(original-path (when (> (length path-line) 2) (string-trim (substring path-line 2))))
(temp-path (when original-path
(or (car (rassoc original-path typst--initialized-files))
(typst--initialize-file original-path))))
(content-node (car (treesit-filter-child node (lambda (n) (equal (treesit-node-type n) "blob")))))
(content (when content-node (string-trim (treesit-node-text content-node)))))
(when temp-path
(append-to-file content nil temp-path)
(append-to-file "\n" nil temp-path)
(message "Tangled to temp file: %s." temp-path)))
(dolist (child (treesit-node-children node))
(typst--tangle child))))
(defun typst-tangle ()
"Tangle the current typst file."
(interactive)
(setq typst--initialized-files nil)
(let ((root (treesit-buffer-root-node)))
(typst--tangle root)
(dolist (pair typst--initialized-files)
(let ((temp-path (car pair))
(original-path (cdr pair)))
(rename-file temp-path original-path t)
(message "Moved %s to %s" temp-path original-path)))
(setq typst--initialized-files nil)))
使用方法:
-
需要treesit和typst-ts-mode
-
比如typst文件内容是 (忽略那个反斜杆…)
...
// xx.py
\```python
print(1)
print(2)
\```
...
运行 M-x typst-tangle
,会将python的code block里面的两个print先导出到tmp文件,再移动到xx.py
里面
注意
因为刚写好,自用。暂时不确定会不会有什么特别的问题。