Skip to content

Instantly share code, notes, and snippets.

@sstirlin
Last active April 3, 2024 16:35
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • 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?

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