画图测试
下载的 drawio 的 deb 包,命令名字是 drawio ,而插件用的是 draw.io ,做一个软链接,可以解决 org-drawio-open 的调用。插件自己的代码是在 win 上使用的,不太适合 gnu/linux 环境,显然没有进行过真正的适配和调试,有一些问题。做一些修改,现在适合在 linux 上面使用了。
https://github.com/kimim/org-drawio
有错误在 emacs 下如何调试
M-x edebug-defun 单步执行 emacs 函数。
M-x toggle-debug-on-error emacs 出错的时候进入 debug 。
我的方案
高质量的插件是需要大量测试覆盖的,开源的东西没有有那么多精力把所有的细节都调整好,很多时候都是用户理解思路并做一些小的修改。add 函数是为了创建 drawio 的源文件并刷新。open 是为了调用外部的 drawio 应用。但是这两个函数都不适合 linux 下的环境。emacs 使用者的环境可以说千奇百怪。
下面对函数做一下修改:
(use-package org-drawio
:commands (org-drawio-add
org-drawio-open)
:custom ((org-drawio-input-dir "./draws")
(org-drawio-output-dir "./images")
(org-drawio-output-page "0")
;; set to t, if you want to crop the image.
(org-drawio-crop nil)))
(require 'org-drawio)
(defun lj/org-drawio-new-if-not-exist (dir file)
"If a FILE or DIR not exsit, create an empty drawio diagram."
(let ((path (concat dir "/" file)))
(when (not (file-exists-p path))
(when (not (file-exists-p dir))
(make-directory dir))
;;(make-empty-file file dir)
(write-region
"<mxfile host=\"Electron\" agent=\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.1.0 Chrome/120.0.6099.109 Electron/28.1.0 Safari/537.36\" version=\"24.1.0\" type=\"device\">
<diagram name=\"第 1 页\" >
<mxGraphModel dx=\"2074\" dy=\"1203\" grid=\"1\" gridSize=\"10\" guides=\"1\" tooltips=\"1\" connect=\"1\" arrows=\"1\" fold=\"1\" page=\"1\" pageScale=\"1\" pageWidth=\"827\" pageHeight=\"583\" math=\"0\" shadow=\"0\">
<root>
<mxCell id=\"0\" />
<mxCell id=\"1\" parent=\"0\" />
</root>
</mxGraphModel>
</diagram>
</mxfile>"
nil path)
)))
(defun lj/org-drawio-open ()
"Open .drawio file in current line of #+drawio keyword."
(interactive)
(let* ((keyword-plist (org-drawio-keyword-string-to-plist))
(dio-input (file-name-with-extension
(plist-get keyword-plist :input) "drawio"))
(dio-input-dir (or (plist-get keyword-plist :input-dir)
org-drawio-input-dir))
(_ (lj/org-drawio-new-if-not-exist dio-input-dir dio-input))
(path (concat dio-input-dir "/" dio-input)))
(cond
;; ensure that draw.io.exe is in execute PATH
((string-equal system-type "windows-nt")
(if (fboundp 'w32-shell-execute)
(w32-shell-execute "open" path)))
;; TODO: need some test for other systems
((string-equal system-type "darwin")
(start-process "" nil "open" "-a"
(or org-drawio-command-drawio
"draw.io")
path))
((string-equal system-type "gnu/linux")
(progn
(set 'cmd0 (concat "drawio " path))
(message cmd0)
(my-sh-send-command cmd0)
)
;;(start-process "" nil "xdg-open"
;; (or org-drawio-command-drawio
;; "draw.io")
;; path)
)
((string-equal system-type "cygwin")
(start-process "" nil "xdg-open" (or org-drawio-command-drawio
"draw.io")
path)))))
;;;;;
(defun lj/org-drawio-add ()
"Convert .drawio file to .svg file, and insert svg to orgmode."
(interactive)
(save-excursion
(let* ((keyword-plist (org-drawio-keyword-string-to-plist))
(dio-input-dir (or (plist-get keyword-plist :input-dir)
org-drawio-input-dir))
(dio-input (file-name-with-extension
(plist-get keyword-plist :input) "drawio"))
(_ (lj/org-drawio-new-if-not-exist dio-input-dir dio-input))
(dio-page (or (plist-get keyword-plist :page)
org-drawio-page))
(dio-output-dir (or (plist-get keyword-plist :output-dir)
org-drawio-output-dir))
(dio-output (plist-get keyword-plist :output))
;; if output file specified, use it, otherwise append page to it.
(dio-output-svg (if dio-output
(file-name-with-extension dio-output "svg")
(file-name-with-extension
(concat (file-name-sans-extension dio-input)
"-" dio-page)
"svg")))
(dio-output-pdf (file-name-with-extension dio-output-svg "pdf"))
;; create output dir if non exist
(_ (when (not (file-exists-p dio-output-dir))
(make-directory dio-output-dir)))
(script (format "%s -x %s%s/%s -p %s -o %s/%s >/dev/null 2>&1 && \
%s %s/%s %s/%s >/dev/null 2>&1"
(file-truename
(executable-find (or org-drawio-command-drawio "draw.io")))
(if org-drawio-crop "--crop " "")
(shell-quote-argument dio-input-dir)
(shell-quote-argument dio-input) dio-page
(shell-quote-argument dio-output-dir)
(shell-quote-argument dio-output-pdf)
(or org-drawio-command-pdf2svg
"pdf2svg")
(shell-quote-argument dio-output-dir)
(shell-quote-argument dio-output-pdf)
(shell-quote-argument dio-output-dir)
(shell-quote-argument dio-output-svg)))
;; special handling, home path should not be backquoted
(script (string-replace "\\~" "~" script)))
;; skip #+caption, #+name of image
(if (org-next-line-empty-p)
(progn (end-of-line) (insert-char ?\n))
(while (string-prefix-p "#+" (org-current-line-string))
(forward-line)))
;; convert from drawio to svg asynchronously, thanks to twiddling
(let ((process (start-process-shell-command "org-drawio" nil script)))
(set-process-sentinel
process `(lambda (process event)
(message event)
(when (string-match-p "finished" event)
;; trash pdf file
(delete-file ,(concat dio-output-dir "/" dio-output-pdf) t)
;; refresh image
(org-redisplay-inline-images)))))
(when (string-prefix-p "[[" (org-current-line-string))
;; when it is image link
(kill-whole-line 0))
(insert "[[file:" dio-output-dir "/" dio-output-svg "]]"))))
emacs 的画图
之前尝试过 emacs 用 tikz 来画图,比较麻烦。适合没事的时候边学边练,有了足够的熟练度之后才能享受到如臂使指。而 drawio 是一个上手难度极低,而且功能也足够强的一个工具。做为一个程序员,称手的工具很重要,但是更重要的是内功。
练好内功,学习一些更有价值的东西,切记。