Vim mode in REPL command line

After trying out vim-slime I went with Slimux. IIRC I found it easier. My relevant init.vim block (still a bit ‘experimenting’ though):

""" slimux

" REPL
map <leader>sl :SlimuxREPLSendLine<cr>
map <leader>sd :SlimuxREPLSendLine<cr>j
vmap <leader>sl :SlimuxREPLSendSelection<cr>
nmap <leader>sp vip:SlimuxREPLSendSelection<cr><esc>
map <leader>sb :SlimuxREPLSendBuffer<cr>
map <leader>sc :SlimuxREPLConfigure<cr>

" shell
map <leader>ssp :SlimuxShellPrompt<cr>
map <leader>ssl :SlimuxShellLast<cr>

" julia
map <leader>sjd :call SlimuxSendCode("@doc " . expand("<cword>") . "\n")<cr>
" map <leader>sje :call SlimuxSendCode("@edit " . expand("<cword>") . "\n")<cr>
map <leader>sji :call SlimuxSendCode(expand("<cword>") . "\n")<cr>
map <leader>sjm :call SlimuxSendCode("methods(" . expand("<cword>") . ")\n")<cr>
2 Likes

Back on the original question, if I’m understanding it correctly: I’ve been
using jupyter console for this purpose (vi-like keybindings in a julia REPL) for
a while now, and it works well enough in general. Still quite a few rough edges.
Anyway, I have this line in my .bashrc if it’s useful to anyone else:

alias iju='jupyter console --ZMQTerminalInteractiveShell.editing_mode=vi \
           --kernel=julia-compiled-0.6'

If you haven’t created any special kernels, you’d just change it to
--kernel=julia or maybe --kernel=julia-0.6 I think (check with jupyter kernelspec list).

2 Likes

Just wanted to post this your solution @non-Jedi
You can also add this to your config:

> cat .jupyter/jupyter_console_config.py
c.ZMQTerminalInteractiveShell.editing_mode='vi'

However, I think it’s not comparable to the real Julia REPL experience :wink: (e.g. things like @edit(1+2) simply hang forever)

I realize this thread is quit old, but I have the same question as the OP more than two years later. Has anything changed? I’m curious if anyone has tried/started implementing vim bindings for the Julia REPL…

6 Likes

short update after juliacon 2022 and the Julia REPL mastery workshop.
You can customize your keybindings.
You can find a very basic vim-like navigation keybindings configuration here.
I guess the idea is, since there can be no real normal mode, just append Ctrl to any vim-ish keybinding you would like to have.

3 Likes

I’ve really wanted to have vim bindings in the REPL for a while, and took it upon myself to give it a proper try. I’ve spent some time developing a package which emulates vim bindings in the REPL, it may be of use to some people here. It’s not perfect, but it checks off a lot of the vim basics. I would be very pleased to have feedback, feel free to try it out and to share your thoughts!

Some of the features implemented so far are:

  • Navigating with motions (h j k l)
  • Basic editing (e.g. dw, cw, x)
  • Editing text objects (e.g. diw)
  • Undo/Redo with u and C-r

Some of the bigger pieces I’d like to still tackle are

  • registers, including copy and paste from the system clipboard
  • unicode. The implementation is pretty naive right now and assumes that 1 char = 1 character width, which makes for some odd behavior when dealing with unicode characters.
  • improved documentation

This project started as an exercise in learning Julia way back during the pandemic, and it’s continued to be something I’ve chipped away at since then. Starting at the end of 2022 I began putting in an effort to polish it up, to take it from “a script I hack on” to a piece of software I would really want to use every time I use the Julia REPL. I’ve also been thrilled to have contributions that have really made the package actually usable (thanks @MilesCranmer!)

I do use it daily now - it still has warts and problems, but I find that being able to use my vim muscle memory is worth the occasional issue it causes. It’s progressed to the point where I’m at least comfortable telling people to try it and only being mildly afraid :sweat_smile:

Cheers!

17 Likes

From an external user I will just say that VimBindings.jl is amazing. I use it every day. If you like vim and Julia you should definitely check it out!

4 Likes

Nice! I like it :smiley: I use a lot of ciX where X \in ['(', '"', "[", "{" etc. but for now I am already happy that basic navigation and diw/ciw are working :wink:

1 Like

Those mappings to apply a function to a word in the buffer (methods, I think of typeof also) look amazing.

I’m glad you found it useful!

I’ve created an issue for text objects which are not yet implemented, including those you mentioned

1 Like

Hi @caleb-allen and thanks for the nice package! We 've been talking a bit on zulip https://julialang.zulipchat.com/#narrow/stream/225582-random/topic/neovim.20.60.3Aterm.60.20thoughts about this advancement. Making the devil’s advocate, I think that architecturally it would be more sustainable to put effort on developing a vim plugin that would play well with neovim’s terminal mode and julia REPL. This way not every vim feature would have to be reimplemented, initlal vim configuration would be available and overall it would be more customizable (as every vim plugin). What’s your take on this ?

Interesting discussion, thanks for the link.

My overall impression is that implementing a vim/neovim plugin to run the REPL is a great idea, but is outside of the scope I set out to achieve with VimBindings.jl and not something I’m looking for myself. In my view, vim great for text editing, and the REPL is great for interacting with Julia. Merging the two in a way which is intuitive is more nuanced than running one within the other.

I’ll respond to your Zulip messages here:

It look like the authors are building a thin vim simulating layer on top. This introduces massive implementation overhead since every vim features has to be reimplemented. Moreover all my vim configuration is useless in this term. I still think efforts toward a vim plugin that works well with julia REPL would be more sustainable, powerful and customizable.

I don’t view VimBindings.jl as a full drop in replacement for vim or neovim, or their full set of capabilities, in the same way that vi mode in bash, fish, or zsh are not full vi implementations; I would not expect to convince a hardcore vim user that VimBindings.jl is vim. Instead, my goal is to take ideas from vim and integrate them into the Julia REPL. In other words, I want VimBindings.jl to enhance the Julia REPL with a vim flavor for anyone using the REPL (a “REPL-based” plugin), not to wrap the Julia REPL in vim (a “vim-based” plugin) just for vim users. I use the REPL from many places, not solely through vim. I hope this makes sense.

In zulip you said:

To be fair VimBindings.jl implements history integration and undo/redo functionality which is not readily available in neovim’s term. But the fact that doesn’t mean it’s the best way forward.

Resolving these corner-case problems is, in fact, my main goal. I don’t think that re-implementing every function of vim is particularly valuable, and there may be an approach which negates the need for re-implementing so many features altogether for VimBindings.jl (and I’ll expand on this shortly). What I do think is valuable is a set of vim-like enhancements which is intentionally designed for its context. Enhancements which clear away roadblocks for the user by removing the need for them to think in two paradigms (vim and the REPL), at least as much as is practical.

If we look at marrying vim to the REPL, there are instances where the two designs clash. These questions would need to be solved in both a “REPL-based” plugin as well as a “vim-based” plugin. They also can’t be solved objectively; one must decide which paradigm to favor, or when to ignore both paradigms altogether. To enable a good user experience one must make an opinionated decision. For example:

  • when hitting “Enter” from Normal mode, should the vim mode be Normal or Insert on a new prompt? Vim says no; the user never entered insert mode. VimBindings.jl says yes.
  • when the user finishes entering code in Insert mode and presses Enter, should the text buffer be saved as a part of the “undo” history? In Vim the answer would be no; the user never left insert mode, which is when undo history is saved. VimBindings.jl says yes.
  • what does a “mark” mean in the Julia REPL? Vim doesn’t have an answer, because the REPL is not a text file; vim is a text editor, not a shell. VimBindings.jl says that a vim mark it ought to mean an entry in the REPL history. In other words, a user ought to be able to mark a specific entry and recall it later. (not implemented yet, but something I’d like to do soon)

The point I’m trying to make is that vim is not a REPL, it is a text editor. Thus, features which make sense in vim (undo/redo, marks, newline, etc), lose their meaning or become ambiguous when mapped to a REPL. The value in VimBindings.jl is not just replicating the vim commands on text in a buffer, but specifically doing the work to integrate vim features to the REPL experience in a way which feels coherent. That VimBindings.jl does history and undo/redo well isn’t just an implementation detail; they are precisely the type of problem I’m trying to solve with VimBindings.jl.

That isn’t to say this couldn’t be achieved from the other side, as a “vim-based” plugin. I just believe that implementing it on the REPL makes it accessible from a wider array of users, instead of just being usable within vim. I also think that integrating with the Julia REPL code is best done in pure Julia.

As for the text operations themselves, there may be something to your idea to improve that with neovim. The alternate approach I mentioned earlier is is a route that I explored early on with VimBindings.jl, doing what the vs-code neovim plugin does. That is, embedding neovim under the hood - starting up a neovim instance and then synchronizing the neovim buffer with the REPL contents, and sending key strokes to neovim. I don’t think it would be as simple as wiring up the buffer to neovim, for the design reasons mentioned above (I put together a prototype a few years ago and it was quite fragile). Still, it would be a clearer path to getting nearly all of vim’s functionality including configuration and plugins.

If there was demand for a fully featured vim implementation within the REPL, I think that would be the right way to go. I’ve returned to that idea a few times, it just comes with a whole host of new design questions that I haven’t had time time to look into. I think it’s a pretty daunting task. My only reference is vs-code neovim, which looks anything but trivial.

4 Likes