Open_rec : Espanso
espanso?
espanso is the best free and open-source text expander I have seen. It can replace pre-defined triggers with pre-define snippets. For instance, :mt with:
Please provide me the source code for a Markdown table explaining ____
or :br with:
best regards,
Ron
espanso saves me a dozen or so keystrokes each time I interact with GPTs or write an email. It is essential to my workflow, not just because it saves time, but more importantly because reducing tedious yet necessary repetitions to a minimum helps me concentrate on the creative part.
Why espanso? espanso is much more than a text expander.
It supports emojis, images, dynamic injections, and scripts, and can be set up as an emoji+GIF input method, datetime injector, and shortcuts to various scripts, among numerous other possibilities.
espanso also supports context-aware replacement. Different sets of triggers can be set up for different apps. For instance, :br for best regards can be limited to email clients, freeing up the trigger for different use in another context. Therefore, all my triggers can stay really short. None of my triggers are longer than 4 characters.
Last but not the least, the espanso community is just amazing. You meet the nicest people with espanso. Many write and share extensions and packages: Jobie Wong, for instance, created a complete open-source emoji v.15 library for espanso; Many help others out on the Discord channel: The channel is more responsive than most commercial support, getting back to questions within a few hours.
💻 OS:
| Linux | Windows | macOS | Android | iOS |
|---|---|---|---|---|
| ✅ | ✅ | ✅ |
We focus on Linux, but many of the applications we recommend are cross-platform.
⏰: 10 - 40 minutes
For those:
- Comfortable with basic command line operations
- Looking to speed up their typing
Good to Know
Codium:
Our code editor of choice is VSCodium. You will see BASH scripts like codium <file> in this tutorial. You can substitute codium with nano (the default GNU text editor) or your code editor of choice.
espanso
Download
See here for instructions and troubleshooting guide.
Start up
espanso is command line. If you have taken the effort to move to Linux, it is the extra hundred meter after a mile to learn basic BASH command line syntax.
A good place to start with BASH on Linux
# Check status, start if not running
if espanso status | grep -q "espanso is running"; then
echo "✅ Espanso is running."
else
echo "❌ Espanso is not running."
echo "🔄 Attempting to restart..."
espanso
sleep 2
if espanso status | grep -q "espanso is running"; then
echo "✅ Espanso restarted successfully!"
else
echo "⚠️ Failed to start Esvpanso. Try running: espanso"
fi
fi
Static match
The basic building block of espanso is match.
matches:
# Simple text replacement
- trigger: ":espanso"
replace: "Hi there!"
Whenever the trigger is typed, espanso replaces it with replace.
.yml
Matches are stored in .yml (Yet Another Markup Language) files.
An example .yml file:
# espanso match file
# For a complete introduction, visit the official docs at: https://espanso.org/docs/
# You can use this file to define the base matches (aka snippets)
# that will be available in every application when using espanso.
# Matches are substitution rules: when you type the "trigger" string
# it gets replaced by the "replace" string.
matches:
# Simple text replacement
- trigger: ":espanso"
replace: "Hi there!"
Configuration directory
espanso .yml configuration files are stored in directory $CONFIG. You can find out the path of $CONFIG by bash espanso path.
Run the following script to jump to the configuration directory and store the path as the CONFIG variable:
CONFIG=$(espanso path | awk '/Config:/ {print $2}')
cd "$CONFIG" && echo -e "\$CONFIG is now set to $CONFIG\nCurrent directory is changed to $CONFIG" || echo -e "Error. Verify espanso is running."
Run ls and you will see two folders:
config\ match\
Continue cd and ls around you quickly discover the configuration file structure of espanso:
- match
base.ymlpackages/
- config
default.yml
Now run codium $CONFIG/match/base.yml and what do you see?
codium starts the code editor VSCodium. Use
nanoor another text editor if you do not have VSCodium.
match/
match/ folder tells espanso WAHT to do. You can add custom matches in base.yml, or create your own .ymls. I recommend the latter approach to preserve the base as something to revert back to if things goes wrong. Consider creating separate custom .ymls for different contexts, such as one for Javascript coding, one for responding to emails, and one for AI prompts, etc. with this syntax:
matches:
- trigger: ":br"
replace: "Regards,\nRon" # `\n` is interpreted by espanso by default as the newline character
- trigger: ":l"
replace: "Linux"
...
YML is indentation-sensitive. Prefer a single
SPACEtoTAB.
Special characters can be represented by their unicode, such as
\u20acfor €.
config/
config/ folder tells espanso HOW and WHEN to activate.
HOW:
You can toggle options with the format <option>: <value> in default.yml. For instance, you can write auto_restart: false to disable automatic refreshment upon detection of changes to the configuration. A complete list of available options can be found here.
WHEN:
You can also specify in what apps each match sheet in match/ is loaded. For instance, you can specify certain matches are only loaded in email clients.
We will discuss in more depth in App specific Configurations
Search bar and Opps! button
When you have a bazellion matches, which is not impossible with large packages such as emoji packs installed, you will inevitably start to lose track.
ALT+SPACE by default brings up the search bar for matches. Typing > at the beginning of the search bar brings up available espanso commands.
❗
ALT+SPACEmay create conflict with system shortcuts on Linux. You can change it by writingsearch_shortcut: <shortcut>in$CONFIG/config/default.ymlExample:
search_shortcut: CTRL+ALT+SPACEAvailable keys:
ALT,CTRL,CMD,SHIFT,ENTER,TAB,SPACE,META,OPTION,INSERT,DOWN,LEFT,RIGHT,UP,END,HOME,PAGEDOWN,PAGEUP,F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12,F13,F14,F15,F16,F17,F18,F19,F20,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,0,1,2,3,4,5,6,7,8,9,NUMPAD0,NUMPAD1,NUMPAD2,NUMPAD3,NUMPAD4,NUMPAD5,NUMPAD6,NUMPAD7,NUMPAD8,NUMPAD9
Not all keys are tested. Bug reports are highly appreciated.
You can also set up a search trigger by writing search_trigger: "<trigger>" in $CONFIG/config/default.yml.
BACKSPACE immediately after a trigger undos the trigger. Useful in case of accidents.
❗From time to time espanso would get stuck and not respond to keyboard shortcuts. Run
espanso restartand try again.
Case propagation
- trigger: alh
replace: although
word: true
propagate_case: true
word: true: Replacement is only triggered by alh, not words containing alh, for instance, alh
propagate_case: alh -> although; AlH -> Although; ALH -> ALTHOUGH
Image substitution
- trigger: :dog
image_path: "/path/to/image.png"
The recommended image format for Linux is .png
Rich text substitution is also available.
Dynamic matches
In addition to static matches,espanso also supports dynamic matches.
Datetime
In dynamic matches, replace contains one or more variables:
- trigger: :now
replace: "{{datetime}}"
vars:
- name: datetime
type: date
params:
format: "%Y-%m-%dT%H:%M%z"
datetime is a custom variable name created for reference in replace.
date is an espanso expansion that return system datetime. It is based on chrono
%z displays the timezone offset relative to UTC+0. The extension accepts parameter format to specify how the datetime should be displayed. For more info on this extension, see espanso date extension guide
Choice
As you add more and more matches, you may run out of simple triggers. Luckily espanso supports the choice structure:
- trigger: ":os"
replace: "{{output}}"
vars:
- name: output
type: choice
params:
values:
- "Linux"
- "macOS"
- "Windows"
With this :os triggers a selection box. Try it out.
Echo
global_vars:
vars:
- name: var
type: echo
params:
echo: "value"
echo is used to declare global variables in espanso, similar to var variable=value in Javascript.
Global variables can be used in any subsequent replaces.
Script activation
- trigger: ":pyscript"
replace: "{{output}}"
vars:
- name: output
type: script
params:
args:
- python
- /path/to/your/script.py
This executes the python script at /path/to/your/script.py.
The espanso .config folder can be substituted by %CONFIG%. For instance, if the script is located at /home/<user>/.config/espanso/script.py, then the path can be passed as %CONFIG%/script.py
❗ Limit execution to fast-running scripts to avoid lag.
A possible value for param is debug:true to display additional technical info,
Shell integration
You can set up trigger to execute shell commands:
- trigger: ":ip"
replace: "{{output}}"
vars:
- name: output
type: shell
params:
cmd: "curl 'https://api.ipify.org'"
shell: bash
Use shell: pwsh for powershell core.
For a complete list of extensions, see espanso extensions
Regex triggers
In Dynamic matches, the triggers remained fixed.
Dynamic triggers are possible with Regex:
- trigger: ":#(?P<num>\\d)"
replace: "{{output}}"
vars:
- name: output
type: shell
params:
cmd: "printf '%*s' $ESPANSO_num | tr ' ' '#'"
shell: bash
The trigger uses the named capture group (num) to capture a single integer (\d).
In the regex variant used by espanso, named capture groups are specified with (?P<name>expr.). \d must be escaped with \ because \ is a special character in yml.
The captured groups are stored as espanso variables, which can be recalled with $ESPANSO_name in bash scripts. The example bash scripts prints # n times for Markdown usage.
See more here
App-specific configurations
_.*.yml
All .ymls in match/, except those with names beginning in _, are loaded automatically by espanso startup.
Create _<context>.yml for substitions active in particular apps. For instance, _emailClient.yml to store email addresses and signatures for use in email clients only.
_.*is regex.
config/
espanso is not yet smart enough to automatically interpret what you mean by email client. You tell it what it means in config/.
In config/, you can either edit default.yml or create new .ymls.
filter_class: "Mail"
extra_includes:
- "../match/_email.yml"
- "textEditing.yml
In general, email clients are in the Mail class. You can find out the class of each Windows with xprop.
in addition to extra_include, include,extra_exclude are some possible values.
With extra_include, the default matches (those written in [^_].*.yml) are implicitedly included, while with include only the .ymls explicitly specified are enabled. extra_exclude can be used to exclude certain .ymls loaded by default.
Other filters are available
Packages
espanso supports packages, which are essentially packaged .yml match sheets written by the community.
espanso path packages #find package storage location
espanso install <package-name> (--version <version> --force) #--force overwrites any existing package of the same name.
espanso package update <package-name> | espanso package update all
espanso uninstall <package-name>
espanso package list
You can find many official packages here
Updating espanso configurations
As you type, you will discover more and more potential matches worth settting up. Run these commands to quickly jump to the match/ directory and add new matches!
CONFIG=$(espanso path | awk '/Config:/ {print $2}')
cd "$CONFIG/match" && echo -e "\$CONFIG is now set to $CONFIG\nCurrent directory is changed to $CONFIG/match" || echo -e "Error. Verify espanso is running."
echo -e "Available match files:\n$(ls)"
Member discussion