Search code examples
pythonvimterminal-emulator

Sending input to embedded terminal in vim


In my .vimrc file I have included the following line:

autocmd vimenter * botright term

This means that, whenever vim starts, it will open a terminal at the bottom-right. I would like to create a key-mapping that makes vim run a given, dynamically-generated command at the terminal. For example, I have added the following to my .vimrc file:

nmap <leader><leader> <C-w><C-w>python my_python_file.py<CR><C-w><C-w>

So if I am editing a file called my_py_file.py, I can press <leader><leader> and vim will first change windows (changing to the embedded terminal), then enter the command

python my_python_file.py

so that the file will run in python, and finally change back to the other window so that I can continue editing. This works! But I would like it to work for arbitrary files, not just for files that are named my_python_file.py. How can this be accomplished?

I have thought about using expand('%:p') to get the full path of the current file, but I have not been able to pass this string to the embedded terminal window as input. I have tried writing a function to accomplish this, but with no success.


Solution

  • The key is to use map <expr> <leader><leader> ... so that <leader><leader> can be mapped to a dynamically-generated binding. The below code snippet from a .vimrc file works with Vim 8.0:

    " open a terminal directly below current window
    nnoremap <leader>t :split<cr><c-w><c-j>:terminal ++curwin<cr><c-w><c-k>
    " save current file and run python on it in terminal window directly below
    nnoremap <expr> <leader><leader> ':w<cr><c-w><c-j>python ' . expand('%:p') . '<cr><c-w><c-k>'
    

    This maps <leader>t to open a new terminal buffer, and <leader><leader> to run python in that terminal buffer. Note that the terminal stays in Terminal-Job mode the whole time.

    Slight modification will be needed for this to work with NeoVim:

    " open a terminal directly below current window
    nnoremap <leader>t :split<cr><c-w><c-j>:terminal<cr><c-w><c-k>
    " save current file and run python on it in terminal window directly below
    nnoremap <expr> <leader><leader> ':w<cr><c-w><c-j>ipython ' . expand('%:p') . '<cr><c-\><c-n><c-w><c-k>'
    

    In the NeoVim version, we must change from Terminal-Normal mode to Terminal-Job mode before passing input to the terminal, and then return to Terminal-Normal mode.