Vi and Vim Stack Exchange is a question and answer site for people using the vi and Vim families of text editors. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

In Mac OS, I am trying to write a function that will say the current paragraph without moving the cursor, but something doesn't seem to work. This is what I have so far:

function! SayIt()
    let l:line = line(".")
    let l:col  = col(".")
    execute "normal V"
    execute "silent '<,'>w !say"
   call cursor(l:line,l:col)

vnoremap <leader>v :call SayIt()<cr>

If I remove the execute "normal V" line the function works when I have previously selected a paragraph (or rather a long soft wrapped line). What am I doing wrong?

share|improve this question
What do you mean when you say the function doesn't work? What happens? Four things that occur to me: 1) you can only use the map from visual mode, because you create no mappings for other modes, 2) calling the function from visual mode, you may want to do execute "normal V:!say", or else escape visual mode before the second execute, because in visual mode, '< moves to beginning of the last visual selection, not the current, 3) normal V will select a line, not a paragraph–consider vip, and 4) the irony of "silent ... !say" ;) – jjaderberg Feb 22 at 20:25
I know it doesn't answer your question, but I think Vim automatically puts the marks '{ and '} around the current paragraph, so if you define the mapping nnoremap <silent> <leader>v :<C-U>silent! '{,'}w !say<CR> and hit <leader>v in normal mode, the contents of the current paragraph should be written on the standard input of the say program. – saginaw Feb 22 at 20:26
jjaderberg, you are right, one of the issues was the mapping. Yes, what an irony silent ... !say. saginaw, thank you very much. This solution worked great without the need of a function. – Amaru Feb 22 at 20:53
up vote 3 down vote accepted

Your selection is being made with the V command, so your '<,'> marks are just set to that line.

Try to select the paragraph with the ip motion after going into visual mode, then the range will be what you want.

The executes are unnecessary. Also that cursor stuff isn't the way the pros do it. :)

function! SayIt()
    let l:winview = winsaveview()
    normal Vip
    silent '<,'>w !say
    call winrestview(l:winview)
share|improve this answer
Thank you. I keep learning great stuff here. This function works, but with some unexpected results. It seems to select, randomly the previous or the current paragraph. – Amaru Feb 22 at 20:49
Paragraphs are demarcated by blank lines, so if you have spaces on lines in between paragraphs they'll be treated as if there isn't a paragraph break. Otherwise I'm not familiar with what you're reporting, ip should select the containing paragraph if you're in one and the next paragraph if you aren't in one. – dash-tom-bang Feb 22 at 20:51

Thank you for your help. In terms of functions, I think that the one posted by dash-tom-bang is the closest solution. But I have opted for the mapping suggested by saginaw.

nnoremap <silent> <leader>v :<C-U>silent! '{,'}w !say<CR>

It works without the function.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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