Podobnie jak Ctrl-A i Ctrl-X, ale modyfikuj tylko pierwszą cyfrę

10

Czy istnieje sposób na zwiększenie / zmniejszenie pierwszej cyfry za / pod kursorem, a nie całej liczby.

Wiem, że to nie tak działa vim, ale czy istnieje wtyczka, która to robi? Nie mogłem tego znaleźć.

Jest to bardzo przydatne podczas edycji css, a także w innych przypadkach.

Dany:

▐margin: 10px

Kiedy naciskam CTRL-A, chcę zobaczyć:

▐margin: 20px

Rzeczywisty:

▐margin: 11px
firedev
źródło
10
Możesz także 10<C-a>dodać 10 lub r2zamienić 1 na 2.
jamessan 14.04.15

Odpowiedzi:

6

Wydaje się, że działa to całkiem dobrze i robi całkiem rozsądne rzeczy, gdy używa się <C-a>na 9 (95 staje się 105), lub używa <C-x>na 0 (105 staje się 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
  • Po pierwsze, szukamy dowolnej cyfry, search()ma tę zaletę, że nie resetuje się @/.
  • a <Esc>h - Przejdź do trybu wstawiania, dodaj spację po cyfrze i idź w lewo, aby kursor znajdował się nad cyfrą.
  • Możemy teraz użyć <C-a>lub <C-x>.
  • Używamy lxhdo usuwania dodanego miejsca.

Odwzorowałem to na g<C-a>i g<C-x>, więc nadal możesz zadzwonić do oryginału.

Nieco inna wersja, która będzie wyszukiwać tylko liczby w bieżącym wierszu (ale pozostawi wiszącą spację, jeśli w bieżącym wierszu nie ma numeru):

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

A oto kolejna wersja, która wykorzystuje tę samą koncepcję jak poprzednio, ale dodaje również spację przed cyfrą. Spowoduje to g<C-a>zignorowanie dowolnego znaku munis przed liczbą (domyślnie, <C-a>on -42„zwiększy” ją do -41.

Akceptuje również liczenie, więc 5g<C-a>zwiększy liczbę o 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>
Martin Tournoij
źródło
9

Przyrost podstawowy

Oto proste makro do wykonania akcji:

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

W trybie normalnym ty

  • m` Zaznacz swoją lokalizację
  • l przesuń jedną postać w prawo
  • v$x przeciąć do końca linii
  • h wróć do pierwotnej pozycji
  • <c-a> przyrost (lub spadek)
  • p wklej z powrotem swoje cięcie
  • `` wróć do swojego znaku

Przejdź do następnego numeru

Jeśli chcesz przeskoczyć do następnej liczby (lub pozostać w bieżącej pozycji, jeśli znajduje się na numerze), potrzebujesz funkcji, która sprawdza bieżący kursor i możliwy skok do następnej liczby.

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``

NextNumumieszcza znak pod kursorem, sprawdza, czy jest to liczba, a jeśli nie, szuka następnego numeru. Potem reszta jest taka sama. Jeśli chcesz, aby mapowanie było inne, zmień na przykład nnoremap <leader>ato, co chcesz nnoremap <c-a>.

Ignorowanie negatywów i liczb wyższych niż 9

Jeśli chcesz po prostu przewijać cyfry i nie powodować, by działały one jako liczby całkowite ze znakiem, następujące funkcje będą zwiększać i zmniejszać oraz przesuwać po wartościach 0 i 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>

Teraz, gdy jesteś włączony 8i pisz <leader>a, dostajesz 9. Ponowne wykonanie spowoduje 0. Jeśli naciśniesz <leader>xna 0dostajesz 9. To samo dotyczy liczb ujemnych. Funkcje wycinają pojedynczy znak, zwiększają, zmniejszają lub przewijają, a następnie wklejają na miejscu.

jecxjo
źródło
Coś tu jest nie tak, ale będę pamiętać o tym pomyśle, być może można go ulepszyć. Powinien przeskakiwać do pierwszej cyfry w bieżącej linii, jeśli taka istnieje i działać na niej. Najlepiej jest <c-a>/<c-x>również odwzorować na .
firedev
Zaktualizowana wersja. Teraz przeskakuje do przodu do następnej liczby lub jeśli aktualnie znajdujesz się powyżej cyfry, możesz ją zwiększyć.
jecxjo
Tak! To jest niesamowite, dziękuję! Nie rozumiem, dlaczego kwestia została downvoted choć było to irytujące mnie, ponieważ jeden dzień i widocznie wiele osób przedefiniować <c-a>i <c-x>na coś innego, ponieważ domyślne zachowanie nie jest przydatna.
firedev
Widziałem, że zostało to zanegowane, ponieważ pytanie dotyczyło czegoś bardzo konkretnego, a pierwotne pytanie zmieniło się po drodze ... potrzeba przeskoczenia do pierwszej liczby. Poza tym faktycznie używam <c-a>i <c-x>dużo. Za każdym razem, gdy aktualizuję wersję lub zwiększam zmienną zakresu, po prostu [N]<c-a>zamiast kasować i zamieniać.
jecxjo 15.04.15
1
Byłoby to możliwe, ale byłby to znacznie większy zestaw funkcji. Obecna implementacja wykorzystuje <c-a>i <c-x>które musiałyby zostać usunięte za pomocą funkcji, która robi to samo, ale ignoruje kreskę.
jecxjo
5

Oto wersja, którą napisałem, używając wyrażenia zastępczego:

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>

Każdy z nich po prostu szuka pierwszej cyfry w wierszu i dodaje lub odejmuje jeden, jeśli jest w zakresie odpowiednio [0–8] lub [1-9]. Ma trzy problemy:

  1. Chodzi głównie o manipulację tekstem i patrzy tylko na pierwszy znak, więc nie wie, czy liczba jest ujemna. Można to naprawić, ale podoba mi się obecne zachowanie.
  2. Blokuje rejestr wyszukiwania: "/a jeśli masz włączone wyszukiwanie, wówczas wszystkie liczby w bieżącym buforze zostaną podświetlone, gdy go użyjesz. Możesz dołączyć :noh<CR>do każdego z powyższych mappoleceń, aby zatrzymać podświetlanie, ale nie wiem, jak ładnie zatrzymać rejestr przed zablokowaniem.
  3. Działa na pierwszej liczbie w linii, a nie na pierwszej liczbie po kursorze.

Ponadto, gdybym to był ja, zamapowałbym powyższe na <leader>ai <leader>xzamiast na CTRL-A/X. W ten sposób masz do dyspozycji oba zachowania. <leader>jest domyślnie klawiszem ukośnika odwrotnego ( \).

Cookyt
źródło
Fakt, że pomija liczbę ujemną, jest w porządku, w rzeczywistości zachowanie domyślne wydawało mi się dziwne. Myślę, że z tym też wygląda znacznie lepiej :noh. Ale prawdziwym problemem jest to, że nie można użyć pozycji kursora jako podstawy, a zatem można zwiększyć tylko pierwszą cyfrę w linii.
firedev
To kończy się na cyfrze 9, a powyżej 10 zwiększa się o 11, a nie o 10 ... Myślę, że to niezamierzone (np. Błąd)? Ponadto zawsze chcesz używać mapowania nierekurencyjnego ( noremap) i nigdy map . Zobacz tę stronę, aby uzyskać bardziej szczegółowe wyjaśnienie tego.
Martin Tournoij