Làm cách nào để thay thế-dán văn bản đã được kéo trong vim mà không kéo các dòng bị xóa?


39

Vì vậy, tôi thường thấy mình sao chép văn bản từ điểm này sang điểm khác trong khi ghi đè văn bản cũ nơi dán mới:

blah1
newtext
blah2
wrong1
blah3
wrong2
blah4

Giả sử tôi đánh dấu trực quan newtextvà mắt cá chân ynó. Bây giờ tôi chọn wrong1(có thể là bất cứ điều gì, không nhất thiết chỉ là một từ) và paste newtext. Tuy nhiên, nếu bây giờ tôi làm tương tự với wrong2nó sẽ được thay thế bằng wrong1thay vì newtext.

Vậy làm cách nào để giữ cho văn bản trong bộ đệm không bị hoán đổi với văn bản mà tôi hiện đang ghi đè?

Chỉnh sửa 1

Mặc dù tôi khá thích các đề xuất reigister (tôi nghĩ rằng tôi sẽ bắt đầu sử dụng các thanh ghi nhiều hơn, bây giờ tôi đã phát hiện ra :dislệnh), tôi sẽ sửa đổi câu trả lời của jinfield , vì tôi không sử dụng chế độ tráo đổi.

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

thực hiện các mẹo hoàn hảo.

Chỉnh sửa 2

Tôi đã quá nhanh; Giải pháp của romainl chính xác là những gì tôi đang tìm kiếm, mà không cần hack trong Chỉnh sửa 1 .
Thật ra, thế vnoremap p "_dPlà đủ!
Vì vậy, thay đổi câu trả lời được chấp nhận.


2
Xin chào fyi, từ lâu tôi đã sử dụng nó vnoremap p "_dP mapvà tôi nhận thấy rằng nó không hoạt động tốt cho từ / ký tự cuối cùng trong một dòng. Tôi đã trở lại ra đi vào vnoremap p "0p, vnoremap P "0Pset clipboard=unnamed(cho OSX)
Kache

vnoremap p "_dPloại bỏ khoảng trắng trên dán. Chỉnh sửa 1 hoạt động hoàn hảo.
Vaclav Kasal

Câu trả lời:


21

Tôi có những ánh xạ này trong .vimrc của mình:

" 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

"_là "thanh ghi lỗ đen", theo :help "_:

"Khi ghi vào thanh ghi này, không có gì xảy ra. Điều này có thể được sử dụng để xóa văn bản mà không ảnh hưởng đến các thanh ghi thông thường. Khi đọc từ thanh ghi này, không có gì được trả về. {Không phải trong Vi}"


1
Tôi đã sử dụng nó vnoremap p "_dP mapvà nhận thấy rằng nó không hoạt động tốt cho từ / ký tự cuối cùng trong một dòng. Tôi đã trở lại ra đi vào vnoremap p "0p, vnoremap P "0Pset clipboard=unnamed(cho OSX)
Kache

vnoremap p "_dPngừng làm việc cho tôi trong chế độ chọn, nhưng vnoremap <leader>p "_dPvẫn hoạt động
whitesiroi

1
có thể <leader>là một trình giữ chỗ mà tôi phải biết để thay thế bằng thứ gì đó, nhưng điều này chỉ hiệu quả với tôi nếu tôi gỡ bỏ nó. Nó có nghĩa là gì ở đây?
Hashbrown

1
@Hashbrown :help mapleader,.
romainl

Thông báo trước: vnoremap <leader>pánh xạ không hoạt động chính xác trên dòng cuối cùng của bộ đệm vì ngay sau khi bạn xóa dòng cuối cùng của bộ đệm, bây giờ bạn đang ở dòng một giây cuối cùng và Psẽ dán phía trên dòng đó, thay vì bên dưới.
Kal

13

Ngoài bộ đệm tiêu chuẩn, bạn có thể kéo văn bản vào các bộ đệm được đặt tên, sau đó đặt từ các bộ đệm được đặt tên. Có tới 26 bộ đệm được đặt tên mà bạn có thể sử dụng (một cho mỗi chữ cái). Sử dụng dấu ngoặc kép và một chữ cái để truy cập vào bộ đệm có tên. Ví dụ:

"dyy - Yank dòng hiện tại vào bộ đệm d.
"a7yy- Yank bảy dòng tiếp theo vào bộ đệm a.
"dP- Đặt nội dung của bộ đệm d trước con trỏ.
"ap- Đặt nội dung của bộ đệm a sau con trỏ

Một điều thú vị khác, nếu bạn sử dụng chữ in hoa thay vì chữ thường, tức là "Dyydòng hiện tại sẽ được gắn vào bộ đệm d thay vì thay thế nó. Thêm chi tiết trong cuốn sách O`Reilly: http://docstore.mik.ua/orelly/unix/vi/ch04_03.htm


3
Điều rất mát mẻ. Tôi biết về bộ đệm, nhưng không kết nối chúng với vấn đề này. Nó vẫn còn cồng kềnh với "amọi thứ, nhưng không sao.
bitmask

4

Khi sử dụng putở chế độ trực quan, văn bản bạn đang thay thế wrong1sẽ bị ghi đè bởi nội dung của thanh ghi 'chưa được đặt tên'.

Điều này thực sự hoạt động bằng cách 'đặt' thanh ghi sau khi lựa chọn và sau đó xóa lựa chọn. Vấn đề là việc xóa này hiện được lưu trữ trong thanh unnamedghi và sẽ được sử dụng cho puthành động tiếp theo .

Giải pháp, theo :h v_p, là kéo vào một thanh ghi có tên, chẳng hạn như "0y, sau đó dán bằng cách sử dụng "0pbao nhiêu lần bạn cần. Có thể hữu ích khi lập bản đồ <leader>y<leader>psử dụng một thanh ghi có tên, nếu đây là việc bạn thường xuyên làm.

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

để được trợ giúp thêm xem:

:help v_p
:help map

Giải pháp này có vẻ hữu dụng nhất, cho đến khi một cái gì đó thông minh xuất hiện từ chính vim.
Joly Julum

4

Dán từ "0đăng ký là quan trọng để biết, nhưng bạn thường muốn thay thế nhiều lần. Nếu bạn thực hiện nó thành một hành động lặp lại, bạn có thể sử dụng .toán tử, như được ám chỉ bởi garyjohn. Nó được giải thích trên wiki vim :

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". 

3

Khi bạn kéo văn bản vào thanh ghi không tên *, một bản sao cũng được đưa vào thanh ghi 0. Mỗi lần bạn thay thế văn bản đã chọn, bạn chỉ có thể dán từ thanh ghi 0. Xem

:help registers

Ngoài ra, nếu bạn đang thay thế một số từ bằng cùng một từ, bạn có thể chỉ cần di chuyển đến đầu của từ cần thay thế và gõ .. Điều đó sẽ lặp lại thao tác chỉnh sửa cuối cùng. Xem

:help single-repeat

* Các vị trí lưu trữ mà bạn kéo vào và đặt vào được gọi là các thanh ghi. Bộ đệm là thứ bạn chỉnh sửa, thường là bản sao của tệp từ đĩa.


1

Tôi cần điều này thường xuyên, tôi đã viết một plugin cho điều đó: Thay thếWithRegister .

Plugin này cung cấp một lệnh hai trong một grthay thế văn bản được bao phủ bởi {motion}, toàn bộ dòng hoặc lựa chọn hiện tại với nội dung của một thanh ghi; văn bản cũ bị xóa vào thanh ghi lỗ đen, tức là nó đã biến mất.


1

Vì một cái gì đó như vnoremap p "_dP(tôi cũng đã thử xhoặc c) có vấn đề với đầu và cuối dòng, tôi đã kết thúc việc này: vnoremap p :<C-U>let @p = @+<CR>gvp:let @+ = @p<CR>tôi thấy đơn giản hơn các plugin hiện có (cũng không hoạt động với set clipboard=unnamedplushộp). Vì vậy, những gì nó làm là:

  • chuyển sang chế độ lệnh
  • xóa phạm vi ( C-U)
  • +đăng ký dự phòng (do không có tên, các lựa chọn thay thế "*tùy thuộc vào cấu hình của bạn) đểp
  • phục hồi lựa chọn và dán
  • chuyển sang chế độ lệnh một lần nữa
  • phục hồi đăng ký

Hoàn hảo! Đây là lựa chọn đầu tiên trong số các tùy chọn này hoạt động chính xác như mong đợi đối với tôi. Cảm ơn!
Jamis Charles

1

Đây là những gì tôi sử dụng (được sao chép theo nghĩa đen từ .vimrc của tôi) cho kiểu điều khiển Windows + X cut / Control + C copy / Control + V paste / Control + S save / Control + F find / Control + H thay thế hành vi.

Hàm smartpaste () sẽ chứa những gì bạn tìm kiếm, tức là một cách để dán lên văn bản được tô sáng mà không cần đồng thời đánh dấu những gì đã chọn.

" 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

-1

tl; dr - vnoremap p "_c *

Dưới đây là danh sách các ánh xạ đầy đủ của tôi:
"Fix đăng ký sao chép / dán
nnoremap DD" * dd
nnoremap D "* d
vnoremap D" d
nnoremap d "_D
nnoremap dd" _dd
vnoremap d "_D
nnoremap s" _s
vnoremap s "_s
nnoremap c "_c
vnoremap c" _c
nnoremap x "_x
vnoremap x" _x
vnoremap p "_c

"Dán trên
nnoremap dòng mới , p op
nnoremap, P Op

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.