Skip to content

Binding Field define

The define field can be used to define reusable values. There are three types of values that can be defined.

  1. [[define.val]] variable definitions: defines any number of key-value pairs that can be referenced inside an expression or when clause.
  2. [[define.command]] command definitions: defines one or more commands that can be referenced when running multiple commands.
  3. [[define.bind]] bind definitions: defines a partial set of command fields that can be referenced using the default field of bind.

Variable Definitions

These can be any arbitrary TOML value. You can define multiple variables within each [[define.val]] element this way. These are then available in any expressions evaluated at runtime and in when clauses. They can also be changed using setValue

Expressions can occur within the values, and these will be evaluated at read-time. No val. fields are in scope within these expressions: you cannot refer to one define.val key within the expression of a second define.val key.

Example

To handle symmetric insert of brackets, Larkin uses the following definition

toml
[[define.val]]

[define.val.braces]
"{".before = "{"
"{".after = "}"
"}".before = "{"
"}".after = "}"
"[".before = "["
"[".after = "]"
"]".before = "["
"]".after = "]"
"(".before = "("
"(".after = ")"
")".before = "("
")".after = ")"
"<".before = "<"
"<".after = ">"
">".before = "<"
">".after = ">"

This is then applied when handling symmetric typing using the whenNoBinding.run option of [[mode]].

toml
[[mode]]
name = "syminsert"
highlight = "Highlight"
cursorShape = "BlockOutline"

[[mode.whenNoBinding.run]]
command = "selection-utilities.insertAround"
args.before = '{{val.braces[key.captured]?.before ?? key.captured}}'
args.after = "{{val.braces[key.captured]?.after ?? key.captured}}"
args.followCursor = true

Command Definitions

You can define reusable commands that can be run when running multiple commands.

In addition to the normal fields of a command, you must provide an id to refer to the command as {{command.[id]}}.

Example

Larkin defines commands to select N lines downwards

toml
[[define.command]]
id = "selectLinesDown"
command = "runCommands"
args.commands = [
    "selection-utilities.shrinkToActive",
    { skipWhen = "{{key.count <= 0}}", command = "cursorMove", args = { to = "down", by = "wrappedLine", select = true, value = "{{key.count}}" } },
    "expandLineSelection",
    "selection-utilities.exchangeAnchorActive",
]

And uses this definition as follows

toml
[[bind]]
default = "{{bind.edit_action}}"
key = "c"
when = "!editorHasSelection && master-key.count > 1"
command = "runCommands"
args.commands = [
    "{{command.selectLinesDown}}",
    "deleteRight",
    "editor.action.insertLineBefore",
    "master-key.enterInsert",
]

Binding Definitions

You can define partial bind definitions, e.g. for common default values to use across many bindings.

The args field is merged recursively with the default value, allowing you to specify some arguments in the default [[define.bind]] and others in [[bind]] directly. The remaining fields are set to the default value when not specified (i.e. there is no deep merging for the other fields).

Example

Larkin makes extensive use of default keys for the simple cursor motions. The default command is always cursorMove and each motion changes what direction to move using args.value.

toml
[[define.bind]]
id = "edit_motion_prim"
default = "{{bind.edit_motion}}"
command = "cursorMove"
args.value = "{{key.count}}"
args.select = "{{editorHasSelection}}"

[[bind]]
default = "{{bind.edit_motion_prim}}"
key = "h"
args.to = "left"
mode = "normal"

[[bind]]
default = "{{bind.edit_motion_prim}}"
key = "l"
args.to = "right"

This example also demonstrates that define.bind definitions can themselves have a default, allowing for a hierarchy of defaults if so desired.