2024-02-25 ,

org-link-completion.elによるリンクの補完とorg-modeのリンク構文

先日から作っているorg-link-completion.elですが、一応org-modeのリンク表記の内部のうち、ほとんど全ての場所で補完ができるようになりました。

misohena/org-link-completion: Complete the link type, path and description part of links at point in org-mode buffer.

次の場所で補完できるはずです。

  • [[ link-type:
  • [[ searchtarget
  • [[# custom-id
  • [[# custom-id ][ description
  • [[* heading
  • [[* heading ][ description
  • [[( coderef)
  • [[(coderef)][ description
  • [[ Search Target
  • [[ Search Target ][ description
  • [[ /dir/file
  • [[ ./dir/file
  • [[ /dir/file
  • [[ c:/dir/file
  • [[ /dir/file ][ description (上記 / ./ / c:/ を含む)
  • [[file: file
  • [[file+sys: file
  • [[file+emacs: file
  • [[file: file ][ description (上記 file+sys: file+emacs: を含む)
  • [[ unknown-type: path
  • [[ unknown-type: path ][ description

補完できないところは[と[、]と[、]と]の間くらいじゃないでしょうか。

そもそもorg-modeでどんなリンクが書けるのかというのがあやふやだったんですよね。仕方ないのでちゃんとおさらいしました。

org-modeのリンクで一番重要なコンセプトは、URLや(ディレクトリを含む)ファイルパスのように見えるもの以外は内部リンクだということでしょう。つまり、 file: とか https: とか付いているものや ./screenshot.png のようなもの以外は現在のorg-modeバッファ内へのリンクです。

ただ、私は解析の都合上 file: とか https: のようなリンクタイプが付いているかそうでないかによって大きく二通りに分けました。その上で、付いていないもののうち、ファイルパスは外部リンク、そうでないものは内部リンクということになります。

それを踏まえて全ての形式を列挙すると次のようなります。

  • リンクタイプ無し
    • 内部リンク
      • [[ # カスタムID ]
      • [[ * 見出し ]
      • [[ ( コード行参照 ) ]
      • [[ 色々検索 ]
    • 外部リンク
      • ディレクトリ始まりファイルパス

        • 相対パス
          • [[ ./ ファイルパス
          • [[ ../ ファイルパス (追記:漏れていたので追加)
        • 絶対パス

          • [[ / ファイルパス
          • [[ ~/ ファイルパス
          • [[ ~ ユーザ名 ファイルパス (追記:漏れていたので追加)
          • [[ \ ファイルパス (MS-Win) (追記:漏れていたので追加)
          • [[ ドライブレター : /または\ ファイルパス (MS-Win) (追記:コロンの後には/か\が必要)

          (追記:絶対パスはfile-name-absolute-pがtを返す形式でなければならない。つまり ~ユーザ名 なんてのも許容される(!)し c:\ とバックスラッシュが続くのも許容される。c:の後にパス区切りが無いドライブ相対指定は許容されない。当然プラットフォームによって異なる。面白いのが相対パスにバックスラッシュを使った .\file は許容されないが絶対パス \file は許容される点)

        (注: file: と同じように 後ろに :: を付けられるが省略)

  • リンクタイプ付き
    • 省略記法(org-link-abbrev-alist, org-link-abbrev-alist-local)
    • リンクタイプ(org-link-parameters)
      • file: (file+sys:file+emacs: も形式は同じ。 ファイルパス は空でも良い)
        • [[file: ファイルパス ]
        • [[file: ファイルパス :: 行番号 ]
        • [[file: ファイルパス :: 色々検索 ]
        • [[file: ファイルパス :: * 見出し ]
        • [[file: ファイルパス :: # カスタムID ]
        • [[file: ファイルパス :: ( コード行参照 ) ]
        • [[file: ファイルパス :: / 正規表現 / ]
      • その他沢山(標準的なもの: attachment:, bbdb:, docview:, doi:, elisp:, gnus:, rmail:, mhe:, help:, http:, https:, id:, info:, irc:, mailto:, news:, shell:)

……漏れがあったらすみません。

いろんなリンクの例としてexamples/links.orgというのも作っておきました。

# の後で補完すれば全カスタムIDが候補として出ますし、 ( の後なら全(ref:)表記、 * の後なら全見出しが出ます(見出しだけはorg-modeの標準でも補完してくれます)。

色々検索 の部分ですが、概ね次のように検索されるようです。

  1. dedicated target (<< と >> で囲んだ文字列がリンクターゲットになります。文字列はエクスポートされません)
  2. 要素(ブロック)の名前 (#+NAME:で指定する)
  3. 見出し
  4. 全文検索 (org-link-search-must-match-exact-headlineがnilの時またはorg以外のファイルの時のみ)

概ね <<My Target>>#+NAME: table1 のようなものへのリンクと考えた方が良さそうなので、それだけを補完候補として出しています。

ファイルの :: 以降はまだ未実装です。現時点では補完されません。

file以外のリンクタイプについては手を付けていません。 org-link-parametersから :capf-path:capf-desc という非標準のプロパティを取得してそれを呼び出すようにしてあるので自分でいくらでも追加できます。org-elisp-link.elもその方法で補完関数を追加しているので、関数名や変数名をorg-modeバッファ内で補完できます。

いずれの種類においても有効なのが他の同種のリンクから候補を集めるという方法です。リンクの説明部分を補完するときに、既に書かれている同じタイプとパスを持つリンクから説明部分を拝借してくることが出来ます。パスについても同じタイプを持つリンクから候補を集めます。

色々やると大きなファイルで処理が遅くなる場合もあるかもしれません。全ての補完関数は個別に取り除く(無効化する)ことが出来るようになっています。

というわけで大枠は出来たかと思います。細かいところがまだ残っていますが、まぁ、そのうちやったりやらなかったりするでしょう。

ここまでやっておいてこの投稿を書いている間に何回C-c C-lでミニバッファにパスや説明部を入力してリンクを作成したことか。まぁ、今後は両方使えるということで(笑)

参考資料: