Bagaimana cara mengganti-rekatkan teks yang ditarik ke dalam vim tanpa menarik garis yang dihapus?

39

Jadi saya biasanya menemukan diri saya menyalin teks dari satu titik ke titik lain sambil menimpa teks lama di mana yang baru disisipkan:

blah1
newtext
blah2
wrong1
blah3
wrong2
blah4

Misalkan saya menandai secara visual newtextdan ymenggesernya. Sekarang saya pilih wrong1(yang bisa apa saja, tidak harus hanya sepatah kata pun) dan paste newtext. Namun, jika sekarang saya melakukan hal yang sama dengan wrong2itu akan diganti dengan wrong1bukan newtext.

Jadi bagaimana cara menjaga agar teks yang ada di buffer tidak ditukar dengan teks yang saat ini saya timpa?

Edit 1

Walaupun saya cukup menyukai saran reigister (saya pikir saya akan mulai menggunakan register lebih banyak, sekarang saya menemukan :disperintah), saya akan dengan modifikasi jawaban jinfield , karena saya tidak menggunakan mode swapping.

vnoremap p "0p
vnoremap P "0P
vnoremap y "0y
vnoremap d "0d

melakukan trik dengan sempurna.

Edit 2

Saya terlalu cepat; solusi romainl adalah persis apa yang saya cari, tanpa hack di Edit 1 .
Sebenarnya vnoremap p "_dPsudah cukup!
Jadi, mengubah jawaban yang diterima.

bitmask
sumber
2
Hei fyi, saya sudah lama menggunakannya vnoremap p "_dP map, dan saya perhatikan itu tidak bekerja dengan baik untuk kata / karakter terakhir dalam satu baris. Aku sudah kembali pergi ke vnoremap p "0p, vnoremap P "0Pdan set clipboard=unnamed(untuk OSX)
Kache
vnoremap p "_dPmenghilangkan ruang putih pada pasta. Sunting 1 berfungsi dengan sempurna.
Vaclav Kasal

Jawaban:

21

Saya memiliki pemetaan ini di .vimrc saya:

" delete without yanking
nnoremap <leader>d "_d
vnoremap <leader>d "_d

" replace currently selected text with default register
" without yanking it
vnoremap <leader>p "_dP

"_adalah "daftar lubang hitam", menurut :help "_:

"Saat menulis ke register ini, tidak ada yang terjadi. Ini dapat digunakan untuk menghapus teks tanpa mempengaruhi register normal. Ketika membaca dari register ini, tidak ada yang dikembalikan. {Not in Vi}"

romainl
sumber
1
Saya telah menggunakan itu vnoremap p "_dP mapdan memperhatikan bahwa itu tidak berfungsi dengan baik untuk kata / karakter terakhir dalam satu baris. Aku sudah kembali pergi ke vnoremap p "0p, vnoremap P "0Pdan set clipboard=unnamed(untuk OSX)
Kache
vnoremap p "_dPberhenti bekerja untuk saya dalam mode pilih, tetapi vnoremap <leader>p "_dPberhasil
whitesiroi
1
mungkin <leader>adalah pengganti yang seharusnya saya ketahui untuk menggantikannya dengan sesuatu, tetapi ini hanya bekerja untuk saya jika saya menghapusnya. Apa artinya di sini?
Hashbrown
1
@ Hasbrown :help mapleader,.
romainl
Peringatan kecil: vnoremap <leader>ppemetaan tidak berfungsi dengan benar pada baris terakhir buffer karena segera setelah Anda menghapus baris terakhir buffer, Anda sekarang berada di baris sekali-kedua-terakhir, dan Pakan menempel di atas garis itu, bukannya di bawah.
Kal
13

Selain buffer standar, Anda dapat menarik teks ke buffer bernama, dan kemudian menempatkan dari buffer bernama. Ada hingga 26 buffer bernama yang dapat Anda gunakan (satu untuk setiap huruf). Gunakan tanda kutip ganda dan surat untuk mengakses buffer bernama. Contoh:

"dyy - Yank line saat ini ke buffer d.
"a7yy- Tarik tujuh baris berikutnya ke dalam buffer a.
"dP- Letakkan isi buffer d sebelum kursor.
"ap- Letakkan isi buffer setelah kursor

Hal keren lainnya, jika Anda menggunakan huruf kapital dan bukan huruf kecil, yaitu "Dyybaris saat ini akan ditambahkan ke buffer d bukannya menggantikannya. Lebih detail dalam buku O`Reilly: http://docstore.mik.ua/orelly/unix/vi/ch04_03.htm

Tradsud
sumber
3
Hal yang sangat keren. Saya tahu tentang buffer, tetapi tidak menghubungkan mereka dengan masalah ini. Masih rumit untuk "asemuanya, tapi oke.
bitmask
4

Saat menggunakan putdalam mode visual, teks yang Anda gantikan,, wrong1ditimpa oleh isi register 'tidak dikenal'.

Ini sebenarnya bekerja dengan 'meletakkan' register setelah seleksi dan kemudian menghapus seleksi. Masalahnya adalah bahwa penghapusan ini sekarang disimpan dalam unnamedregister dan akan digunakan untuk puttindakan selanjutnya .

Solusinya, menurut :h v_p, adalah menarik ke register bernama, seperti "0y, lalu tempel menggunakan "0pwaktu sebanyak yang Anda butuhkan. Mungkin bermanfaat untuk memetakan <leader>ydan <leader>pmenggunakan register bernama, jika ini adalah sesuatu yang sering Anda lakukan.

:map <leader>y "0y
:map <leader>p "0p

untuk bantuan lebih lanjut lihat:

:help v_p
:help map
jinfield
sumber
Solusi ini tampaknya paling dapat digunakan, sampai sesuatu yang pintar muncul dari vim itu sendiri.
Yugal Jindle
4

Menempel dari "0daftar penting untuk diketahui, tetapi Anda sering ingin mengganti berkali-kali. Jika Anda membuatnya menjadi tindakan yang berulang, Anda dapat menggunakan .operator, seperti yang disinggung oleh garyjohn. Dijelaskan di vim wiki :

yiw     yank inner word (copy word under cursor, say "first". Same as above).
...     Move the cursor to another word (say "second").
ciw<C-r>0   select "second", then replace it with "first" If you are at the start of the word then cw<C-r>0 is sufficient.
...     Move the cursor to another word (say "third").
.   select "third", then replace it with "first". 
Jerph
sumber
3

Ketika Anda menarik teks ke dalam register tanpa nama *, salinan juga dimasukkan ke dalam register 0. Setiap kali Anda mengganti teks yang dipilih, Anda dapat menempelkannya dari 0 register. Lihat

:help registers

Selain itu, jika Anda mengganti sejumlah kata dengan kata yang sama, Anda bisa langsung pindah ke awal kata yang akan diganti dan ketik .. Itu akan mengulangi operasi pengeditan terakhir. Lihat

:help single-repeat

* Lokasi penyimpanan yang Anda tarik dan masukkan disebut register. Buffer adalah hal yang Anda edit, biasanya salinan file dari disk.

garyjohn
sumber
1

Saya sangat membutuhkan ini, saya menulis sebuah plugin untuk itu: ReplaceWithRegister .

Plugin ini menawarkan perintah dua-dalam-satu gryang menggantikan teks yang dicakup oleh {motion}, seluruh baris, atau pilihan saat ini dengan isi register; teks lama dihapus ke register black-hole, yaitu hilang.

Ingo Karkat
sumber
1

Karena sesuatu seperti vnoremap p "_dP(saya juga mencoba xatau c) memiliki masalah dengan garis awal dan akhir, saya akhirnya melakukan ini: vnoremap p :<C-U>let @p = @+<CR>gvp:let @+ = @p<CR>yang saya temukan lebih sederhana daripada plugin yang ada (yang juga tidak bekerja dengan di set clipboard=unnamedplusluar kotak). Jadi yang dilakukannya adalah:

  • beralih ke mode perintah
  • hapus rentang ( C-U)
  • backup +mendaftar (karena unnamedplus, alternatif yang "dan *tergantung pada konfigurasi Anda) untukp
  • pulihkan pilihan dan tempel
  • beralih ke mode perintah lagi
  • pulihkan register
Sebastian Blask
sumber
Sempurna! Ini adalah yang pertama dari opsi ini yang bekerja persis seperti yang diharapkan untuk saya. Terima kasih!
Jamis Charles
1

Inilah yang saya gunakan (secara harfiah disalin dari .vimrc saya) untuk Windows-style Control + X cut / Control + C copy / Control + V paste / Control + S save / Control + F find / Control + H ganti perilaku.

Fungsi smartpaste () harus berisi apa yang Anda cari, yaitu cara untuk menempelkan teks yang disorot tanpa secara bersamaan menarik apa yang dipilih.

" Windows common keyboard shortcuts and pasting behavior {{{

" Uncomment to enable debugging.
" Check debug output with :messages
let s:debug_smart_cut = 0
let s:debug_smart_copy = 0
let s:debug_smart_paste = 0

function! SmartCut()
    execute 'normal! gv"+c'

    if visualmode() != "\<C-v>" " If not Visual-Block mode
        " Trim the last \r\n | \n | \r character in the '+' buffer
        " NOTE: This messes up Visual-Block pasting.
        let @+ = substitute(@+,'\(\r\?\n\|\r\)$','','g')
    endif

    if exists("s:debug_smart_cut") && s:debug_smart_cut
        echomsg "SmartCut '+' buffer: " . @+
    endif
endfunction

function! SmartCopy()
    execute 'normal! gv"+y'

    if visualmode() != "\<C-v>" " If not Visual-Block mode
        " Trim the last \r\n | \n | \r character in the '+' buffer
        " NOTE: This messes up Visual-Block pasting.
        let @+ = substitute(@+,'\(\r\?\n\|\r\)$','','g')
    endif

    if exists("s:debug_smart_copy") && s:debug_smart_copy
        echomsg "SmartCopy '+' buffer: " . @+
    endif
endfunction

" Delete to black hole register before pasting. This function is a smarter version of "_d"+P or "_dp to handle special cases better.
" SOURCE: http://stackoverflow.com/questions/12625722/vim-toggling-buffer-overwrite-behavior-when-deleting
function! SmartPaste()
    let mode = 'gv'

    let delete = '"_d'

    let reg = '"+'

    " See :help '> for more information. Hint: if you select some text and press ':' you will see :'<,'>
    " SOURCE: http://superuser.com/questions/723621/how-can-i-check-if-the-cursor-is-at-the-end-of-a-line
    " SOURCE: http://stackoverflow.com/questions/7262536/vim-count-lines-in-selected-range
    " SOURCE: https://git.zug.fr/config/vim/blob/master/init.vim
    " SOURCE: https://git.zug.fr/config/vim/blob/master/after/plugin/zzzmappings.vim
    let currentColumn = col(".")
    let currentLine = line(".")
    let lastVisibleLetterColumn = col("$") - 1
    let lastLineOfBuffer = line("$")
    let selectionEndLine = line("'>")
    let selectionEndLineLength = len(getline(selectionEndLine))
    let nextLineLength = len(getline(currentLine + 1))
    let selectionStartColumn = col("'<")
    let selectionEndColumn = col("'>")

    " If selection does not include or go beyond the last visible character of the line (by also selecting the invisible EOL character)
    if selectionEndColumn < selectionEndLineLength
        let cmd = 'P'

        if exists("s:debug_smart_paste") && s:debug_smart_paste
            echomsg "SmartPaste special case #1"
        endif

    " If attempting to paste on a blank last line
    elseif selectionEndLineLength == 0 && selectionEndLine == lastLineOfBuffer
        let cmd = 'P'

        if exists("s:debug_smart_paste") && s:debug_smart_paste
            echomsg "SmartPaste special case #2"
        endif

    " If selection ends after the last visible character of the line (by also selecting the invisible EOL character) and next line is not blank and not the last line
    elseif selectionEndColumn > selectionEndLineLength && nextLineLength > 0 && selectionEndLine != lastLineOfBuffer
        let cmd = 'P'

        if exists("s:debug_smart_paste") && s:debug_smart_paste
            echomsg "SmartPaste special case #3"
        endif

    " If selection ends after the last visible character of the line (by also selecting the invisible EOL character), or the line is visually selected (Shift + V), and next line is the last line
    elseif selectionEndColumn > selectionEndLineLength && selectionEndLine == lastLineOfBuffer
        " SOURCE:  http://vim.wikia.com/wiki/Quickly_adding_and_deleting_empty_lines

        " Fixes bug where if the last line is fully selected (Shift + V) and a paste occurs, that the paste appears to insert after the first character of the line above it because the delete operation [which occurs before the paste]
        " is causing the caret to go up a line, and then 'p' cmd causes the paste to occur after the caret, thereby pasting after the first letter of that line.
        " However this but does not occur if there's a blank line underneath the selected line, prior to deleting it, as the cursor goes down after the delete in that situation.
        call append(selectionEndLine, "")

        let cmd = 'p'

        if exists("s:debug_smart_paste") && s:debug_smart_paste
            echomsg "SmartPaste special case #4"
        endif

    else
        let cmd = 'p'

        if exists("s:debug_smart_paste") && s:debug_smart_paste
            echomsg "SmartPaste default case"
        endif
    endif

    if exists("s:debug_smart_paste") && s:debug_smart_paste
        echomsg "SmartPaste debug info:"
        echomsg "    currentColumn: " . currentColumn
        echomsg "    currentLine: " . currentLine
        echomsg "    lastVisibleLetterColumn: " . lastVisibleLetterColumn
        echomsg "    lastLineOfBuffer: " . lastLineOfBuffer
        echomsg "    selectionEndLine: " . selectionEndLine
        echomsg "    selectionEndLineLength: " . selectionEndLineLength
        echomsg "    nextLineLength: " . nextLineLength
        echomsg "    selectionStartColumn: " . selectionStartColumn
        echomsg "    selectionEndColumn: " . selectionEndColumn
        echomsg "    cmd: " . cmd
        echo [getpos("'<")[1:2], getpos("'>")[1:2]]
        echo "visualmode(): " . visualmode()
        echo "mode(): " . mode()
    endif

    if visualmode() != "\<C-v>" " If not Visual-Block mode
        " Trim the last \r\n | \n | \r character in the '+' buffer
        " NOTE: This messes up Visual-Block pasting.
        let @+ = substitute(@+,'\(\r\?\n\|\r\)$','','g')
    endif

    try
        execute 'normal! ' . mode . delete . reg . cmd
    catch /E353:\ Nothing\ in\ register\ +/
    endtry

    " Move caret one position to right
    call cursor(0, col(".") + 1)
endfunction

" p or P delete to black hole register before pasting
" NOTE: <C-u> removes the '<,'> visual-selection from the command line. See :h c_CTRL-u
vnoremap <silent> p :<C-u>call SmartPaste()<CR>
vnoremap <silent> P :<C-u>call SmartPaste()<CR>

" MiddleMouse delete to black hole register before pasting
nnoremap <MiddleMouse> "+p " Changes default behavior from 'P' mode to 'p' mode for normal mode middle-mouse pasting
" NOTE: <C-u> removes the '<,'> visual-selection from the command line. See :h c_CTRL-u
vnoremap <silent> <MiddleMouse> :<C-u>call SmartPaste()<CR>
inoremap <MiddleMouse> <C-r><C-o>+

" Disable weird multi-click things you can do with middle mouse button
" SOURCE: http://vim.wikia.com/wiki/Mouse_wheel_for_scroll_only_-_disable_middle_button_paste
noremap <2-MiddleMouse> <Nop>
inoremap <2-MiddleMouse> <Nop>
noremap <3-MiddleMouse> <Nop>
inoremap <3-MiddleMouse> <Nop>
noremap <4-MiddleMouse> <Nop>
inoremap <4-MiddleMouse> <Nop>

if os != "mac" " NOTE: MacVim provides Command+C|X|V|A|S and undo/redo support and also can Command+C|V to the command line by default
    " SOURCE: https://opensource.apple.com/source/vim/vim-62.41.2/runtime/macmap.vim.auto.html
    " NOTE: Only copy and paste are possible in the command line from what i can tell.
    "       Their is no undo for text typed in the command line and you cannot paste text onto a selection of text to replace it.
    cnoremap <C-c> <C-y>
    cnoremap <C-v> <C-r>+
    " TODO: Is their a select-all for the command line???

    " Cut, copy, and paste support for visual and insert mode (not for normal mode)
    " SOURCE: http://superuser.com/questions/10588/how-to-make-cut-copy-paste-in-gvim-on-ubuntu-work-with-ctrlx-ctrlc-ctrlv
    " NOTE: <C-u> removes the '<,'> visual-selection from the command line. See :h c_CTRL-u
    vnoremap <silent> <C-x> :<C-u>call SmartCut()<CR>
    vnoremap <silent> <C-c> :<C-u>call SmartCopy()<CR>
    vnoremap <silent> <C-v> :<C-u>call SmartPaste()<CR>
    inoremap <C-v> <C-r><C-o>+

    " Select-all support for normal, visual, and insert mode
    " http://vim.wikia.com/wiki/Using_standard_editor_shortcuts_in_Vim
    nnoremap <C-a> ggVG
    vnoremap <C-a> ggVG
    inoremap <C-a> <Esc>ggVG

    " Save file support for normal, visual, and insert mode
    " SOURCE: http://vim.wikia.com/wiki/Map_Ctrl-S_to_save_current_or_new_files
    " If the current buffer has never been saved, it will have no name,
    " call the file browser to save it, otherwise just save it.
    command -nargs=0 -bar Update if &modified |
                                \    if empty(bufname('%')) |
                                \        browse confirm write |
                                \    else |
                                \        confirm write |
                                \    endif |
                                \endif
    nnoremap <silent> <C-s> :update<CR>
    " NOTE: <C-u> removes the '<,'> visual-selection from the command line. See :h c_CTRL-u
    vnoremap <silent> <C-s> :<C-u>update<CR>V
    " NOTE: <C-o> executes a normal-mode command without leaving insert mode. See :help ins-special-special
    "inoremap <silent> <C-s> <C-o>:update<CR>
    "
    " <C-o> doesn't seem to work while also using the "Open the OmniCompletion menu as you type" code while the menu is visible.
    " Doing "call feedkeys("\<C-x>\<C-o>", "n")" to perform omni completion seems to be the issue.
    " However doing "call feedkeys("\<C-x>\<C-i>", "n")" to perform keywork completion seems to work without issue.
    "
    " Workaround will exit insert mode to execute the command and then enter insert mode.
    inoremap <silent> <C-s> <Esc>:update<CR>I

    " Undo and redo support for normal, visual, and insert mode
    nnoremap <C-z> <Esc>u
    nnoremap <C-y> <Esc><C-r>

    " NOTE: <C-u> removes the '<,'> visual-selection from the command line. See :h c_CTRL-u
    vnoremap <C-z> :<C-u>uV
    vnoremap <C-y> :<C-u><C-r>V

    inoremap <C-z> <Esc>uI
    inoremap <C-y> <Esc><C-r>I

    function! Find()
        let wordUnderCursor = expand('<cword>')
        if len(wordUnderCursor) > 0
            execute 'promptfind ' . wordUnderCursor
        else
            execute 'promptfind'
        endif
    endfunction

    function! Replace()
        let wordUnderCursor = expand('<cword>')
        if len(wordUnderCursor) > 0
            execute 'promptrepl ' . wordUnderCursor
        else
            execute 'promptrepl'
        endif
    endfunction

    " Find and Find/Replace support for normal, visual, and insert mode
    nnoremap <C-f> :call Find()<CR>
    nnoremap <C-h> :call Replace()<CR>

    " NOTE: <C-u> removes the '<,'> visual-selection from the command line. See :h c_CTRL-u
    vnoremap <C-f> :<C-u>call Find()<CR>
    vnoremap <C-h> :<C-u>call Replace()<CR>

    " NOTE: <C-o> executes a normal-mode command without leaving insert mode. See :help ins-special-special
    inoremap <C-f> <C-o>:call Find()<CR>
    inoremap <C-h> <C-o>:call Replace()<CR>
endif

" }}} Windows common keyboard shortcuts and pasting behavior
Serigala Terfokus
sumber
-1

tl; dr - vnoremap p "_c *

Berikut adalah daftar pemetaan lengkap saya:
"Perbaiki daftar copy / paste
nnoremap DD" * dd
nnoremap D "* d
vnoremap D" d
nnoremap dd "_d
nnoremap dd" _dd
vnoremap d "_d
nnoremap s" _s
vnoremap s "_s
vnoremap s" _s c "_c
vnoremap c" _c
nnoremap x "_x
vnoremap x" _x
vnoremap p "_c

"Tempel di baris baru
nnoremap, p op
nnoremap, P Op

kawerte
sumber