I have a command:

command! -nargs=1 TmuxSession !tmux.session "<args>"

and I want to run it in visual mode so that selected text will be passed as argument.
By selected text I mean selected in visual mode in vim.

How can I achieve that?

I tried running

command -nargs=1 -range -register TmuxSession !tmux.session "<args>"

but it keeps saying E471: Argument required

I know about using <C-r>" to paste an argument and that is how I use the upper command at the moment, but I don't want to copy selection and paste it every time to the command, because this can be done faster using range.


Following solution does not work:

function! PrintRange() range
    echo getline(a:firstline, a:lastline)

command! -range PassRange <line1>,<line2>call PrintRange()

because when I want to select second and third word from line containing one two three - I get the whole line (obviously).

I need to pass only the selected part of the text.



3 Answers 3


See this answer on stackoverflow.

The example given is:

 function! PrintGivenRange() range
     echo "firstline ".a:firstline." lastline ".a:lastline
     " Do some more things

 command! -range PassRange <line1>,<line2>call PrintGivenRange()

Thus you might want to create a function which would use the range and do the tmux call you want.

In your function, to get the text in the range you can use the getline() function which will take a:firstline and a:lastline as parameters and return the text in the buffer between theses lines. You can have a look at :h getline() or :h getbufline().

Edit If you want to get the text characterwise and not linewise you'll have to play with the marks. This edit is inspired from this SO answer.

So when you call you command with :'<,'>PassRange the marks '< and '> are set. The doc :h '< tells us that these marks are used to describe the last visual selection.

Your function would need to look like this:

function! PrintGivenRange() range
    " Get the line and column of the visual selection marks
    let [lnum1, col1] = getpos("'<")[1:2]
    let [lnum2, col2] = getpos("'>")[1:2]

    " Get all the lines represented by this range
    let lines = getline(lnum1, lnum2)         

    " The last line might need to be cut if the visual selection didn't end on the last column
    let lines[-1] = lines[-1][: col2 - (&selection == 'inclusive' ? 1 : 2)]
    " The first line might need to be trimmed if the visual selection didn't start on the first column
    let lines[0] = lines[0][col1 - 1:]

    " Get the desired text
    let selectedText = join(lines, "\n")         

    " Do the call to tmux
    execute "!tmux.session " . selectedText 
  • Thanks, but I've seen this answer and it is not helpful. The return of this echo is giving me line numbers but I need to use the actual selection content.
    – lewiatan
    Commented Jan 18, 2017 at 14:10
  • @lewiatan in your function you can then use functions like getline() or getbufline() for example to get the content of your buffer between these lines. See :h getline() or :h getbufline()
    – statox
    Commented Jan 18, 2017 at 14:14
  • it is better now, but I still think that's not it. There must be a better way to get the selection.
    – lewiatan
    Commented Jan 18, 2017 at 14:29
  • @lewiatan Let's way for an answer which better fits your needs then :)
    – statox
    Commented Jan 18, 2017 at 14:32
  • 1
    @lewiatan I think I understand better what you want now. Have a look at this one you called your command with the range '<,'> you can play with getpos() to get the exact position of the mark on the line and thus the code.
    – statox
    Commented Jan 18, 2017 at 14:58

you can also adapt this one liner

command -range TmuxSession execute "!tmux.session " . @*

or if you do need multiline visual selection change @* to substitute(@*,"\n"," ","g")

The @* register stores current selection (for linux, on windows there could be different naming convention).

The -range is only to avoid an error if you want to execute this command with range marks, i.e. '<,'>TmuxSession.

  • I did not express myself specific enough. What I meant was the text that is selected in visual mode, but this is also useful.
    – lewiatan
    Commented Jan 19, 2017 at 8:04

You can also copy the part you want to use and use <C-r>" to paste it. For example, if you want to run myCommand like feh, firefox etc on a the line :map mapping Vy:!myCommand <C-r>"<Cr>

  • 1
    Welcome to Vi and Vim! Thanks for trying to help, but I'm not sure this answers OP's question very well.
    – D. Ben Knoble
    Commented Mar 28, 2020 at 19:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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