:rocket: This library will add Vim motions and operators to all your input fields on OS X. Why should Emacs users have all the fun?
Not all motions or operators are implemented, but you can open an issue if you're missing something.
The plugin will not work with system inputs marked as secure, such as password fields or anything in 1Password, as it can't read those fields!
Run this command in Terminal:
bash <(curl -s https://raw.githubusercontent.com/dbalatero/VimMode.spoon/master/bin/installer)
then read the post-install info printed at the end and follow the instructions.
Once installed:
To update the plugin, run:
cd ~/.hammerspoon/Spoons/VimMode.spoon && git pull
There are two flavors of Vim mode that we try to enable using feature detection.
Advanced mode gets turned on when we detect the accessibility features we need to make it work. If the field you are focused in:
contentEditable
rich field in the web browser, I'm not touching that with a 10-foot poleIn advanced mode, we actually can read in the value of the focused field and modify cursor position/selection with theoretical perfect accuracy. In this mode, I strive to make sure all Vim motions are as accurate as the editor. I'm sure they are not, though, and would appreciate bug reports!
In fallback mode, we just map Vim motions/operators to built-in text keyboard shortcuts in OS X, and fire them blindly. This works pretty well, and is how the original version of this plugin worked. There is some behavior that doesn't match Vim however, which we cannot emulate without having the context that Advanced Mode gives.
0
- beginning of line$
- end of linef<char>
F<char>
t<char>
T<char>
:h WORD
):h WORD
)gg
- top of bufferhjkl
- arrow keys:h WORD
)iw
- in wordi'
- in single quotesi(
- in parensi{
- in bracesi<
- in angle bracketsi`
- in backticksi"
- in double quotescc
- delete line and enter insert modedd
- delete liner<char>
to replace - currently broken^r
to redocmd+f
search (when cmd+f
is supported in app)^d
- page down^u
- page down2dw
)Here are all the configuration options available for you. Add/edit your config
in ~/.hammerspoon/init.lua
.
local VimMode = hs.loadSpoon('VimMode')
local vim = VimMode:new()
vim:enterWithSequence('jk')
This sequence only watches for simple characters - it can't handle uppercase
(enterWithSequence('JK')
) or any other modifier keys (ctrl, shift). This is
meant to handle the popularity of people binding jj
, jk
, or kj
to
entering normal mode in Vim.
The sequence also times out by default after 140ms
- if you type a j
and
wait for the timeout, it will type the j
for you. You can control the timeout like so:
-- timeout after 100ms instead. this is a nicer default for `jk`, but needs to
-- be more like 140ms for `jj` to be caught quickly enough.
vim:enterWithSequence('jk', 100)
If you have a sequence of jk
and you go to type ja
it will immediately
pass through the ja
keys without any latency either. I wanted this to work
close to inoremap jk <esc>
.
-- Basic key binding to ctrl+;
-- You can choose any key binding you want here, see:
-- https://www.hammerspoon.org/docs/hs.hotkey.html#bind
vim:bindHotKeys({ enter = {{'ctrl'}, ';'} })
Some apps work best in fallback mode. To force fallback mode for these apps, do:
local VimMode = hs.loadSpoon('VimMode')
local vim = VimMode:new()
-- Dwarf Fortress needs to use fallback mode :)j
vim:useFallbackMode('dwarfort.exe')
-- same w/ Chrome
vim:useFallbackMode('Google Chrome')
You probably want to disable this Vim mode in the terminal, or any actual
instance of Vim. Calling vim:disableForApp(...)
allows you to disable or
enable Vim mode depending on which window is in focus.
local VimMode = hs.loadSpoon('VimMode')
local vim = VimMode:new()
-- sometimes you need to check Activity Monitor to get the app's
-- real name
vim:disableForApp('Code')
vim:disableForApp('iTerm')
vim:disableForApp('MacVim')
vim:disableForApp('Terminal')
local VimMode = hs.loadSpoon('VimMode')
local vim = VimMode:new()
vim:shouldShowAlertInNormalMode(false)
This turns on a Flux-style dim when you enter normal mode.
local VimMode = hs.loadSpoon('VimMode')
local vim = VimMode:new()
vim:shouldDimScreenInNormalMode(true)
There are a few beta features you can try out right now and give feedback on:
This adds an experimental block cursor on top of the current character, to emulate what it looks like in Vim. This only works in fields that support Advanced Mode.
To enable:
vim:enableBetaFeature('block_cursor_overlay')
Discussed in: #63
Some websites just really need to be forced into fallback mode at all times, and the detection we have isn't good enough to do so. This may be deprecated going forward in favor of getting better field detection or handling rich fields better.
This currently only works for Chrome and Safari, as Firefox has a trash AppleScript interface.
To enable:
vim:enableBetaFeature('fallback_only_urls')
-- When entering normal mode on any URL that matches any of the patterns below,
-- we will enforce fallback mode.
vim:setFallbackOnlyUrlPatterns({
"docs.google.com",
})
Discussed in: #71
Install Hammerspoon
Next, run this in your Terminal:
mkdir -p ~/.hammerspoon/Spoons
git clone https://github.com/dbalatero/VimMode.spoon \
~/.hammerspoon/Spoons/VimMode.spoon
Modify your ~/.hammerspoon/init.lua
file to contain the following:
local VimMode = hs.loadSpoon('VimMode')
local vim = VimMode:new()
vim
:disableForApp('Code')
:disableForApp('MacVim')
:disableForApp('zoom.us')
:enterWithSequence('jk')
There are unit tests and integration tests!
To run the unit tests:
cd VimMode.spoon
bin/dev-setup
busted spec
To run the integration tests, there is a bit of setup, which you can read
about in the docs/Integration_Tests.md
document. However, once you setup,
it should just be:
bundle exec rspec spec