necotech blog

Emacsで外部スクリプトを動作させるコマンドを作る覚書

elispって癖が強すぎて苦手なので、何か処理をしたい時に別の言語で書いた方が簡単な場合が多いです。elispを書くたびに毎回何かを調べている気がするので、覚書というかテンプレートとしてまとめました。

作るもの

今回はサンプルとして、ファイルを読み込み、その1行目(n行目)をカレントバッファに挿入するコマンドを作ってみます。

外部のスクリプトを用意する

まず、言語は何でもいいので、連携させたいスクリプトを用意します。今回はRubyを使いました。

#! /usr/local/bin/ruby

# ファイルのパスを受け取って、1行目を出力するスクリプト
if ARGV[0] and File.exists?(ARGV[0])
  puts File.read(ARGV[0]).lines.first.chomp
end

それをどこか適当な場所に置き、実行権限を与えます。

$ mv cat-1line.rb ~/.emacs.d/bin/
$ chmod 755 ~/.emacs.d/bin/cat-1line.rb

init.el

次に、init.elなどEmacsの起動時に読み込まれるファイルに、上記スクリプトを使用する関数を書きます。

(defun cat-1line (path)
  (interactive "fFile: ")
  (let ((command (concat "~/.emacs.d/bin/cat-1line.rb " path)))
    (insert (shell-command-to-string command))))

interactiveを使えば、ユーザにファイルパスや任意の文字列を入力させ、それを関数の引数として受け取ることができます。引数の文字列の意味は、ややこしいので下記を参照してください。

[参考]
interactiveの使い方 (GNU Emacs Lisp リファレンスマニュアル)
emacsのinteractiveの使い方を整理し理解してみました

これで、Emacs上で外部スクリプトが使えるようになりました。

M-x cat-1line⏎
File: path/to/text-file⏎

interactiveで複数の引数を受け取る

複数の引数に入力値をバインドしたい場合は、引数文字列を改行で区切ればうまく動作するようです。

;; 出力する行数を指定できるように変更
(defun cat-1line (path line-number)
  (interactive "fFile: \nnLine: ")
  (let ((command (format "~/.emacs.d/bin/cat-1line.rb %s %d" path line-number)))
    (insert (shell-command-to-string command))))

実行させるスクリプトも、これに対応させて修正します。

# ファイルのパスを受け取って、n行目を出力するスクリプト
if ARGV[0] and File.exists?(ARGV[0])
  n = ARGV[1] ? ARGV[1].to_i - 1 : 0;
  puts File.read(ARGV[0]).lines.to_a[n].chomp
end
M-x cat-1line⏎
File: path/to/text-file⏎
Line: 3⏎
Facebook にシェア
LinkedIn にシェア
Pocket