如何从目录中的 Org 文件列表中提取标题作为链接

How to extract titles as links from a list of Org files in a directory

我有一个目录下的 org 文件列表:

> org-file1.org
> org-file2.org
> org-file3.org
> ...
> org-fileN.org

我想提取他们的标题(使用 #+title 标签)作为链接如下:

 [[file:org-file1.org][title for org file 1]]
 [[file:org-file2.org][title for org file 2]]
 [[file:org-file3.org][title for org file 3]]
 ...
 [[file:org-fileN.org][title for org file N]]

如何使用 Emacs Lisp 将它们提取为列表?

下面是一些可用于单个文件以获取标题的代码。它是可用于测试的 org 模式文件的一部分。将其保存为 Org 模式文件,在 Emacs 中访问它并在代码块上键入 C-c C-c。更改标题并再次评估代码块。

#+OPTIONS: toc:nil
#+TITLE: This is a very nice title, don't you think?
#+AUTHOR: A.U. Thor

* foo
bar


* Code

#+begin_src elisp :results drawer
  (save-excursion
    (goto-char (point-min))
    (let ((case-fold-search t))
      (search-forward-regexp "^#\+TITLE:")
      (org-element-property :value (org-element-context (org-element-at-point)))))
#+end_src


#+RESULTS:
:results:
This is a very nice title, don't you think?
:end:

代码块转到缓冲区的开头,在一行的开头向前搜索字符串 #+TITLE:(搜索是 case-insensitive),然后使用 org-element 库解析缓冲区,获取上下文并从中获取 :value 属性。

为了使其成为一个完整的解决方案,您必须:

  • 让它更健壮:检查这是一个标题关键字,而不是一些偶然满足匹配的随机垃圾,尽管这不太可能;但安全总比后悔好。

  • 将其包装在一个循环中,该循环对目录中的每个文件执行 find-file 并获取每个文件的标题和 returns 元组列表:(filename title),您可以轻松地使用它来创建链接。

您可以为此使用 org-element-api,但在这种情况下,可能 easier/faster 只是使用 looking-at-p 通过正则表达式进行搜索。要获取一个目录下的所有文件,有directory-files(-recursively)。然后最后你可以使用以下函数实现它:

(defun extract-org-directory-titles-as-list (&optional dir)
  (interactive "D")
  (print
   (delete nil
           (let ((case-fold-search t))
             (mapcar (lambda (f)
                       (when (string-match "org$" f)
                         (with-temp-buffer
                           (insert-file-contents-literally
                            (concat (file-name-as-directory dir) f))
                           (while (and (not (looking-at-p "#\+TITLE:"))
                                       (not (eobp)))
                             (forward-line))
                           (when (not (eobp))
                             (cons f (substring (thing-at-point 'line) 9 -1))))))
                     (directory-files dir))))))

(defun insert-directory-org-file-titles (&optional dir)
  (interactive "D")
  (let ((files-titles (extract-org-directory-titles-as-list dir)))
    (dolist (ft files-titles)
      (insert (concat "[[file:" (car ft)"][" (cdr ft) "]]\n")))))

如果您更喜欢将它作为一个 (a) 列表,就像您问的那样,那么只需使用 extract-org-directory-titles-as-list.