2023年4月21日
Emacsには補完をサポートするパッケージがあり、最も有名なのはcompanyです。他にはlspを使うことで、プログラミング言語別に入力のサポートをしてくれます。
yasnippetは入力補完の1つで、予め定義したスニペットを使うととで、コードを展開できます。展開にはショートカットキーを使い、高速でプログラミングができる様になります。
例えば、javascriptの変数宣言は大体こんな感じでしょう。
const name = "alice"
yasnippetで、予め変数宣言のスニペットを定義して、 キーに
const
を登録しておきます。const ${1:name} = ${2:initial};
すると、javascriptコード上で
const
と打ち込むだけで、簡単に雛形が展開されてコードを書くことができます。こちらが完成済みのyasnippet設定コードです。
(use-package yasnippet
:ensure t
:custom-face
(yas-field-highlight-face ((t (:inherit nil))))
:bind (:map yas-minor-mode-map
;; バインドが使いづらいので解除
("C-c & C-n" . nil)
("C-c & C-s" . nil)
("C-c & C-v" . nil)
;; よく使うコマンドをバインド
("C-x y n" . yas-new-snippet)
("C-x y i" . yas-insert-snippet)
("C-x y v" . yas-visit-snippet-file)
("C-x y l" . yas-describe-tables)
("C-x y r" . yas-reload-all))
:init
(yas-global-mode)
:config
(setq yas-prompt-functions '(yas-ido-prompt))
;; pythonのインデントバグを修正する関数
(defun yasnippet-snippets--fixed-indent ()
"Set `yas-indent-line' to `fixed'."
(set (make-local-variable 'yas-indent-line) 'fixed))
(add-hook 'python-mode-hook #'yasnippet-snippets--fixed-indent))
スニペットの登録
スニペットは現在開いているメジャーモードに紐づいて作成されます。
js-modeで
.js
ファイルを開いている時に、スニペットを作成すると、js-modeでのみでトリガーするスニペットが作成されます。適当に
index.js
ファイルを作り、それを開いて、スニペットを作ってみましょう。js-modeでスニペットを作ってみます。![article image](https://prod-files-secure.s3.us-west-2.amazonaws.com/a3d79190-572a-4604-a045-8b27c534a5b2/5bee6b3d-eabe-4987-aa11-0cee988ad5f0/newfile.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240727%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240727T070919Z&X-Amz-Expires=3600&X-Amz-Signature=9fe6651747b7845d35b0bc6a511764cc3dceb7a6fdde0b787a34e98cc6b844ca&X-Amz-SignedHeaders=host&x-id=GetObject)
"C-x y n" yas-new-snippet
でスニペット用のバッファを用意します。![article image](https://prod-files-secure.s3.us-west-2.amazonaws.com/a3d79190-572a-4604-a045-8b27c534a5b2/84641f41-8c10-4d6d-8f05-5e56cb0a32d0/snippetfile.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240727%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240727T070919Z&X-Amz-Expires=3600&X-Amz-Signature=3e1af9cd0b534ea04edf1f90da1ed0b6b0e8d19acd24ce954ec3e06edfe297fe&X-Amz-SignedHeaders=host&x-id=GetObject)
javascriptの
const
のスニペットを作ってみましょう。
$0
はカーソルの最後の終着点です。# -*- mode: snippet -*-
# name: const
# key: const
# --
const ${1:name} = ${2:initial}
$0
記述したら
C-x C-s
で保存します。エコーエリアにファイルの保存場所が表示されるので、ファイル名をconst
にしてエンターを押します。![article image](https://prod-files-secure.s3.us-west-2.amazonaws.com/a3d79190-572a-4604-a045-8b27c534a5b2/b63f995c-16be-4427-9b38-8beaccef47a4/save.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240727%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240727T070919Z&X-Amz-Expires=3600&X-Amz-Signature=ba908d5380774c067fbf499e7388be0f64846427faab6a6ec24d574be17b1298&X-Amz-SignedHeaders=host&x-id=GetObject)
ここで表示される
js-mode
フォルダがスニペットのトリガー切り分けになります。js-mode
フォルダに保存されたスニペットはjs-modeでしか発動しません。const
スニペットが登録されました。スニペットの展開
index.js
に戻って、const
と打ち込みます。![article image](https://prod-files-secure.s3.us-west-2.amazonaws.com/a3d79190-572a-4604-a045-8b27c534a5b2/9470b3eb-a575-432e-8c06-816351853b7f/const.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240727%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240727T070919Z&X-Amz-Expires=3600&X-Amz-Signature=32c92e0973b4b0d49935ee00621b7935ec3f5d0e5091b9612d8237fd79c28cec&X-Amz-SignedHeaders=host&x-id=GetObject)
TAB
をタイプすると、スニペットが展開されます。変数名の部分にカーソルが当たるので、
message
とか入力し、もう一度TAB
を押します。今度は値のところにカーソルが移動するので"alice"
を入力します。最後にTAB
を叩くと改行されます。![article image](https://prod-files-secure.s3.us-west-2.amazonaws.com/a3d79190-572a-4604-a045-8b27c534a5b2/336d017f-a52d-4b8b-b8f1-16408f64f5a9/value.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240727%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240727T070919Z&X-Amz-Expires=3600&X-Amz-Signature=b730a69c2f06f47df7c2e6926624f3a7a3ffc04b8e04e60b0785baa8b433c6a6&X-Amz-SignedHeaders=host&x-id=GetObject)
今のはキーが分かっている状態でスニペットを使用しました。
スニペットが増えてくるとどのキーが利用できるかわからなくなってきます。
"C-x y i" yas-insert-snippet
はエコーエリアで対話的にスニペット挿入をサポートしてくれます。今は1つしかスニペットを登録していないので、const
スニペットがそのまま挿入されます。候補が増えてくると絞り込みからの選択でスニペットを挿入できます。
下の画像はif
スニペットとconst
スニペットがある場合の挙動です。![article image](https://prod-files-secure.s3.us-west-2.amazonaws.com/a3d79190-572a-4604-a045-8b27c534a5b2/93881c73-ed84-46b3-ae82-675270955d18/choose.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240727%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240727T070919Z&X-Amz-Expires=3600&X-Amz-Signature=8c6df645a1c154d2cb4ae0245a89448dcb22ea7761c7f1f2212b8bbd107c6420&X-Amz-SignedHeaders=host&x-id=GetObject)
スニペットの編集
作成した
const
スニペットは~/.emacs.d/snippets/js-mode/const
に保存されているので、それを直接開いて、編集することもできます。
面倒な場合は"C-x y v" yas-visit-snippet-file
を実行します。候補が複数ある場合は、エコーエリアで対象のスニペットを選びます。![article image](https://prod-files-secure.s3.us-west-2.amazonaws.com/a3d79190-572a-4604-a045-8b27c534a5b2/c0d2dbb4-a40d-4e3d-bab5-171905055fe8/echo.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240727%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240727T070919Z&X-Amz-Expires=3600&X-Amz-Signature=13d87f852890bed833d65bf6564e7411c1e101f0f35df638ce2de1d1a9926211&X-Amz-SignedHeaders=host&x-id=GetObject)
スニペットファイルが開くので、編集が可能になります。
利用できるスニペットをざっくり見る
"C-x y l" yas-describe-tables
は現在のメジャーモードで使えるスニペットのテーブルを表示します。何が使えて、どのようなキーが割り振られているかを確認するにはこれがベストです。![article image](https://prod-files-secure.s3.us-west-2.amazonaws.com/a3d79190-572a-4604-a045-8b27c534a5b2/c38603b3-5521-4535-933b-d865fcad6407/table.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240727%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240727T070919Z&X-Amz-Expires=3600&X-Amz-Signature=eb295ed555ec592ca0d772d8a6c056e77af33b3d408ba74b0ed6db410f514915&X-Amz-SignedHeaders=host&x-id=GetObject)
スニペットのサンプル
最初からスニペットを自作するのは大変だと思うので、こちらのサンプルを参考にして用意すると良いと思います。ほとんどのプログラミング言語に向けたスニペットが用意されています。
スニペットの自作
私は大体
ruby
、python
、javascript
で開発をおこなっているので、それぞれの言語で以下のようなスニペットを作っています。キーをそれぞれの言語毎に違うものにしてしまうと、覚えるのが大変になるので、共通にしています。それと、キーが同じメジャーモードで被らない限りは1文字で展開できる様にしています。
ここでは代表してpythonのスニペットを紹介します。
変数宣言
v
をキーにしてどの言語も大体こんな感じで展開します。# -*- mode: snippet -*-
# name: variable
# key: v
# --
${1:name} = ${2:initial}
$0
関数宣言
f
をキーにしてそれぞれの言語で関数の雛形を展開します。 # -*- mode: snippet -*-
# name: function
# key: f
# --
def ${1:name}(${2:arg}):
$0
if文
if
をキーにして条件式を展開します。# -*- mode: snippet -*-
# name: if
# key: if
# --
if ${1:cond}:
$0
ife
をキーにしてif-else条件式を展開します。# -*- mode: snippet -*-
# name: if-else
# key: ife
# --
if $1:
$2
else:
$0
elif
をキーに移してif-elifの複数条件式を展開します。# -*- mode: snippet -*-
# name: if-elif
# key: elif
# --
if ${1: cond}:
${2:code}
elif ${3: cond}:
$0
san
をキーにして三項演算子を展開します。# -*- mode: snippet -*-
# name: sankouenzanshi
# key: san
# --
${1:variable} = ${2:true_value} if ${3:cond} else ${4:false_value}
ループ
w
をキーにしてwhile文を展開します。# -*- mode: snippet -*-
# name: while
# key: w
# --
while ${1:condition}:
$0
デバッグ
デバッグ用のキーは好みもあると思います。私は癖でlogの
l
を使っていたのでそれを割り当てています。# -*- mode: snippet -*-
# name: debug
# key: l
# --
print(${1:value})
まとめ
スニペットはあればあるほど、コーディングが早くなるので、よく使うなぁって気づいたら積極的に登録して使い倒しましょう。
また、いくつかのプログラム言語を使っているとちょっとしたif文でも書き方が分からなくなったりするのでそういう思い出すためのコストを下げる意味でもスニペットは役に立ちます。
![profile image](/prof.jpg)
Ted
大学でコンセンサスアルゴリズムを研究。卒業後ベンチャー企業に入社してフルスタックでWebサービスを開発。現在は大手IT企業に転職し、プログラミングを行っている。AIにプログラマーの仕事を奪って欲しいと願っている。