Espanso
Espanso とは、オープンソースかつ無料で使用できる、クロスプラットフォーム(Windows、macOS、Linux)のスニペットアプリです。Espanso を使用すると、短いキーワードを入力するだけで、長いテキストを瞬時に入力できます。これにより、繰り返し入力する必要のあるテキストを簡単に入力できるようになります。Mac 標準のテキスト辞書よりも高速で、多機能です。さらに、Shell script を呼び出すことができるので、ただのスニペットアプリとしてだけでなく、アプリやファイルを開いたり、APIを呼び出すことができるなど、非常に拡張性が高いです。例えば、クリップボードにコピーしたテキストを即時翻訳させることができ、作業中のアプリから離れる必要もなくなります。
インストール
インストールしたら、アプリを開きます。そして、ターミナルを開き、コマンドで espanso status
を実行して動いているか確認しましょう。
設定
Espanso の設定は主に2つのファイルで行います。
esnpanso/
config/
default.yml
match/
base.yml
espanso
のディレクトリの場所は OS によって異なり、コマンド espanso path
によって確かめることができます。
- Linux:
$XDG_CONFIG_HOME/espanso
(e.g./home/user/.config/espanso
) - MacOS:
$HOME/Library/Application Support/espanso
(e.g./Users/user/Library/Application Support/espanso
) - Windows:
{FOLDERID_RoamingAppData}\espanso
(e.g.C:\Users\user\AppData\Roaming\espanso
)
config/default.yml
ファイルは、初めは特に設定することはないです。
もし、メニューバーのアイコンを非表示にたい場合は、show_icon: false
と書き込むと良いです。
使い方
スニペットの設定は match/base.yml
ファイルに書き込みます。
基本的には次のような文法で書きます。
matches:
- trigger: ":hello"
replace: "world"
# 複数行
- trigger: ":hello"
replace: "line1\nline2"
# 複数行
- trigger: ":include newlines"
replace: |
exactly as you see
will appear these three
lines of poetry
# 改行なし
- trigger: ":fold newlines"
replace: >
this is really a
single line of text
despite appearances
match/base.yml
を変更したら、それを反映させるためにメニューバーで Reload
をするか、コマンドで espanso restart
を実行しましょう。
望まないスニペットの作動を防ぐために、:
や ;
などの普段は使わない記号を接頭辞に用いると良いです。
:a
を登録すると :as
や :ad
といったトリガーは使えなくなります。なぜなら、:a
を入力した段階で別のテキストに置換されるからです。このようなことを防ぐために、短すぎるトリガーの設定は避けた方が良いです。
match
ディレクトリにある全ての .yml
ファイルは読み込まれるので、用途に応じてファイルを細かく分割することもできます。
動的マッチ
次の設定では、:now
と入力すると It's 11:29
のように現在時刻に変換します。
- trigger: ":now"
replace: It's {{mytime}}
vars:
- name: mytime
type: date
params:
format: "%H:%M"
単語マッチ
基本的な trigger
と match
の設定方法では、変換して欲しくない場面で変換が起こる可能性があります。例えば、トリガー ther
によって there
としたいとき、other
と入力しても変換が実行され othere
となってしまいます。これを防ぐためには、以下のように word: true
のオプションをつけます。
- trigger: "ther"
replace: there
word: true
カーソルヒント
テキストを変換した後に、カーソルが来る位置を $|$
で決めることができます。
- trigger: ":div"
replace: <div>$|$</div>
一つのトリガーに複数の変換
- trigger: ":quote"
replace: "Every moment is a fresh beginning."
- trigger: ":quote"
replace: "Everything you can imagine is real."
- trigger: ":quote"
replace: "Whatever you do, do it well."
複数のトリガーに一つの変換
- triggers: [":hello", ":hi"]
replace: "world"
複数のトリガーに複数の変換
- triggers: [":ok",":emoji"]
replace: "👍"
- triggers: [":ok",":emoji"]
replace: "✅"
- triggers: [":up",":emoji"]
replace: "⬆️"
- triggers: [":down",":emoji"]
replace: "⬇️"
画像のマッチ
- trigger: ":cat"
image_path: "$CONFIG/images/cat.png"
グローバル変数
match
に共通してよく使う変数がある場合はグローバル変数として設定すると、変更する際に便利です。
global_vars:
- name: myname
type: echo
params:
echo: "John"
# It can also be defined as follows:
# - name: myname
# type: shell
# params:
# cmd: "John"
matches:
- trigger: ":greet"
replace: "Hello {{myname}}"
- trigger: ":sig"
replace: "Best regards, {{myname}}"
espanso のディレクトリを GitHub などで管理したいが、一部プライベートなパラメーターを含むような場合は、params.yml
に入れておき、params.yml
を .gitignore
に追加する方法があります。match
ディレクトリにある *.yml
ファイルは全て読み込まれます。それ以外の場合は、直接パスを指定して import することもできます。
esnpanso/
config/
default.yml
match/
base.yml
params.yml
# base.yml
imports:
- "paths/to/your.yml"
matches:
- trigger: ":hello"
replace: "{{greet}} Jon"
Clipboard Extension
変換後の中身にクリップボードの内容を含めて出力することができます。これで、貼り付け作業が必要なくなります。
例えば、直前にコピーしたリンクを用いて、HTML の <a>
タグを作成したい時、以下のようにトリガーを定義します。
- trigger: ":aref"
replace: "<a href='{{clip}}' />$|$</a>"
vars:
- name: "clip"
type: "clipboard"
マークダウンのトリガー例:
- trigger: ";mdlink"
replace: "[$|$]({{clip}})"
vars:
- name: "clip"
type: "clipboard"
- trigger: ";mdcode"
replace: |
```
{{clip}}
```
vars:
- name: "clip"
type: "clipboard"
各トリガーにクリップボード変数を定義するのが面倒な方は、global_vars
に定義しておくと良いです。
Shell Exntension
シェルコマンドを実行して、その結果を出力することもできます。
- trigger: ":shell"
replace: "{{output}}"
vars:
- name: output
type: shell
params:
cmd: "echo 'Hello from your shell'"
以下の例は、ipify からパブリック IP を取得するトリガーです。
- trigger: ":ip"
replace: "{{output}}"
vars:
- name: output
type: shell
params:
cmd: "curl 'https://api.ipify.org'"
以下の例は、UUID(Universally Unique Identifier)を生成するトリガーです。
- trigger: ";uuid"
replace: "{{output}}"
vars:
- name: output
type: shell
params:
# macOS,Linux:
cmd: "uuidgen"
# Windows (requires PowerShell):
# cmd: "powershell -command \"[guid]::NewGuid().ToString()\""
以下の複数の例は、本来のアプリの趣旨とは異なりますが、アプリやWebサイト、ファイルを開くためのトリガーです。
まずは、ターミナルや特定のフォルダを開くトリガー。
- trigger: ";term"
replace: "{{output}}"
vars:
- name: output
type: shell
params:
cmd: "open -a Terminal.app"
- trigger: ";dotfile"
replace: "{{output}}"
vars:
- name: output
type: shell
params:
cmd: "open ~/github/dotfiles/"
ターミナルを経由し、VScode で espanso
ディレクトリを開くトリガー。ターミナルが開き、code ~/github/dotfiles/espanso/
が実行されます。\n
がエンターの役割を果たします。
- trigger: ";espanso"
replace: "{{output}}\n"
vars:
- name: output
type: shell
params:
cmd: "open -a Terminal.app; echo 'code ~/github/dotfiles/espanso/'"
以下のように、直接呼び出す書き方もできますが、最初に開かれているファイルの一部が消される可能性があります。
- trigger: ";espanso"
replace: "{{output}}"
vars:
- name: output
type: shell
params:
cmd: "code ~/github/dotfiles/espanso/"
CotEditor.app
で新しいファイルを作成し、それを開くトリガー。
- trigger: ";newfile"
replace: "{{output}}"
vars:
- name: uuid
type: shell
params:
cmd: "uuidgen"
- name: output
type: shell
params:
cmd: "cd ~/Desktop; touch {{uuid}}.md; open /Applications/CotEditor.app {{uuid}}.md"
Youtube を開くトリガー。デフォルトのブラウザで開きます。
- trigger: ";you"
replace: "{{output}}"
vars:
- name: output
type: shell
params:
cmd: "open 'https://www.youtube.com/'"
クリップボードにコピーした内容を検索するトリガー。
- trigger: ";ggl"
replace: "{{output}}"
vars:
- name: "clip"
type: "clipboard"
- name: output
type: shell
params:
cmd: "open 'https://www.google.com/search?q={{clip}}'"
クリップボードにコピーした内容を Google Gemini で翻訳するトリガー。global_vars
にGEMINI_API_KEY
を定義した上で使用してください。
- trigger: ";transen"
replace: "{{translation}}"
vars:
- name: "clip"
type: "clipboard"
- name: translation
type: shell
params:
cmd: >
curl -s \
"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={{GEMINI_API_KEY}}" \
-H 'Content-Type: application/json' \
-X POST \
-d '{
"contents": [{
"parts": [{"text": "Translate the following to English. Provide ONLY the translated text, no explanations or markdown: {{clip}}"}]
}]
}' \
| jq -r '.candidates[0].content.parts[0].text | split("\n")[0]'
指示を変更すれば、いろいろな種類のトリガーを作成できます!
Script Exntension
外部ファイルを実行してその結果を受け取ることもできます。
script.py
print("Hello from python")
base.yml
- trigger: ":pyscript"
replace: "{{output}}"
vars:
- name: output
type: script
params:
args:
- python
- /path/to/your/script.py
Form Extension
トリガーからフォームを生成し、定型文にそって文章を作成することもできます。
- trigger: ":greet"
form: |
Hey [[name]],
Happy Birthday!
上のフォームは以下のように表現することもできます。
# The above is equivalent to the following
- trigger: ";_greet"
replace: |
Hey {{form.name}},
Happy Birthday!
vars:
- name: "form"
type: form
params:
layout: |
Hey [[name]],
Happy Birthday!
variable
と form
を同じトリガー内で使用するような複雑な場合には、こちらの記法出ないと作動しないようです。
次の設定は、メールの定型文フォームから文章を作成します。
matches:
- trigger: ";reply"
form: |
Hi, [[name]]
Thank you for your email and for bringing this to our attention.
I am sorry that you're disappointed with our product.
[[choices]]
Looking forward to hearing from you
All the best,
ABC Support Team
form_fields:
choices:
type: choice
values:
- Could you please let me know what specific issues you've encountered?
- sentence 2
- sentence 3
- sentence 4
より複雑なフォームの使い方として、次のように Todo アイテムを作成できます。
- trigger: ";todo"
replace: "Task: {{form1.task}}, Due Date: {{form1.day}} {{form1.time}}"
vars:
- name: "day0"
type: date
params:
format: "%Y/%m/%d"
- name: "day1"
type: shell
params:
cmd: "date -v+1d '+%Y/%m/%d'"
- name: "day2"
type: shell
params:
cmd: "date -v+2d '+%Y/%m/%d'"
- name: "day3"
type: shell
params:
cmd: "date -v+3d '+%Y/%m/%d'"
- name: "day4"
type: shell
params:
cmd: "date -v+4d '+%Y/%m/%d'"
- name: "day5"
type: shell
params:
cmd: "date -v+5d '+%Y/%m/%d'"
- name: "day6"
type: shell
params:
cmd: "date -v+6d '+%Y/%m/%d'"
- name: "form1"
type: form
params:
layout: "Task: [[task]], Due Date: [[day]] [[time]]"
fields:
day:
type: choice
values: |
{{day0}}
{{day1}}
{{day2}}
{{day3}}
{{day4}}
{{day5}}
{{day6}}
time:
type: choice
values:
- "9:00"
- "10:00"
- "11:00"
- "12:00"
- "13:00"
- "14:00"
- "15:00"
- "16:00"
- "17:00"
- "18:00"
- "19:00"
- "20:00"
例
ここでは書ききれなかったトリガーの例は以下のレポジトリにあります。
あるいは、次のサイトも参考になります。