Seperti Ctrl-A dan Ctrl-X tetapi hanya memodifikasi digit pertama

10

Apakah ada cara untuk menambah / mengurangi digit pertama setelah / di bawah kursor, bukan seluruh angka.

Saya tahu ini bukan cara vim bekerja, tetapi apakah ada plugin yang melakukan itu? Saya tidak dapat menemukannya.

Ini sangat berguna saat mengedit css dan dalam kasus lain juga.

Diberikan:

▐margin: 10px

Ketika saya menekan CTRL-Asaya ingin melihat:

▐margin: 20px

Sebenarnya:

▐margin: 11px
dipecat
sumber
10
Anda juga 10<C-a>dapat menambahkan 10 atau r2mengganti 1 dengan 2.
jamessan

Jawaban:

6

Ini tampaknya bekerja dengan cukup baik, dan melakukan hal-hal yang cukup waras ketika menggunakan <C-a>angka 9 (95 menjadi 105), atau menggunakan <C-x>angka 0 (105 menjadi 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
  • Pertama, kami mencari digit apa pun, search()memiliki keuntungan tidak mengatur ulang @/.
  • a <Esc>h - Pergi ke mode insert, tambahkan spasi setelah digit, dan pergi ke kiri sehingga kursor berada di atas digit.
  • Kita sekarang dapat menggunakan <C-a>atau <C-x>.
  • Kami menggunakan lxhuntuk menghapus ruang yang kami tambahkan.

Saya telah memetakan ini ke g<C-a>dan g<C-x>, jadi Anda masih dapat memanggil yang asli.

Versi yang sedikit berbeda yang hanya akan mencari angka pada baris saat ini (tetapi akan meninggalkan ruang yang menggantung jika tidak ada angka di baris saat ini):

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

Dan inilah versi lain yang menggunakan konsep yang sama seperti sebelumnya, tetapi juga menambahkan spasi sebelum digit. Ini akan membuat g<C-a>mengabaikan tanda munis sebelum nomor (secara default, <C-a>pada -42akan 'bertambah' menjadi -41.

Itu juga menerima hitungan, sehingga 5g<C-a>akan menambah angka dengan 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
sumber
9

Peningkatan dasar

Berikut ini adalah makro sederhana untuk melakukan tindakan:

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

Dalam mode normal Anda

  • m` Tandai lokasi Anda
  • l pindahkan satu karakter ke kanan
  • v$x potong sampai akhir garis
  • h kembali ke posisi semula
  • <c-a> increment (atau decrement)
  • p tempelkan kembali potongan Anda
  • `` kembali ke tanda Anda

Lompat ke nomor berikutnya

Jika Anda ingin melompat ke nomor berikutnya (atau tetap di posisi Anda saat ini jika pada nomor), Anda memerlukan fungsi yang memeriksa karakter yang sedang dikutuk dan mungkin melompat ke nomor berikutnya.

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

NextNummendapatkan karakter di bawah kursor, memeriksa apakah nomornya dan jika tidak mencari nomor berikutnya. Setelah itu sisanya sama. Jika Anda ingin pemetaan berbeda, ubah saja nnoremap <leader>asesuai keinginan, misalnya nnoremap <c-a>.

Mengabaikan negatif dan angka lebih tinggi dari 9

Jika Anda ingin hanya menggilir angka dan tidak menjadikannya bertindak sebagai bilangan bulat yang ditandatangani, fungsi-fungsi berikut akan bertambah dan berkurang dan berguling pada 0 dan 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>

Sekarang ketika Anda aktif 8dan ketik yang <leader>aAnda dapatkan 9. Melakukannya lagi menghasilkan 0. Jika Anda menekan <leader>xpada 0Anda mendapatkan 9. Hal yang sama berlaku untuk angka negatif. Fungsi memotong satu karakter, increment, decrement atau roll over dan kemudian tempelkan pada tempatnya.

jecxjo
sumber
Ada yang tidak beres di sini, tapi saya akan mengingatnya, mungkin bisa diperbaiki. Itu harus melompat ke digit pertama pada baris saat ini jika ada dan beroperasi di atasnya. Lebih disukai bisa dipetakan <c-a>/<c-x>juga.
firedev
Versi yang diperbarui. Sekarang melompat maju ke nomor berikutnya atau jika Anda saat ini lebih dari satu digit memungkinkan Anda untuk menambahnya.
jecxjo
Iya! Ini luar biasa, terima kasih! Saya tidak mengerti mengapa pertanyaannya dibatalkan, ini mengganggu saya sejak hari pertama dan tampaknya banyak orang mendefinisikan ulang <c-a>dan <c-x>untuk sesuatu yang lain karena perilaku default tidak begitu berguna.
firedev
Saya bisa melihatnya diturunkan karena pertanyaannya adalah untuk sesuatu yang sangat spesifik dan jenis pertanyaan awal berubah sepanjang jalan ... kebutuhan untuk melompat ke nomor pertama. Selain itu, saya benar-benar menggunakan <c-a>dan <c-x>banyak. Setiap kali saya memperbarui versi atau menambah variabel rentang, saya hanya [N]<c-a>menghapus dan mengganti.
jecxjo
1
Itu akan mungkin tetapi akan menjadi satu set fungsi yang jauh lebih besar. Implementasi saat ini mengambil keuntungan dari <c-a>dan <c-x>yang perlu dijatuhkan untuk fungsi yang melakukan hal yang sama tetapi mengabaikan tanda hubung.
jecxjo
5

Ini adalah versi yang saya tulis menggunakan ekspresi pengganti:

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>

Masing-masing hanya mencari karakter digit pertama pada baris, dan menambahkan atau mengurangi satu jika masing-masing berada dalam kisaran [0-8] atau [1-9]. Ada tiga masalah:

  1. Ini sebagian besar manipulasi teks, dan hanya melihat karakter pertama, jadi tidak tahu apakah angka negatif. Ini bisa diperbaiki, tapi saya suka perilaku apa adanya.
  2. Ini mengacaukan register pencarian "/:, dan jika Anda mengaktifkan pencarian, maka semua angka dalam buffer saat ini akan disorot ketika Anda menggunakan ini. Anda dapat menambahkan :noh<CR>ke masing-masing mapperintah di atas untuk menghentikan penyorotan, tapi saya tidak tahu bagaimana menghentikan register agar tidak musnah.
  3. Ini bekerja pada angka pertama di telepon, bukan nomor pertama setelah kursor.

Juga, jika itu saya, saya akan memetakan di atas ke <leader>adan <leader>x, bukan ke CTRL-A/X. Dengan cara ini, Anda memiliki kedua perilaku yang tersedia untuk Anda. <leader>adalah, secara default, tombol backslash ( \).

Cookyt
sumber
Fakta bahwa itu mengabaikan angka negatif baik-baik saja, pada kenyataannya perilaku standar tampak aneh bagi saya. Saya pikir itu terlihat jauh lebih baik :nohjuga. Tetapi masalah sebenarnya adalah bahwa ia tidak dapat menggunakan posisi kursor sebagai basis dan dengan demikian Anda hanya dapat menambah angka pertama dalam baris.
firedev
Ini berhenti pada angka 9, dan di atas 10 bertambah 11, bukan 10 ... Saya pikir ini tidak disengaja (mis. Bug)? Selain itu, Anda selalu ingin menggunakan pemetaan non-rekursif ( noremap) dan tidak pernah map . Lihat halaman ini untuk penjelasan lebih rinci tentang itu.
Martin Tournoij