Espanso: a better way to type
Changing your way of typing with macros and automations.
Have you heard of espanso? I have been using it to automate small tasks while typing, such as inserting a date or generating an ID.
Installation
Start by installing espanso from its download page. Select your operating system, then open a terminal and run:
espanso status
A working installation prints espanso is running. The first time you open it, a short tutorial asks you to type :espanso; espanso replaces it with Hi there.
That small substitution is the basic idea. The examples below show how far it can go.
Configuration
Before writing a configuration, find espanso's configuration directory:
espanso path
The command prints three paths: Config, Packages, and Runtime. We need the path shown for Config. Open it in your editor β neovim in my case:
cd "$(espanso path config)"
code # Using vscode to be more familiar
Espanso directory
The directory contains several .yml files. base.yml is the main configuration file and contains the substitution rules.
Choose a consistent prefix for espanso triggers. Configurations and packages often use :, but ; avoids conflicts with Slack, Notion, and similar applications. It also means you do not need Shift + ; to type a colon.
Substitutions
Now that we know which file to edit, let us look at espanso's substitution types.
Add the following blocks to the matches array in base.yml.
Static substitution
Static substitution is the simplest type. Any message or value that you repeatedly copy and paste can become an espanso macro.
- trigger: ;email
replace: [email protected]
- trigger: ;ssn
replace: 123-45-6789 # Fake SSN generated by my espanso :D
Static substitutions work well when you only need to insert text at the cursor. They can fill common form fields such as email, ID, phone number, or full name.
I also use them for social links, including my YouTube channel, LinkedIn, Twitter/X, and for inserting emojis.
Dynamic substitution
Espanso also provides directives for dynamic values, such as the current time:
- trigger: ;now
replace: {{time}}
vars:
- name: time
type: date
params:
format: "%H:%M"
This uses chrono tokens, a Rust library for date formatting. You can also use parameters such as offset to create triggers for yesterday or tomorrow.
The random extension chooses one value from a list. I use it for ZIP codes: instead of generating an invalid number, I keep a list of known valid codes and select one for autocomplete.
- label: "Random ZIP"
replace: '{{zip}}'
trigger: ;zip
vars:
- name: zip
type: random
params:
choices:
- 10001
- 90210
- 33101
- 60601
- 98101
- 02101
- 85001
- 30301
Now ;zip inserts a valid ZIP code selected from the list.
These examples use espanso's match extensions, variables with the {{VARIABLE_NAME}} syntax, and trigger labels through the - label: property.
Integrating your scripts
Espanso can also execute shell commands when a trigger is typed. This lets you generate values dynamically with any command available on your system, not only bash, zsh, or fish. For example, you can write a program in Deno and use its output as the replacement.
Start with the example from the official documentation:
- trigger: ":ip"
replace: "{{output}}"
vars:
- name: output
type: shell
params:
cmd: "curl 'https://api.ipify.org'"
This uses curl to make a GET request to ipify.org and return your external IP.
Command execution can vary between operating systems, so check the command syntax for your platform. With that limitation in mind, let us explore a few uses.
ID Generator
Developers often use online tools to generate test IDs and documents. The workflow is usually:
- Open the browser
- Enter the URL
- Find the right option
- Click to generate
With espanso, typing ;uuid can insert a valid UUID at the cursor without leaving the editor or terminal.
As mentioned above, espanso can execute programs written in any language. For this example, use a small UUID generator:
- trigger: ";uuid"
replace: "{{uuid}}"
vars:
- name: uuid
type: shell
params:
cmd: "node -e 'console.log(require(\"node:crypto\").randomUUID())'"
From here, you can turn many repetitive tasks into an espanso flow. Colleagues who adopted it now use it for email templates, automatic form filling, and ID generation.
Conclusion
I have used espanso for more than a year and a half, and it has changed how I work with forms, email, data entry, SQL queries, code snippets, and more. The complete set of automations is in my espanso configuration file.
The main drawback for me is writing YAML. My configuration is therefore written in TypeScript and Deno, which avoids spacing and indentation mistakes. If you prefer YAML, the equivalent configuration is available in this gist.
Thanks for reading.