Como restaurar a posição do cursor após executar um comando normal?

13

Estou tentando codificar uma função que substitui o caractere na sexta coluna da minha linha atual por um símbolo de dólar ( $), mas gostaria que meu cursor permanecesse na posição em que estava antes de chamar a função.

Então, tentei armazenar a coluna atual, executar minhas alterações e voltar com a seguinte função:

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

Provavelmente estou entendendo mal algo sobre o executecomando ... Ou talvez eu deva criar uma string contendo o comando que quero que seja executado?

Feffe
fonte

Respostas:

19

Você deve usar getpos():

Para salvar sua posição em uma variável:

let save_pos = getpos(".")

getpos()toma como argumento uma marca, aqui "."representa a posição atual do seu cursor.

E para restaurá-lo:

call setpos('.', save_pos)

Aqui, o primeiro argumento indica que você moverá a marca da posição atual do seu cursor (daí a sua posição atual) e o segundo é onde colocar a marca (a posição que você salvou anteriormente).

Sua função ficaria assim:

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

Para mais detalhes, consulte: :h getpos()e:h setpos()


Para mais detalhes sobre o uso de execute: esta função pega uma string e a executa. Sua cadeia pode ter apenas caracteres codificados entre aspas duplas ou o conteúdo de variáveis.

Quando você escreve

execute col_number."|"

Se você estiver na 12ª coluna, a string expandida será 12|. Execute tentará executar este comando, mas não funcionará porque 12|não é uma função vimscript, mas um comando no modo normal.

Para executá-lo a partir de um vimscript, você deve dizer "execute-o como se eu o tivesse digitado no modo normal", é para isso que o normal é usado.

Portanto, sem a execução, você teria escrito:

normal 12|

Agora, para fazer sua executeligação funcionar, você deve adicionar a normalpalavra-chave à sua cadeia expandida, assim:

execute "normal " . col_number . "|"
statox
fonte
Obrigado por esta solução (é a que eu usarei), mas existe alguma outra maneira de usar a minha variável "col_number"? Isso me permitiria entender melhor como executar / trabalho normal.
Feffe
1
@Feffe: Minha atualização deve esclarecer isso :-)
statox
3

Esta função mantém também o seu registro de pesquisa. Então você pode passar seu comando como argumento.

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

Alguma explicação

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

Por exemplo:

"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#'")

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

SergioAraujo
fonte
1
Bem vindo ao nosso site! Ao responder, tente dar uma explicação dentro da resposta e não apenas links para outras páginas. Os links podem morrer e podem ter muitas informações irrelevantes para serem classificadas.
precisa saber é o seguinte
1
Como eu disse no SO-duplicate, a restauração deve ocorrer em um finallybloco. Caso contrário, se a a:commandfalha falhar, nada será restaurado.
Luc Hermitte
Acabo fixo minha função como você mencionou @Luc Hermitte
SergioAraujo
Grandes exemplos - muito úteis.
Charlie Dalsass