おすすめスニペットツール - espanso と LuaSnip の使い分け

おすすめスニペットツール - espanso と LuaSnip の使い分け

作成日:
更新日:

スニペットツールとして、以下の2つを使い分けています。

  • espanso — システム全体で使えるテキストエクスパンダー
  • LuaSnip — Neovim用のスニペットエンジン

どちらも外部スクリプト(Python等)を実行できるという点が気に入っています。

使い分けの方針

用途 ツール 理由
コーディング LuaSnip ファイルタイプ別に設定できる
それ以外全般 espanso どのアプリでも使える

espanso の使用例

  • メールの挨拶文
  • 住所・連絡先
  • よく使うフレーズ
  • ミーティング候補日の生成

LuaSnip の使用例

  • 関数テンプレート
  • ボイラープレートコード
  • 言語固有のイディオム
  • テストコードの雛形

espanso

Rust製のテキストエクスパンダーです。macOS、Windows、Linuxで動作します。

基本的な設定

~/.config/espanso/match/base.yml:

matches:
  # 静的なスニペット
  - trigger: ";;mail"
    replace: "example@example.com"

  - trigger: ";;addr"
    replace: |
      〒100-0001
      東京都千代田区...

  # 動的なスニペット(日付)
  - trigger: ";;today"
    replace: "{{date}}"
    vars:
      - name: date
        type: date
        params:
          format: "%Y/%m/%d"

外部スクリプトの実行

espansoの強力な機能のひとつが、外部スクリプトの実行です。

例として、;;sche で直近1週間のミーティング候補日を動的に出力する設定:

matches:
  - trigger: ";;sche"
    replace: "{{output}}"
    vars:
      - name: output
        type: script
        params:
          args:
            - python3
            - /path/to/scripts/schedule.py
# schedule.py
from datetime import datetime, timedelta

def generate_schedule():
    today = datetime.now()
    lines = ["ミーティング候補日:", ""]
    
    for i in range(7):
        date = today + timedelta(days=i)
        weekday = ["月", "火", "水", "木", "金", "土", "日"][date.weekday()]
        lines.append(f"- {date.month}/{date.day}({weekday}) 10:00-18:00")
    
    return "\n".join(lines)

print(generate_schedule())

これで ;;sche と入力すると、以下のような文字列が展開されます:

ミーティング候補日:

- 12/9(月) 10:00-18:00
- 12/10(火) 10:00-18:00
- 12/11(水) 10:00-18:00
...

毎回手で書く必要がなくなって、かなり楽になりました。

LuaSnip

Neovim用の高機能スニペットエンジンです。

ファイルタイプ別設定

LuaSnipの強みは、ファイルタイプごとにスニペットを定義できること。

-- lua/snippets/typescript.lua
local ls = require("luasnip")
local s = ls.snippet
local t = ls.text_node
local i = ls.insert_node

return {
  -- 関数テンプレート
  s("fn", {
    t("function "),
    i(1, "name"),
    t("("),
    i(2),
    t(") {"),
    t({"", "  "}),
    i(0),
    t({"", "}"}),
  }),

  -- アロー関数
  s("af", {
    t("const "),
    i(1, "name"),
    t(" = ("),
    i(2),
    t(") => {"),
    t({"", "  "}),
    i(0),
    t({"", "}"}),
  }),
}

TypeScriptファイルでのみ fnaf が展開される、といった使い分けができます。

外部スクリプトの実行

LuaSnipでも外部スクリプトを実行できます。

local ls = require("luasnip")
local s = ls.snippet
local f = ls.function_node

s("uuid", {
  f(function()
    local handle = io.popen("uuidgen")
    local result = handle:read("*a"):gsub("%s+$", "")
    handle:close()
    return result
  end),
}),

uuid と入力すると、動的にUUIDが生成されます。

espanso の改善:入力ミス対策

espansoを使っていて、どうしても改善したかった点がありました。

長いトリガーを入力間違えてしまうと発火しない

例えば ;;schedule というトリガーを設定していて、;;schedle(lが抜けた)と入力してしまうと、何も起こりません。 入力を消してやり直すのが地味にストレスでした。

Better Touch Tool を使った解決策

これを改善するために、Better Touch Tool と組み合わせる設定を行いました。

仕組み

  1. 発火させたいトリガー(例:;;sche)をクリップボードにコピー
  2. 任意の場所で Ctrl+Shift+; を押す
  3. クリップボードの内容が「入力」され、espansoが発火

Better Touch Tool の設定

  1. Better Touch Tool を開く
  2. キーボードショートカットを追加
  3. Ctrl+Shift+; にキーマップを設定
  4. アクションとして「テキストを入力(Insert / Type Custom Text)」を選択
  5. 入力内容に {clipboard} を設定

重要: 「入力してテキストを挿入する(Type text)」オプションを選択すること。

espansoはテキスト入力を監視して発火するため、単なるペーストではなく「キーボードからの入力」として扱わせる必要があります。

使い方

1. トリガー文字列をコピー(例:;;sche をコピー)
2. 展開したい場所にカーソルを移動
3. Ctrl+Shift+; を押す
4. espanso がトリガーを検知して展開

これで入力ミスを気にせず、確実にスニペットを展開できるようになりました。

よく使うトリガーの管理

この方法を活用して、よく使うトリガーをテキストファイルで管理しています。

# ~/snippets.txt
;;sche    - ミーティング候補日
;;mail    - メールアドレス
;;addr    - 住所
;;thanks  - お礼メール
;;mtg     - 議事録テンプレート

このファイルから必要なトリガーをコピーして Ctrl+Shift+; で展開。 トリガー名を覚えていなくても大丈夫です。

まとめ

スニペットツールの使い分け:

ツール 用途 特徴
espanso システム全体 どのアプリでも使える、外部スクリプト実行可能
LuaSnip Neovim ファイルタイプ別設定、プレースホルダー移動

共通して気に入っている点:

  • 外部スクリプト実行 — 動的なコンテンツ生成が可能
  • 設定ファイルで管理 — バージョン管理できる、dotfilesに含められる

espansoの入力ミス対策:

  • Better Touch Tool と連携
  • トリガーをコピー → Ctrl+Shift+; で確実に展開
  • 長いトリガー名でも安心

スニペットは一度設定すると長く使えるので、時間をかけて整備する価値があります。


参考