0

Initial window:

vim opened first,then vert term split the left window

My expectation: to copy whole or a part of python code in the right window into the left window's python terminal and execute.

My .vimrc setting:

function! CopyPasteBuffer() 
    normal  gg"*yG
    wincmd p
    call feedkeys("\<C-W>\"*")
endfunction
nnoremap <leader>pp  :call CopyPasteBuffer()<CR>

function! CopyRun() range
    exe  a:firstline . "," . a:lastline . "y*"
    wincmd p
    call feedkeys("\<C-W>\"*")
endfunction
command! -range PassRange <line1>,<line2>call CopyRun()
nnoremap ,pr :CopyRun<cr>

In vim's normal mode in the right window, I type ,pp (leader configured as ,), all python statements in the right pushed into python terminal in the left and executed.

enter image description here

Now I want to execute a range of python statements in the right, move cursor in the right window and enter into ex mode, and type 1,3pr, the lines are executed but not in my desired python terminal such as the above image shows.

How to fix my vimscript?

After following Maxim Kim's suggestion,1,3PassRange works, I rewrite the mapping as nnoremap ,pr :PassRange<cr>, why can't 1,3pr get the same effect as 1,3PassRange?

enter image description here

Following Maxim Kim's instruction, I want to make more progress, toggle from uppercase to lowercase and from lowercase to uppercase, it is inconvenient.

Without range as argument:

nnoremap <leader>pp  :call CopyPasteBuffer()<CR>

I can type ,pp without uppercase to get desired result.
With range as argument:

command! -range  Xr <line1>,<line2>call CopyRun()

1,3Xr can work,i want to make ,1,3re map as 1,3Xr and call CopyRun,so add new mapping

map <leader>,re :Xr<cr>

It can't work, how to fix it?

2
  • I use :call term_list()[0]->term_sendkeys(getline('.') .. "\<CR>") to send current line to a terminal window.
    – balki
    Commented Mar 13, 2023 at 22:51
  • Function using term_sendkeys: balki.me/posts/vim-stt
    – balki
    Commented Aug 7, 2023 at 23:59

2 Answers 2

1

You have to create a vim command that process the range and you actually have it in your code snippet: PassRange

So try :1,3PassRange

When you do :1,3pr you run builtin print ex command to print lines in range (See :h :pr).

You can't use normal mappings as an ex commands like you tried to do.

Shorten your :PassRange command to :Pr:

 command! -range Pr <line1>,<line2>call CopyRun()

And run it with :1,3Pr.

7
  • I rewrite the mapping as nnoremap ,pr :PassRange<cr>,why 1,3pr can't get the same effect as 1,3PassRange?
    – showkey
    Commented Feb 17, 2021 at 8:49
  • 1
    @showkey, because mapping is not an ex command. You can't use it like this.
    – Maxim Kim
    Commented Feb 17, 2021 at 9:36
  • @showkey rename PassRange to Pr and use it like :1,3Pr
    – Maxim Kim
    Commented Feb 17, 2021 at 9:37
  • Please help make a little progress to use all lowercase characters ,i map as nnoremap ,re :Xr<cr>,why 1,3re can't work?
    – showkey
    Commented Feb 17, 2021 at 10:44
  • @showkey you should definitely read about vimscript, mappings, commands somewhere... probably in vim user manual or some book. You are mixing mappings and user commands. Mappings do not work the same way as user commands. User commands can not start with lowercase letters. It is in vim help and user manual.
    – Maxim Kim
    Commented Feb 17, 2021 at 10:46
0

It can't work, how to fix it?

Everything is working as designed so there is nothing to fix. What you want to do is impossible to achieve with Vim as it currently works. Get over it.

Basically, built-in normal mode commands (like ~ or w) and custom normal mode mappings (like your ,p) can take a positive count (2~, 4w, 6,p, etc.) but not a range (like 1,3~ or 5,13,p). You can't insert an arbitrary range in the middle of a mapping either (like the ,1,3p you are giving as example). 5,13,p would be too ambiguous and ,5,13p is simply not possible.

Now, you could work around that limitation by simply creating lots and lots of explicit mappings for every possible range:

map <leader>1,2re :<C-u>1,2Xr<cr>
map <leader>1,3re :<C-u>1,3Xr<cr>
map <leader>1,4re :<C-u>1,4Xr<cr>
" etc.

This is not very elegant but it will work, in a dumb way, and can be generated in a loop if you want.

Another possibility is using your mapping in visual mode:

vjjj,p

which should pass the range <','> to your custom Ex command :Xr.

Another possibility would be to prompt the user for a range via :help input() and then feed it to the underlying commands/functions.

Not the answer you're looking for? Browse other questions tagged or ask your own question.