23

I am trying to code a function that replaces the character in the sixth column of my current line with a dollar symbol ($), but I would like my cursor to remain at the position it was before calling the function.

So I tried to store the current column, execute my changes, and then come back with the following function :

function! DollarSplit()
   let col_number=col(".")     "stores the current column number of the cursor
   normal! 6|r$                " replaces the 6th caracter in line with a $
   execute col_number."|" 
endfunction

I am probably misunderstanding something about the execute command... Or maybe I should create a string containing the command I want to be executed ?

2 Answers 2

31

You should use getpos():

To save you position in a variable:

let save_pos = getpos(".")

getpos() takes as argument a mark, here "." represents the current position of your cursor.

And to restore it:

call setpos('.', save_pos)

Here the first argument indicate that you will move the mark of the current position of your cursor (hence your current position) and the second is where to put the mark (the position that you saved earlier).

Your function would look like this:

function! DollarSplit()
   let save_pos = getpos(".")
   normal! 6|r$                " replaces the 6th caracter in line with a $
   call setpos(".", save_pos)
endfunction

For more details see: :h getpos() and :h setpos()


For more details about your usage of execute: this function will take a string and execute it. Your string can be only hardcoded characters between double quotes or the contents of variables.

When you write

execute col_number."|"

If you are on the 12th column the expanded string will be 12|. Execute will try to execute this command but it won't work because 12| is not a vimscript function but a normal mode command.

To execute it from a vimscript you have to say "execute it as if I had typed it in normal mode`, that's what normal is used for.

So without the execute you would have wrote:

normal 12|

Now to make your execute call work you have to add the normal keyword to your expanded string, like this:

execute "normal " . col_number . "|"
2
  • Thanks for this solution (it is the one I will use), but is there any other way around, using my "col_number" variable ? That would allow me to understand better how execute/normal work.
    – Feffe
    May 12, 2016 at 15:29
  • 1
    @Feffe: My update should clarify this :-)
    – statox
    May 12, 2016 at 15:36
5

This function keeps also your search register. So you can pass your command as argument on it.

if !exists('*Preserve')
    function! Preserve(command)
        try
            " Preparation: save last search, and cursor position.
            let l:win_view = winsaveview()
            let l:old_query = getreg('/')
            silent! execute 'keepjumps' . a:command
        finally
            " try restore / reg and cursor position
            call winrestview(l:win_view)
            call setreg('/', l:old_query)
        endtry
    endfunction
endif

Some explanation

let .......... used to set a variable
l:somevar .... local variable
winsaveview()  get information about window view
winrestview(lwinview) restores window view to its last status
getreg('/')    used to store the last search in a variable
keepjumps      used to performe any change without change jumplis
. a:command    concatenates any given command with keepjumps

For example:

"Reident file without moving cursor position
:call Preserve('normal! gg=G')

"Reindent command using 'Preserve()'
command! -nargs=0 Reindent :call Preserve('exec "normal! gg=G"')

"If you have any change log at your file header
:call Preserve('1,5s/Last Change: \zs.*/\=strftime("%c")/e')

"Close all buffers but current one
" https://bitbucket.org/snippets/sergio/9nbyGy
command! BufOnly silent! call Preserve("exec '%bd|e#|bd#'")

source: https://technotales.wordpress.com/2010/03/31/preserve-a-vim-function-that-keeps-your-state/

4
  • 1
    Welcome to our site! When answering try to give some explanation within the answer and not just links to other pages. Links can die, and may have a lot of irrelevant information to sort through.
    – Tumbler41
    Dec 21, 2016 at 23:12
  • 1
    As I said in the SO-duplicate, the restoration should happen in a finally block. Otherwise, if the a:command fails, nothing would be restored. Sep 1, 2017 at 14:32
  • I have just fixed my function as you mentioned @Luc Hermitte Jan 2, 2018 at 12:34
  • Great examples - very useful. Jul 12, 2018 at 19:45

Your Answer

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

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