Skip to content

Instantly share code, notes, and snippets.

@sstirlin
Last active March 19, 2025 09:34
Show Gist options
  • Save sstirlin/c3c207b1052b613ab9554b4ebdfc3f35 to your computer and use it in GitHub Desktop.
Save sstirlin/c3c207b1052b613ab9554b4ebdfc3f35 to your computer and use it in GitHub Desktop.
vim bindings for IPython

As of IPython 5, readline is no longer used to interpret keystrokes.
Instead, the pure-python library prompt_toolkit is used.

Getting vim mode in IPython is straightforward. First, edit

~/.ipython/profile_default/ipython_config.py

and add the following line:

c.TerminalInteractiveShell.editing_mode = 'vi'

For custom keybindings, create a new file

~/.ipython/profile_default/startup/keybindings.py

and put this code in (this remaps jk to Esc):

from IPython import get_ipython
from prompt_toolkit.enums import DEFAULT_BUFFER
from prompt_toolkit.filters import HasFocus, ViInsertMode
from prompt_toolkit.key_binding.vi_state import InputMode


ip = get_ipython()

def switch_to_navigation_mode(event):
    vi_state = event.cli.vi_state
    vi_state.reset(InputMode.NAVIGATION)

if getattr(ip, 'pt_cli'):
    registry = ip.pt_cli.application.key_bindings_registry
    registry.add_binding(u'j',u'k',
                         filter=(HasFocus(DEFAULT_BUFFER)
                                 & ViInsertMode()))(switch_to_navigation_mode)

For notebooks, you can enable vim mode by installing this plugin https://github.com/lambdalisue/jupyter-vim-binding

@omoindrot
Copy link

This is not working anymore with newer version of ipython, see here for an updated code: https://ipython.readthedocs.io/en/stable/config/details.html#keyboard-shortcuts

@itaranto
Copy link

itaranto commented Nov 24, 2020

This is not working anymore with newer version of ipython, see here for an updated code: https://ipython.readthedocs.io/en/stable/config/details.html#keyboard-shortcuts

It does work for me. I''m using IPython 7.18.1.

@casio
Copy link

casio commented May 15, 2021

For me, using ipython 7.23.1, this does the trick(in eg. ~/.ipython/profile_default/startup/keybindings.py):

from IPython import get_ipython
from prompt_toolkit.enums import DEFAULT_BUFFER
from prompt_toolkit.filters import HasFocus, ViInsertMode
from prompt_toolkit.key_binding.vi_state import InputMode

def switch_to_navigation_mode(event):
    event.cli.vi_state.input_mode = InputMode.NAVIGATION

get_ipython().pt_app.key_bindings.add_binding(
    u"j", u"k", filter=(HasFocus(DEFAULT_BUFFER) & ViInsertMode())
)(switch_to_navigation_mode)

@Paul-Aime
Copy link

Paul-Aime commented Feb 17, 2022

@casio solution still works for IPython 8.0.1.

Just a little addition using decorators to easily write multiple keybindings:

# ...
from functools import partial

keybindings = IPython.get_ipython().pt_app.key_bindings

vi_navigation_mode_keybinding = partial(keybindings.add, filter=HasFocus(DEFAULT_BUFFER) & ViNavigationMode())
vi_insert_mode_keybinding = partial(keybindings.add, filter=HasFocus(DEFAULT_BUFFER) & ViInsertMode())

@vi_insert_mode_keybinding("k", "k")
def switch_to_navigation_mode(event):
    event.cli.vi_state.input_mode = InputMode.NAVIGATION

@dvths
Copy link

dvths commented Aug 1, 2023

Hello, guys!

This topic was very helpful for me! However, I recently updated my environment, and in ipython 8.14, the 'pt_app' member is unknown ("Cannot access member 'pt_app' for type None").
I tried searching the documentation, but it seems that this part has not been updated yet (at least as far as I could dig). Also, I haven't been able to find anything in the source code that could help me...
I have been using C-[ as a workaround, but I'm really annoyed by having to type "jk" every time unintentionally :/
Do you happen to know how I can work around this issue?

@Paul-Aime
Copy link

@dvths I do have the same but it's just a linter warning. It says type None because the actual upstream warning is "get_ipython" is not exported from module IPython.

Does it raise an error for you?

@pritamdodeja
Copy link

Does anybody know how to enable vim bindings for jupyter console? ipython cannot (per my understanding) connect to an existing kernel, whereas jupyter console can. Thanks!

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