org-mode 通過elisp實現信息和編輯功能的缺失

各位午夜好,我今天下午寫我的第一個包,裏面涉及到一個和org-capture的olp一樣從最高層的節點一步一步向subheading裏面找進去的(如(org-find-heading-olp-in-buffer “heading1” “heading1.1” “heading1.1.1”).我在各處找了半天,沒有能夠找到好用的函數.

我去看過org-capture的內容,但是看不出來是怎樣實現olp,於是自己用org-mode那些structure naviagate的函數(org-forward-heading-same-level org-next-visible-heading這些)模仿自己找heading的過程寫了一個hermanhel/org-find-headline-in-buffer-olp的函數,在給的olp路徑合法的情況下已經好工作.

之後我發現如果我假設一個heading有subheading,而它沒有的話,這個函數就不能工作,於是又想找一個能夠給出一個heading的所有subheadings的函數,像org-heading-at-point-subheadings的函數,但是又找不到.這個信息無論是在org-heading-component還是org-element裏面都沒有發現有提供.org-ml好像是有關於subheading的函數啦,但是它完全沒有at point的功能.

我覺得我想要找的這兩個函數都是很平常,很經常會有人想要用到的函數吧?畢竟是樹形結構的筆記,想要用hierarchy的方式找heading,或者想要知道一個heading下面有哪些subheading應該是很平常的應用,沒有理由沒有人想到過.所以,有哪位壇友知道是我遺漏了什麼嗎?其實有這些函數在很近很常識的地方?還是有一些理由不實現這些函數呢?

我找到一個outline-has-subheading-p的predicate好看有沒有subheading的,但是也是和我差不多思路,看下一個heading和這個subtree的end的位置大小關係.有outline的這些函數在,implement這些函數應該也不是什麼很麻煩的事…

下面的代码当 point 所在 subtree 有子 node 时, 返回 t, 否则返回 nil

(save-restriction
  (org-narrow-to-subtree)
  (if (caddr (caddr (org-element-parse-buffer 'headline)))
  t
  nil))

以及, 要找到所有子 node, 也可以用 org-element 办到, 只不过似乎你要找的是非常简洁的一两个已经实现的函数, 这个我就不知道有没有了, 我能想到的方法都是要稍微多写两行的.

對,我當時在想應該有org-mode原生的函數,腦子裏想的目標用法大概是像處理json一樣處理orgmode的entry.可能是應為我還不熟悉org-mode和elisp所以覺得再navigate上有點寸步難行www

如果我前兩天有看到你的回帖估計會省很多事www 因為我的場景裡需要的子節點都是leaf,所以最後org-next-visible-headline下去一個一個用org-get-entry拿到了.我想可能大家平時自己寫包的時候都會寫個一個兩個這種函數,但是可能沒有一個專門的大包做這種事情.

喔我的包寫好,dedicated-session,是精力管理功能,不嫌棄是處女作也請多多指摘~~

outline-show-children改写了一下,

(defun my-outline-dump-children (&optional level)
  "Dump all direct subheadings of this heading.
Prefix arg LEVEL is how many levels below the current level should be shown.
Default is enough to cause the following heading to appear."
  (interactive "P")
  (setq level
	(if level (prefix-numeric-value level)
	  (save-excursion
	    (outline-back-to-heading)
	    (let ((start-level (funcall outline-level)))
	      (outline-next-heading)
	      (if (eobp)
		  1
		(max 1 (- (funcall outline-level) start-level)))))))
    (save-excursion
      (outline-back-to-heading)
      (setq level (+ level (funcall outline-level)))
      (outline-map-region
       (lambda ()
	 (if (<= (funcall outline-level) level)
         (message "position=%s heading-text=%s"
                  (point)
                  (string-trim (buffer-substring (line-beginning-position) (line-end-position))))))
       (point)
       (progn (outline-end-of-subtree)
	      (if (eobp) (point-max) (1+ (point)))))))

org-mode找不到的比较底层的api一般都在outline-mode实现,再不济找个差不多的api改写一下也可以了。