2024-02-20 ,

org-modeリンクの説明部分でcompletion-at-pointできるようにする

昨日の続き。

昨日の投稿の最後に blog: リンクのpath部分([[blog:<ここ>)を補完するコードを書きましたが、今度は説明(description)部分([[blog:2024-02-20-hello-emacs][<ここ>))を補完するコードを書いてみました。

(2024-02-23追記: 補完関数を定義する一般的な枠組み部分をorg-link-completion.elへ移動しました。それに伴い以下のコード等を書き直しました)

org-elisp-link.el org-link-completion.elの方に必要となる機能をすでに追加してあります。org-link-properties:completion-at-point プロパティはやめて :capf-path:capf-desc を使うようにしました。これによって、path部分と説明部分を補完する関数を別々に指定することが出来ます。

これを使うとブログリンクの説明部分を補完するコードを次のように書くことが出来ます。

(require 'org-link-completion)

(defun my-org-blog-link-capf-desc ()
  "ポイント上のblogリンクの説明部分を補完します。"
  (org-link-completion-parse-let :desc (type path desc-beg desc-end)
    (when-let ((blog (my-blog-from-link-type type)))
      (let* ((title (let* ((dir (plist-get blog :local-dir))
                           (file (expand-file-name (concat path ".org") dir)))
                      (my-org-blog-org-file-title file))))
        (list
         desc-beg desc-end
         (append
          (when title
            (list title
                  (concat title " | " (plist-get blog :title))))
          (list path)))))))

(defun my-org-blog-org-file-title (file)
  "org-modeで記述されているFILEからタイトルを取得します。"
  (when (file-regular-p file)
    (with-temp-buffer
      (insert-file-contents file nil nil 16384) ;; きっと先頭の方にあるでしょう。
      (goto-char (point-min))
      (let ((case-fold-search t))
        (when (re-search-forward
               "^#\\+TITLE: *\\(.*\\)$" nil t)
          (match-string-no-properties 1))))))

(org-link-set-parameters "blog"
                         :capf-desc 'my-org-blog-link-capf-desc)

実際に使うと次のようになります。

blogリンクのdescriptionを補完しているところ
図1: blogリンクのdescriptionを補完しているところ

ファイルの先頭部分にある「#+TITLE:」を見て自動的にタイトルを候補にしてくれます。

blog: リンクに留まらず、普通の file: リンクでも同じ事が出来そうです。.orgファイルへのリンクは同じ方法でタイトルが取得できますから、それを補完候補にすることができます。他にも何らかの方法でタイトルを取得できるファイルへのリンクはそれを補完候補にすることもできるでしょうね。といってもあまり思いつきませんが。pdfとか? http、httpsリンクタイプでhtmlからtitleを取ってくるのはやり過ぎでしょうか?