Home About Contact
Emacs , Emacs Lisp , macOS , Chromebook

Emacs でカーソル行にあるURLを取得してブラウザで開く

macOSまたは Chromebook のLinux において、Emacs で編集しているときに現在のカーソル行にある URL をブラウザで開く方法を調べた。

かつて Emacs Lisp (elisp) を使って Emacs を自分で拡張するのが夢だったが、Lisp がよくわからなくてあきらめていた。 最近 Haskell を学習して関数言語の世界観を多少は理解できるようになった気がしたので、 もしかして、今だったら Lisp のことも理解できるのではないか?と思い挑戦してみた。

とりあえず、現在のカーソル行にあるURLを取得してブラウザで開く、という elisp 関数を書くことができたので、ここに備忘録として書き残す。

Step1 現在のカーソル行の文字列を取得

elisp ではカーソルは point と呼ばれている(らしい)。 その point の存在する行にある文字列を全部取得するには次のようにすればよい。

(buffer-substring-no-properties (point-at-bol) (point-at-eol))

buffer-substring-no-properties 関数という Emacs バッファから文字列を取得する関数があるのでそれを使う。 今、関心があるのは現在の行なので、カーソルのある行に属するバッファの範囲を指定すればよい。

そしてその位置を取得する関数が point-at-bol と point-at-eol。 point-at-bolline-beginning-position という関数の別名、 同じく point-at-eol というのは line-end-position の別名。

つまり、buffer-substring-no-properties 関数に カーソルのある行の開始位置と行の終了位置を渡すことで、目的の文字列を取り出すことができる。

これを使って ミニバファに現在の行を表示する関数を定義。 (foo.el など el 拡張子を持つファイルで Emacs-Lisp モードで作業する必要があるかも。)

(defun my-buffer-substring-current-line ()
  "show current line."
  (interactive)
  (message "%s"
	   (buffer-substring-no-properties (point-at-bol) (point-at-eol))))

この関数の末尾にカーソルを置いて C-x e すると my-buffer-substring-current-line が読み込まれる。 (ミニバッファに関数名が出れば成功。)

なお interactive というのは、この手の対話的に呼び出す関数につけるもの。 またこの関数は引数はない。

それでは使ってみよう。 Hello, World! などと Emacs 上でタイプしてその行にカーソルを置いた状態で、M-x すると ミニバッファに M-x : と出るので、 my-buffer-substring-current-line とタイプする。 すると:

Hello, World!

とミニバッファに表示される。

Step2 その行にあるURLを見つけて取り出す

文字列中にURLが含まれていたらその部分だけを取り出して返す my-get-url 関数:

(defun my-get-url (s)
  (if (string-match ".*\\(https:\\/\\/.*\\/\\).*" s)
      (match-string 1 s)
    s))

my-get-url 関数をテストするための my-test 関数:

(defun my-test ()
  "url test"
  (interactive)
  (message "%s" (my-get-url "hello https://osima.jp/ world!")))

両方を C-x e または M-x eval-region などで評価してから M-x my-test で実行する。 ミニバッファに http://osima.jp/ が表示される。

Step3 外部コマンドを実行する

ここでは URL を渡すとブラウザでそのURLのページを表示させたい。 macOS であれば open コマンド、 ChromeOS であれば xdg-open コマンドを使う。

これらのコマンドを elisp から呼び出すには shell-command 関数を使う:

(defun my-show-url-test ()
  (interactive)
  (shell-command "open https://osima.jp/"))
;;  (shell-command "xdg-open https://osima.jp/"))  

C-x e してから M-x my-show-url-test します。 ブラウザに https://osima.jp/ が表示されます。

Step4 まとめ

Step1 から Step3 までの知識を組み合わせて my-show-url 関数をつくります。

(defun my-get-current-line ()
  (buffer-substring-no-properties (point-at-bol) (point-at-eol)))

(defun my-get-url (s)
  (if (string-match ".*\\(https:\\/\\/.*\\/\\).*" s)
      (match-string 1 s)
    s))

(defun my-show-url ()
  (interactive)
  (shell-command (concat "open " (my-get-url (my-get-current-line)))))

リージョンを作成して M-x eval-region します。 次に、Emacs のバッファに以下の文字列をタイプした行をつくります。

hello https://osima.jp/	world!

この行にカーソルをおいた状態で M-x my-show-url します。 https://osima.jp/ がブラウザに表示されます。

以上です。