I know there'a probably a plugin for that, but since Neovim has a built-in terminal I wanna use it. I just want to bind a key that runs the current file in Python 3. I tried using @% and %, but the shell does not recognize these variables. I think the best way would be to export the current file path as an environment variable, and make use it on the terminal. How can I do that?
I am myself pretty new to vim in general, but I guess you can easily do this. Here is my version of it, which will create a horizontal split, create a terminal buffer and then run the current python file in it and then you can create a another mapping which can close the terminal buffer for you.
nnoremap <C-R> :sp <CR> :term python % <CR> nnoremap <C-W> :bd!<CR>
The best solution for me:
" Create a function to open a neovim terminal in a small split window and run python function! Termpy() exec winheight(0)/4."split" | terminal python3 % endfunction
Then use the solution above to map it to your prefered key combination:
" Press CTRL+R to run python script into separate term window nnoremap <C-R> :call Termpy() <CR>
Other cool things you can do is:
Use a command like :Pyrun
command Pyrun execute ":w<CR>:vert ter python3 "%"<CR>"
Use leader + p to save and run the script
map <leader>p :w<CR>:!python3 %<CR>
python2 and python3 are different,so change it for your projects or you can create different functions
It seems others have missed the fact that your workflow is to have a persistent terminal already open below your file, and you want to access the filename from inside your terminal.
I wrote a plugin that handles this by jumping to the regular file, grabbing the filename, and jumping back. In case you don't want to install it, I post the relevant script contents so you can copy that into your vimrc. Finally, a third way is in line with what you suggest, setting the filename every time you visit a buffer, so that it is already ready when you need it.
Method 1: Install and use vim-termhere
With vim-termhere installed, a binding such as the one suggested in the readme in your vimrc, and a split terminal below your code active in normal mode, you can do
<leader>cf to paste the filename relative to the working dir*, or
<leader>cF to paste the full filename.
*the working dir is not necessarily the same as the terminal's directory. To synchronise either way, you can use vim-dirhere. With the readme's suggested bindings,
<leader>qq in normal mode with the cursor on a terminal status line (
username@hostname:~/some/dir $ ) will set the working dir to
If anything fails, please open an issue on the relevant plugin.
Method 2: Copy some vimscript
If you don't want to install plugins, you can instead copy this and then use
function! termhere#JumpToTerminalBuffer() abort if &buftype ==# 'terminal' return endif let l:first_window_number = winnr() while v:true execute "wincmd W" if &buftype ==# 'terminal' return endif if winnr() == l:first_window_number break endif endwhile throw "Unable to find terminal window in current tab" endfunction function! termhere#JumpToNormalBuffer() abort if &buftype !=# 'terminal' return endif let l:first_window_number = winnr() while v:true execute "wincmd W" if &buftype !=# 'terminal' return endif if winnr() == l:first_window_number break endif endwhile throw "Unable to find non-terminal window in current tab to copy filename from" endfunction function! termhere#UseAbsoluteFilenameInTermBelow(prefix, ...) abort if &buftype ==# 'terminal' call termhere#JumpToNormalBuffer() endif let l:postfix = get(a:, 1, '') let l:filename = expand('%:p') call termhere#JumpToTerminalBuffer() call feedkeys('a' . a:prefix . l:filename . l:postfix) endfunction function! termhere#UseRelativeFilenameInTermBelow(prefix, ...) abort if &buftype ==# 'terminal' call termhere#JumpToNormalBuffer() endif let l:postfix = get(a:, 1, '') let l:filename = bufname('%') call termhere#JumpToTerminalBuffer() call feedkeys('a' . a:prefix . l:filename . l:postfix) endfunction nnoremap <Leader>cf :call termhere#UseRelativeFilenameInTermBelow('')<CR> nnoremap <Leader>cF :call termhere#UseAbsoluteFilenameInTermBelow('')<CR>
Method 3: keeping track of the last filename
Although your suggestion to set an environment variable is not necessary, it is possible, and perhaps using a global may be better if you have some other setup than 'a single terminal below a single file':
First, ensure that g:last_regular_file_buffer has the last regular file name in it:
function! UpdateLastFile() abort if &buftype ==# 'terminal' || bufname('%') ==# '' return endif let g:last_regular_file_buffer = bufname('%') endfunction augroup LastRegularFileBuffer autocmd! autocmd BufEnter * call UpdateLastFile() augroup END
Next, let's set up a keybinding to insert the filename.
function! InsertLastFilename() abort call feedkeys('a ' . g:last_regular_file_buffer) endfunction tnoremap <C-f> <c-\><c-n>:call InsertLastFilename()<CR>
Actually using an environment variable instead of a global, while possible, won't work the way you'd expect because a terminal external to neovim will need to be restarted to see changes to the global environment. If necessary, an external terminal can ask the current neovim instance for a value, but that is a whole different question.