Skip to content

Chained Keybinds #9961

Closed

Description

@mitchellh

Discussion: #3175 (Lots of context!)

The ability to register a keybind with multiple actions that happen in sequence.

Every syntax I can think of complicates parsing binding actions which by this point can contain just about anything. So, instead, I thought of something different. Here is some proposed syntax:

keybind = ctrl+shift+f=ignore
keybind = chain=toggle_fullscreen
keybind = chain=toggle_window_decorations

The chain key would cause the parsed action to be appended to the most recently bound action. Therefore, starting with ignore is a good way to ensure that you're starting a new chain and to establish the key. You could just as easily start with toggle_fullscreen here. The chain will inherit the flags of the most recently bound action (performable, all, global, etc.).

Note that chaining will NOT work with unbind. Unbind explicitly removes a binding so chaining cannot attach to it.

This adds a bit of verbosity but enables a bunch of good use cases for us:

  • Doesn't complicate parsing actions, there's no ambiguity, quotations, escapes, etc. needed to support this.
  • chain makes it pretty clear something special is going on. I thought about using a sigil like | or |> or something but that makes it pretty special. chain is pretty clear, I think.
  • Compatible with CLIs without ugly quoting, --keybind=ctrl+shift+f=unbind --keybind=chain=foo --keybind=chain=bar
  • Easy to make it a configuration error to specify any flags on chains

I know its not ideal and the syntax is a bit odd at first glance, but I think its the best option we've got given the constraints.

Activity

  1. mitchellh commented on Dec 18, 2025

    @mitchellh
    ContributorAuthor

    This initial proposed issue would send all keybinds to the same target surface that triggered it. Importantly, this omits some use cases, such as creating a new window, sending text to it, and then pressing enter. I think that requires some more thought on how we can fit that in and Im happy to see a new discussion about that.

  2. mitchellh commented on Dec 22, 2025

    @mitchellh
    ContributorAuthor

    Adding more details to this for key sequences:

    keybind = ctrl+a>b>c=new_window
    keybind = chain=new_tab
    

    In this scenario, chain applies to the most recent binding, including sequences. So this would chain ctrl+a>b>c to create a new window and a new tab.

    And for tables:

    keybind = foo/a=new_window
    keybind = foo/chain=new_tab
    
    # ERROR! No prior binding
    keybind = chain=new_tab
    

    The chaining must happen with the named table to apply the chain to. If no named table is given, it assumes the default table. This is a bit of an implementation detail but simplifies our implementation a lot (allows us to attach chains to binding sets internally). I think we can work around this limitation in the future since I suspect it'll be a bit of a footgun.

  3. added this to the 1.3.0 milestone on Dec 23, 2025
  4. added a commit that references this issue on Dec 23, 2025
    7ad1e6e
  5. kirelagin commented on Apr 18, 2026

    @kirelagin

    For anyone finding this and being confused about how chain works with tables, what is documented here is no longer true – it has been changed in #10039, and you no longer need the chain prefix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    inputKeyboard or mouse input

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions