Have you checked for existing feature requests?
Summary
Keyboard input handling in the terminal package is fraught. Many bindings theoretically can produce control characters in terminals, and that means many bindings can end up being swallowed by the terminal even when the user intends them to trigger ordinary actions in Pulsar.
Ctrl+F is a good example. It's the default keybinding on Windows and Linux for opening up the terminal's “find” palette. But it has an obscure potential function in a terminal, too, since it matches an emacs-style binding for moving the cursor forward one character.
XTerm.js allows us to be consulted on all keypresses, and to inspect the keyboard event and decide whether we should handle the event instead of XTerm.js. But that's not an easy question to answer in the hypothetical! The most reliable way to answer that question for sure is to call atom.keymaps.handleKeyboardEvent — but that actually handles the event! We're not trying to replace or preempt Pulsar's keyboard handling; we're just trying to tell XTerm.js whether to swallow the event or let it propagate to us, at which point keyboard handling will proceed. If we actually call handleKeyboardEvent for an event that would trigger a Pulsar command, it'll end up getting triggered twice.
(You might think: “Just handle it manually, then tell XTerm.js to swallow it!” Yet that will still result in two triggers for those bindings that don't match any XTerm.js control sequences. We get a bite at the apple before we know if the event represents a key binding with special meaning in a terminal — so if it tries to handle it and strikes out, the event propagates to us anyway, and Pulsar will respond once again to an event that we impatiently handled before its time.)
The best way to fix this would be to have a “dry run” mode for handleKeyboardEvent, or else to split the logic in handleKeyboardEvent into two methods — one for identifying the match or matches for a given keyboard event, and another to actually invoke them.
What benefits does this feature provide?
Introspection is good! It gives us the flexibility we need for the terminal scenario described above.
Any alternatives?
The alternative is to reimplement a lot of atom-keymap's logic in pieces. For instance, I can use the keyboard event to get a list of matching keybindings, but I must then do some of the work that handleKeyboardEvent would do: crawling up the DOM tree to winnow the matches based on their CSS selectors. This is duplication of effort and will only diverge from the true implementation in atom-keymap over time if we need to tweak it.
Other examples:
I'm sure VS Code has a similar problem to our terminal dilemma, since it uses both node-pty and XTerm.js. But I haven't researched how they handle it. That research might give us some insight into heuristics for deciding whether a user meant to invoke a terminal binding or a Pulsar binding, but it seems unlikely that it would help with this specific problem.
Have you checked for existing feature requests?
Summary
Keyboard input handling in the
terminalpackage is fraught. Many bindings theoretically can produce control characters in terminals, and that means many bindings can end up being swallowed by the terminal even when the user intends them to trigger ordinary actions in Pulsar.Ctrl+F is a good example. It's the default keybinding on Windows and Linux for opening up the terminal's “find” palette. But it has an obscure potential function in a terminal, too, since it matches an
emacs-style binding for moving the cursor forward one character.XTerm.js allows us to be consulted on all keypresses, and to inspect the keyboard event and decide whether we should handle the event instead of XTerm.js. But that's not an easy question to answer in the hypothetical! The most reliable way to answer that question for sure is to call
atom.keymaps.handleKeyboardEvent— but that actually handles the event! We're not trying to replace or preempt Pulsar's keyboard handling; we're just trying to tell XTerm.js whether to swallow the event or let it propagate to us, at which point keyboard handling will proceed. If we actually callhandleKeyboardEventfor an event that would trigger a Pulsar command, it'll end up getting triggered twice.(You might think: “Just handle it manually, then tell XTerm.js to swallow it!” Yet that will still result in two triggers for those bindings that don't match any XTerm.js control sequences. We get a bite at the apple before we know if the event represents a key binding with special meaning in a terminal — so if it tries to handle it and strikes out, the event propagates to us anyway, and Pulsar will respond once again to an event that we impatiently handled before its time.)
The best way to fix this would be to have a “dry run” mode for
handleKeyboardEvent, or else to split the logic inhandleKeyboardEventinto two methods — one for identifying the match or matches for a given keyboard event, and another to actually invoke them.What benefits does this feature provide?
Introspection is good! It gives us the flexibility we need for the
terminalscenario described above.Any alternatives?
The alternative is to reimplement a lot of
atom-keymap's logic in pieces. For instance, I can use the keyboard event to get a list of matching keybindings, but I must then do some of the work thathandleKeyboardEventwould do: crawling up the DOM tree to winnow the matches based on their CSS selectors. This is duplication of effort and will only diverge from the true implementation inatom-keymapover time if we need to tweak it.Other examples:
I'm sure VS Code has a similar problem to our
terminaldilemma, since it uses bothnode-ptyand XTerm.js. But I haven't researched how they handle it. That research might give us some insight into heuristics for deciding whether a user meant to invoke a terminal binding or a Pulsar binding, but it seems unlikely that it would help with this specific problem.