Forms

Since version 0.7.0, espanso is capable of creating arbitrarily complex input forms:

Espanso Form

These open up a world of possibilities, allowing the user to create matches with many arguments, as well as injecting those values into custom Scripts or Shell commands.

Prerequisites

In order to use forms, espanso requires modulo to be installed. If you are a Windows or macOS user, then modulo is most likely already installed with recent versions of espanso, but if you are using Linux, you’ll need to install it manually.

Getting started

Let’s say you want to create a match for birthday greetings, personalized with the person name. With forms, that would translate to:

  - trigger: ":greet"
    form: |
      Hey {{name}},
      Happy Birthday!

Then, after typing :greet, you will be prompted with:

Form example

After entering the desired name, we can submit the form either by clicking “Submit” or pressing CTRL+Enter.

The key here is to specify the form field rather than replace, which is a shorthand for the verbose syntax explained in the following sections.

You can create as many fields as you like, just indicate them with the double-brackets {{field_name}} syntax.

Controls

In the previous example, we’ve seen how to use simple text fields, but modulo supports many controls, such as:

  • Multiline text field
  • Choice box
  • List box

In order to use another control, we need to specify it in the form_fields parameter. Let’s say we want to add a multiline text field to our previous example to write our custom message inside the greetings:

  - trigger: ":greet"
    form: |
      Hey {{name}},
      {{text}}
      Happy Birthday!
    form_fields:
      text:
        multiline: true

After saving and triggering the match, we would be prompted with a form like the following:

Form example

Let’s analyze the most important bits:

  1. Inside the form parameter we specified the {{text}} field. This name is arbitrary, you can put whatever you want there.
  2. In the form_fields parameter, we specified that the text field had property multiline: true

Each control has its own options, so let’s see them separately:

Text Fields

Text Fields are the default control. Anytime you specify a new field using the {{field_name}} syntax, that field is considered a text field, if not specified otherwise.

Property Description Default value
multiline If true, the text field becomes a multiline text area false
default Specify the default value of the field null

Choice Box

Choice boxes are fields in which the user can select one choice in a list. In order to use it, you have to specify the type: choice parameter, along with an array of values:

  - trigger: ":form"
    form: |
      {{choices}}
    form_fields:
      choices:
        type: choice
        values:
          - First choice
          - Second choice

Which produces:

Form example

Property Description Default value
default Specify the default value of the field null

List Box

List boxes are completely equivalent to Choice Boxes, with the only difference of requiring type: list rather than type: choice.

  - trigger: ":form"
    form: |
      {{choices}}
    form_fields:
      choices:
        type: list
        values:
          - First choice
          - Second choice

Which produces:

Form example

Using with Script and Shell extension

The syntax proposed above works for most cases, but there are times in which you might want to harness the full power of espanso forms, for example using them with the Script and Shell extension.

The first important thing to understand is that the following syntax:

  - trigger: ":form"
    form: "Hey {{name}}, how are you?"

is a shorthand of the following match:

  - trigger: ":form"
    replace: "Hey {{form1.name}}, how are you?"
    vars:
      - name: "form1"
        type: form
        params:
          layout: "Hey {{name}}, how are you?"

What this does is simply generating a form with the given layout, and then injecting the resulting fields (form1.name) into the replacement text. It should be clear now that forms are extensions themselves, just like the Date and Script extension.

All right, but how can we use forms with the shell extension?

Let’s say that we want to create a match that prompts for user input, and then expands to the reverse of what the user inserted. That could be implemented with:

  - trigger: ":rev"
    replace: "{{reversed}}"
    vars:
    - name: form1
      type: form
      params:
        layout: |
          Reverse {{name}}
    - name: reversed
      type: shell
      params:
       cmd: "echo $ESPANSO_FORM1_NAME | rev"

The key aspect here is that the value of the form field is injected in the shell variable as ESPANSO_FORM1_NAME. The naming is pretty straightforward, as the form variable is called form1 and the field is called name.

To understand more about the variable injection mechanism, please read the Advanced Topics section.

Controls with the Verbose syntax

If you want to use other Controls in a form specified using the above (verbose) syntax, you would have to specify the fields parameter:

  - trigger: ":form"
    replace: "Hey {{form1.name}}, how are you? Do you like {{form1.fruit}}?"
    vars:
      - name: "form1"
        type: form
        params:
          layout: "Name: {{name}} \nFruit: {{fruit}}"
          fields:
            name:
              multiline: true
            fruit:
              type: list # or `choice`
              values:
                - Apples
                - Bananas
                - Oranges
                - Peaches

Note that the fields parameter content is specified as the form_fields parameter explained above.

macOS remarks

For the expansion to take place on macOS, you have to release the submit keys (CTRL+Enter) after submitting the form.

Enabling Tab traversal

By default, on macOS the Tab key can only be used to change focus between Text fields. To make forms completely navigable using the Tab key (including Lists, Selects and Buttons), you have to enable it with these steps:

  1. Open System Preferences
  2. Navigate to the Keyboard panel
  3. Open the Keyboard Shortcuts tab
  4. Near the bottom of the dialog, select “All controls”.

Then you should be able to use the Tab key to navigate between form controls.