Como Ctrl-A e Ctrl-X, mas modifique apenas o primeiro dígito


10

Existe uma maneira de aumentar / diminuir o primeiro dígito após / sob o cursor, não o número inteiro.

Eu sei que não é assim que o vim funciona, mas existe um plugin que faz isso? Não consegui encontrar.

É muito útil ao editar css e também em outros casos.

Dado:

▐margin: 10px

Quando pressiono CTRL-A, quero ver:

▐margin: 20px

Real:

▐margin: 11px

10
Você também pode fazer 10<C-a>para adicionar 10 ou r2para substituir a 1 com um 2.
jamessan

Respostas:


6

Isso parece funcionar muito bem e faz coisas razoavelmente sensatas ao usar <C-a>um 9 (95 se torna 105) ou usar <C-x>um 0 (105 se torna 95):

nnoremap g<C-a> :call search('\d', 'c')<CR>a <Esc>h<C-a>lxh
nnoremap g<C-x> :call search('\d', 'c')<CR>a <Esc>h<C-x>lxh
  • Primeiro, procuramos por qualquer dígito, search()tem a vantagem de não redefinir @/.
  • a <Esc>h - Vá para o modo de inserção, adicione um espaço após o dígito e vá para a esquerda para que o cursor fique na parte superior do dígito.
  • Agora podemos usar <C-a>ou <C-x>.
  • Usamos lxhpara remover o espaço que adicionamos.

Eu mapeei isso para g<C-a>e g<C-x>, assim você ainda pode chamar o original.

Uma versão ligeiramente diferente, que procurará apenas números na linha atual (mas deixará um espaço pendente se não houver número na linha atual):

nnoremap g<C-a> :call search('\d', 'c', line('.'))<CR>a <Esc>h<C-a>lxh
nnoremap g<C-x> :call search('\d', 'c', line('.'))<CR>a <Esc>h<C-x>lxh

E aqui está outra versão que usa o mesmo conceito de antes, mas também adiciona um espaço antes do dígito. Isso fará com que g<C-a>ignorar qualquer sinal munis antes do número (por padrão, <C-a>na -42vontade 'incremento' para -41.

Ele também aceita uma contagem, de modo que 5g<C-a>aumentará o número em 5:

fun! Increment(dir, count)
    " No number on the current line
    if !search('\d', 'c', getline('.'))
        return
    endif

    " Store cursor position
    let l:save_pos = getpos('.')

    " Add spaces around the number
    s/\%#\d/ \0 /
    call setpos('.', l:save_pos)
    normal! l

    " Increment or decrement the number
    if a:dir == 'prev'
        execute "normal! " . repeat("\<C-x>"), a:count
    else
        execute "normal! " . repeat("\<C-a>", a:count)
    endif

    " Remove the spaces
    s/\v (\d{-})%#(\d) /\1\2/

    " Restore cursor position
    call setpos('.', l:save_pos)
endfun

nnoremap <silent> g<C-a> :<C-u>call Increment('next', v:count1)<CR>
nnoremap <silent> g<C-x> :<C-u>call Increment('prev', v:count1)<CR>

9

Incremento básico

Aqui está uma macro simples para executar a ação:

:nnoremap <leader>a m`lv$xh<c-a>p``
:nnoremap <leader>x m`lv$xh<c-x>p``

No modo normal, você

  • m` Marque sua localização
  • l mover um caractere para a direita
  • v$x corte até o final da linha
  • h voltar para a posição original
  • <c-a> incremento (ou decremento)
  • p cole de volta o seu corte
  • `` volte para a sua marca

Ir para o próximo número

Se você quiser pular para o próximo número (ou permanecer na sua posição atual, se estiver em um número), precisará de uma função que verifique o caractere atual e o possível salto para o próximo número.

function! NextNum()
  let ch = getline(".")[col(".")-1]
  if ch !~ "[0-9]"
    execute "normal! /[0-9]\<cr>"
  endif
endfunction

nnoremap <leader>a :call NextNum()<cr>m`lv$xh<c-a>p``
nnoremap <leader>x :call NextNum()<cr>m`lv$xh<c-x>p``

NextNumcoloca o caractere sob o cursor, verifica se é um número e se não procura o próximo número. Depois disso, o resto é o mesmo. Se você deseja que o mapeamento seja diferente, basta alterar nnoremap <leader>apara o que deseja, por exemplo nnoremap <c-a>.

Ignorando negativos e números maiores que 9

Se você deseja apenas percorrer os dígitos e não fazê-los agir como números inteiros assinados, as seguintes funções serão incrementadas, decrementadas e roladas em 0 e 9.

function! NextNum()
  let ch = getline(".")[col(".")-1]
  if ch !~ "[0-9]"
    execute "normal! /[0-9]\<cr>"
  endif
endfunction

function! IncDec(val, dec)
  if a:dec
    if a:val == 0
      return 9
    else
      return a:val - 1
    endif
  else
    if a:val == 9
      return 0
    else
      return a:val + 1
    endif
  endif
endfunction

function! DoMath(dec)
  call NextNum()
  normal! x
  let @" = IncDec(@", a:dec)
  normal! P
endfunction

nnoremap <leader>a :call DoMath(0)<cr>
nnoremap <leader>x :call DoMath(1)<cr>

Agora, quando você está ligado 8e digita, <leader>arecebe 9. Fazê-lo novamente resulta em 0. Se você pressionar <leader>xem 0que você começa 9. O mesmo vale para números negativos. As funções cortam um único caractere, aumentam, diminuem ou passam o mouse e colam no lugar.


Algo não está bem aqui, mas vou manter essa ideia em mente, talvez possa ser melhorada. Ele deve estar saltando para o primeiro dígito na linha atual, se houver, e operar nela. De preferência, seja mapeável <c-a>/<c-x>também.
firedev

A versão atualizada. Agora pula para o próximo número ou se você estiver com mais de um dígito no momento, permite incrementá-lo.
Jecxjo #

Sim! Isso é incrível, obrigado! Eu não entendo por que a questão foi downvoted embora, este foi-me irritante desde o primeiro dia e, aparentemente, muitas pessoas redefinir <c-a>e <c-x>para outra coisa, porque o comportamento padrão não é tão útil.
firedev

Pude ver que a votação foi reduzida, porque a pergunta era para algo muito específico e a pergunta original mudou ao longo do caminho ... a necessidade de pular para o primeiro número. Além disso, eu realmente uso <c-a>e <c-x>muito. Sempre que eu atualizar uma versão ou aumentar uma variável de intervalo, apenas em [N]<c-a>vez de excluir e substituir.
Jecxjo #

11
Seria possível, mas haveria um conjunto muito maior de funções. A implementação atual tira proveito <c-a>e <c-x>precisa ser descartada para uma função que faz o mesmo, mas ignora o traço.
Jecxjo #

5

Aqui está uma versão que escrevi usando uma expressão substituta:

map <c-a> :s/\d/\=submatch(0) < 9 ? submatch(0) + 1 : submatch(0)/<CR>
map <c-x> :s/\d/\=submatch(0) > 0 ? submatch(0) - 1 : submatch(0)/<CR>

Cada um apenas procura o primeiro dígito caractere da linha e adiciona ou subtrai um se estiver no intervalo [0-8] ou [1-9], respectivamente. Tem três problemas:

  1. É principalmente manipulação de texto, e apenas analisa o primeiro caractere, portanto, não se sabe se um número é negativo. Isso é corrigível, mas eu gosto do comportamento atual como está.
  2. Ele derruba o registro de pesquisa:, "/e se você tiver o hlsearch ativado, todos os números no buffer atual serão destacados quando você o usar. Você pode anexar :noh<CR>a cada um dos mapcomandos acima para interromper o realce, mas não sei como impedir que o registro seja derrotado.
  3. Funciona no primeiro número da linha, não no primeiro número após o cursor.

Além disso, se fosse eu, eu traçaria o item acima para <leader>ae <leader>x, em vez de para CTRL-A/X. Dessa forma, você tem os dois comportamentos disponíveis para você. <leader>é, por padrão, a tecla de barra invertida ( \).


O fato de desconsiderar o número negativo é bom, na verdade o comportamento padrão me pareceu estranho. Eu acho que parece muito melhor com :nohtambém. Mas o problema real é que ele não pode usar a posição do cursor como base e, portanto, você pode incrementar apenas o primeiro dígito da linha.
firedev

Isso para no número 9 e, acima de 10, aumenta em 11, não em 10 ... Acho que isso não é intencional (ou seja, um bug)? Além disso, você sempre deseja usar mapeamento não recursivo ( noremap) e nunca map . Veja esta página para uma explicação mais detalhada disso.
Martin Tournoij
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.