I'm reformatting an XML document with an external command from a vimscript function which accepts a range, and I need the cursor to stay at the same line it was before the reformatting. When trying to save the current cursor line number with line('.') or getpos('.'), the line number is always '1' and restoring it makes no sense. Any idea? Here is the functionL

" formats the XML source
function s:DapsXmlFormat() range
  " save the current cursor position as a mark
  let winview = winsaveview()
  " check if the current buffer is valid
  if s:DapsValidateFile() == 0
    let indent_size = indent(a:firstline) / shiftwidth()
    let cmd = '!' . b:xmlformat_script . ' -f ' . b:xmlformat_conf
    silent execute(a:firstline.','.a:lastline.cmd)
    if a:firstline > 1 && a:lastline < line('$')
      " re-indent the visual block
      let repeat = repeat(">", indent_size)
      " a:lastline is probably not valid anymore after re-formatting, need
      " matchit's % to mark the vusual block correctly
      silent execute("normal lV%" . indent_size . ">")
  " go back to the saved cursor position
  call winrestview(winview)

1 Answer 1


As :h :func-range says,

            When the [range] argument is added, the function is
            expected to take care of a range itself.  The range is
            passed as "a:firstline" and "a:lastline".  If [range]
            is excluded, ":{range}call" will call the function for
            each line in the range, with the cursor on the start
            of each line.  See |function-range-example|.
--->        The cursor is still moved to the first line of the
--->        range, as is the case with all Ex commands.

Hence, you must save the view before ranged function/command. For example,

command! -nargs=+ -complete=command Nomove call misc#nomove(<q-args>)
function! misc#nomove(cmd) abort
    let l:pos = winsaveview()
    try | return execute(a:cmd, '')
        call winrestview(l:pos)
:Nomove 10,20call Foobar(...)

The alternative is simply to jump back with "double backqoute" (which restores the cursor position but not other view parameters).

  • I set that on my computer and get: E481: No range allowed
    – john-jones
    Commented Feb 9, 2023 at 16:55

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.