68 votes

Comment remplacer-coller du texte arraché dans vim sans arracher les lignes supprimées ?

Je me retrouve donc généralement à copier du texte d'un point à un autre tout en écrasant l'ancien texte là où le nouveau est collé :

blah1
newtext
blah2
wrong1
blah3
wrong2
blah4

Supposons que je marque visuellement newtext y y ank it. Maintenant, je sélectionne wrong1 (qui peut être n'importe quoi, pas nécessairement un mot) et p aste le newtext . Cependant, si je fais maintenant la même chose avec wrong2 il sera remplacé par wrong1 au lieu de newtext .

Comment éviter que le texte qui se trouve dans la mémoire tampon ne soit échangé avec le texte que je suis en train d'écraser ?

Edit 1

Bien que j'aime beaucoup les suggestions de registres (je pense que je vais commencer à utiliser les registres plus souvent, maintenant que j'ai découvert l'option :dis ), j'opte pour une modification de la commande jinfield Je n'ai pas répondu à cette question, car je n'utilise pas le mode de permutation.

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

fait parfaitement l'affaire.

Edit 2

J'étais trop rapide ; romainl La solution de l'entreprise est précisément ce que je cherchais, sans le piratage de l'internet. Edit 1 .
En fait, vnoremap p "_dP est suffisant !
Donc, changement de réponse accepté.

1voto

jopa Points 800

J'en ai si souvent besoin que j'ai écrit un plugin pour cela : ReplaceWithRegister .

Ce plugin offre un deux-en-un gr commande qui remplace le texte couvert par un {mouvement}, une ou plusieurs lignes entières ou la sélection courante par le contenu d'un registre ; l'ancien texte est effacé dans le registre du trou noir, c'est-à-dire qu'il disparaît.

1voto

FocusedWolf Points 111

C'est ce que j'utilise pour le comportement de style Windows Control + X cut/Control + C copy/Control + V paste/Control + S save/Control + F find/Control + H replace.

La fonction SmartPaste() devrait contenir ce que vous cherchez, c'est-à-dire un moyen de coller sur du texte en surbrillance sans arracher simultanément ce qui était sélectionné.

" Windows common keyboard shortcuts and pasting behavior {{{

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

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 = strchars(getline(selectionEndLine))
    let nextLineLength = strchars(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.
        "
        " Silent was added to suppress "W10: Warning: Changing a readonly file"
        " I got this message while trying to edit a file that was not actually readonly but rather only administrator-editable because it was located in a protected Windows folder.
        " Another way to fix this it is to do "set noro" (if &readonly), and reapply the readonly state after the append with "set ro" (if was readonly).
        " NOTE: "silent!" hides error messages and normal messages, and "silent" just hides normal messages.
        silent 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>+

" Copy :messages to the clipboard.
" NOTE: This is a workaround for not being able to select-all + copy messages.
nnoremap <silent> <Leader>m :redir @*<BAR>silent execute ':messages'<BAR>redir END<CR>

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

    " 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
    " NOTE: <C-u> removes the '<,'> visual-selection from the command line. See :h c_CTRL-u
    nnoremap <C-z> <Esc>u
    vnoremap <C-z> :<C-u>uV
    inoremap <C-z> <Esc>uI

    nnoremap <C-y> <Esc><C-r>
    vnoremap <C-y> :<C-u><C-r>V
    inoremap <C-y> <Esc><C-r>I

    " Disable Vim normal-mode undo/redo keys.
    " NOTE: Disabled in part because <C-z> and <C-y> are mapped to undo/redo and also because visual-mode 'u' and 'U' manipulating the selected text case is useful, but also having 'u' as normal-mode undo is an accident waiting to happen.
    " SOURCE: https://stackoverflow.com/questions/57714401/vi-vim-remap-or-unmap-built-in-command-the-u-key-in-visual-mode
    nnoremap u <NOP>
    nnoremap <C-r> <NOP>

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

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

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

    " NOTE: <C-u> removes the '<,'> visual-selection from the command line. See :h c_CTRL-u
    vnoremap <silent> <C-f> :<C-u>call Find()<CR>
    vnoremap <silent> <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 <silent> <C-f> <C-o>:call Find()<CR>
    inoremap <silent> <C-h> <C-o>:call Replace()<CR>
endif

" }}} Windows common keyboard shortcuts and pasting behavior

1voto

Tom Halladay Points 2387

Comme quelque chose comme vnoremap p "_dP (J'ai aussi essayé x o c ) a des problèmes avec le début et la fin de la ligne, j'ai fini par faire ceci : vnoremap p :<C-U>let @p = @+<CR>gvp:let @+ = @p<CR> que j'ai trouvé plus simple que les plugins existants (qui ne fonctionnaient pas non plus avec set clipboard=unnamedplus hors de la boîte). Donc ce qu'il fait c'est :

  • passer en mode commande
  • supprimer la gamme ( C-U )
  • sauvegarde + (en raison de l'absence de nom, les alternatives sont les suivantes " y * en fonction de votre configuration) pour p
  • récupérer la sélection et coller
  • repasser en mode commande
  • récupérer le registre

1voto

pallly Points 111

La solution suivante pourrait fonctionner dans de nombreux cas : c + CtrlR + 0 + Esc .
Vous pourriez avoir besoin de faire

:set paste

avant d'inhiber l'indentation automatique.

1voto

Brother Erryn Points 803

を使用しています。 clipboard=unamedplus J'ai donc découvert que beaucoup de solutions proposées ici ne fonctionnaient pas parce que le collage mettait le texte écrasé en "+ au lieu de "" . J'ai en outre constaté que "_dP a eu des problèmes à la fin des lignes.

Cependant, j'ai découvert qu'en utilisant c travaillé.

set clipboard=unnamedplus " Use system clipboard.

" Don't put pasted-over content into the clipboard.
vnoremap p "_c<C-r><C-o>+<Esc>

En gros, cela c modifie le texte, et utilise un collage en mode insertion ( <C-r><C-o>+ ) du registre sans nom. Comme le curseur du mode insertion peut se trouver après le dernier caractère d'une ligne, cela ne pose aucun problème en fin de ligne.

Des ajustements possibles :

  • Si vous ne voulez pas remplacer l'habituel p utilisez simplement la commande <Leader>p .
  • Si vous utilisez un registre différent du clibboard, remplacez + con " o * .

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X