Skip to content

Commit

Permalink
Document a tip for improved Insert Mode mappings for ESC
Browse files Browse the repository at this point in the history
As discussed at length in issue atom#334, mapping double characters to ESC
is a common Vim pattern (e.g, 'jj' or 'jk'). Atom supports this style of
mapping, but the editor behavior is inconsistent with Vim in that the
initial characters that partially match a mapping are not displayed on
screen. This is jarring to the user.

This PR adds documentation to the README that describes a two-step
approach to mapping ESC that removes the delay from the editor and much
more closely imitates Vim's behavior.

This issue exists today in Atom 1.3.2. A future update to Atom may
change the behavior of
[KeymapManager](https://atom.io/docs/api/v1.3.2/KeymapManager) so that
partial matches are displayed. Work in this area was most recently done in
[PR atom#94 on atom-keymap](atom/atom-keymap#94).

I considered adding this info to the Wiki, but the project doesn't
currently have one, so I figured the README was the next-best place.
  • Loading branch information
rdlugosz committed Jan 7, 2016
1 parent c5f64c1 commit 1fc3302
Showing 1 changed file with 42 additions and 0 deletions.
42 changes: 42 additions & 0 deletions README.md
Expand Up @@ -23,6 +23,48 @@ which works in conjunction with this plugin.

Currently, vim-mode has some issues with non-US keyboard layouts. If you are using a keyboard layout which *isn't* American and having problems, try installing [keyboard-localization](https://atom.io/packages/keyboard-localization).

#### Double-key Keymaps in Insert Mode

Because the letter keys are typically used to insert characters into the buffer in Insert Mode, binding key combinations like `jj` or `jk` to stand in for `ESC` can be tricky. For example, while the following mapping in `keymap.cson` file will work, you'll notice that the first character doesn't appear on screen until another key is pressed or the keymap wait delay expires (see [KeymapManager::partialMatchTimeout](https://atom.io/docs/api/v1.3.2/KeymapManager)).

```coffeescript
# This works, but the delay in seeing the first character appear
# is inconsistent with Vim and can be jarring to the user.
'atom-text-editor.vim-mode.insert-mode':
'j k': 'vim-mode:activate-normal-mode'
```

An alternative approach proposed in [issue #334 "Remapping ESC"](https://github.com/atom/vim-mode/issues/334#issuecomment-85603175) requires slightly more configuration, but emulates Vim's behavior and eliminates the delay. First, define a function in `init.coffee` which activates Normal Mode if the character immediately before the cursor is the _first_ character in our desired keymapping:

```coffeescript
# init.coffee
atom.commands.add 'atom-text-editor', 'activate-normal-mode-if-preceded-by-j': (e) ->
targetChar = "j" # This should be the FIRST char in your desired mapping
editor = @getModel()
pos = editor.getCursorBufferPosition()
range = [pos.traverse([0,-1]), pos]
lastChar = editor.getTextInBufferRange(range)
if lastChar is targetChar
editor.backspace() # remove the 'j' character from the buffer
atom.commands.dispatch(e.currentTarget, 'vim-mode:activate-normal-mode')
else
e.abortKeyBinding()
```

Now, we just need to bind a single key (the _second_ character in our desired mapping) to the command we just created:

```coffeescript
# keymap.cson
# Bind 'jk' to ESC. Specifically, while in Insert Mode, bind 'k' to a function defined
# in init.coffee that activates Normal Mode if the character immediately before the cursor is 'j'.
'atom-text-editor.vim-mode.insert-mode':
'k': 'activate-normal-mode-if-preceded-by-j'
```

This technique can be adapted to any combination of two keys, such as `jj`, `jk` or—better yet—`kj` (as [Dijkstra](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm) surely would have preferred!) _Note that changes to your `init.coffee` are only picked up upon restarting Atom._

_Caveat:_ In order to enter the mapped characters into a buffer (e.g., typing 'Dijkstra' above), you must first enter those characters separated by a space and then then delete it. This is inconsistent with Vim's behavior, but fortunately it very rarely happens outside of writing documentation about this specific feature!

### Development

* Create a branch with your feature/fix.
Expand Down

0 comments on commit 1fc3302

Please sign in to comment.