11

经常在 vim 中查看日志文件时,我会使用标记突出显示有趣的行。在某些时候,我希望能够将所有有趣的行(所有标记的行或标记列表)复制到寄存器或另一个文件(哪个并不重要;目标是便于编写摘要)。我还没有找到任何内置的方法来做到这一点;在vim中可以吗?

我想这可能是一个相当简单的功能。可能看起来像这样,但我的 vimscript 能力很弱:

for cur_mark in list_of_marks
    goto mark
    yank current line and append to register

有没有人写过类似的东西可以指点我?

谢谢

编辑:我在https://github.com/mikeage/vim-yankmarks发布了接受的解决方案

4

6 回答 6

7

与往常一样,没有什么比寻求帮助更能激励人的事情了。这就是我想出的;欢迎反馈。

function! Yankmark()
    let save_cursor = getpos(".")
    let n = 0
    " I should really make this a parameter...
    let marks_to_yank="abcdefghijklmnopqrstuvwxyz"
    let nummarks = strlen(marks_to_yank)
    " Clear the a register
    let @a=''
    while n < nummarks
        let c = strpart(marks_to_yank, n, 1)
        " Is the mark defined
        if  getpos("'".c)[2] != 0
            " using g' instead of ' doesn't mess with the jumplist
            exec "normal g'".c
            normal "Ayy
        endif
        let n = n + 1
    endwhile
    call setpos('.', save_cursor)
endfunction
于 2013-05-01T07:55:07.227 回答
6

Mikeage 有一个好主意。这是他的函数的一个更精致的版本,变成了一个命令:

":YankMarks [{marks}] [{register}]
"                   Yank all marked (with [a-z] / {marks} marks) lines into
"                   the default register / {register} (in the order of the
"                   marks).
function! s:YankMarks( ... )
    let l:marks = 'abcdefghijklmnopqrstuvwxyz'
    let l:register = '"'
    if a:0 > 2
        echohl ErrorMsg
        echomsg 'Too many arguments'
        echohl None
        return
    elseif a:0 == 2
        let l:marks = a:1
        let l:register = a:2
    elseif a:0 == 1
        if len(a:1) == 1
            let l:register = a:1
        else
            let l:marks = a:1
        endif
    endif

    let l:lines = ''
    let l:yankedMarks = ''
    for l:mark in split(l:marks, '\zs')
        let l:lnum = line("'" . l:mark)
        if l:lnum > 0
            let l:yankedMarks .= l:mark
            let l:lines .= getline(l:lnum) . "\n"
        endif
    endfor

    call setreg(l:register, l:lines, 'V')

    echomsg printf('Yanked %d line%s from mark%s %s',
    \   len(l:yankedMarks),
    \   len(l:yankedMarks) == 1 ? '' : 's',
    \   len(l:yankedMarks) == 1 ? '' : 's',
    \   l:yankedMarks
    \) . (l:register ==# '"' ? '' : ' into register ' . l:register)
endfunction
command! -bar -nargs=* YankMarks call <SID>YankMarks(<f-args>)
于 2013-05-01T19:57:21.407 回答
4

完成此操作的另一种方法可能是使用该:global命令。全局命令采用:g/{pattern}/{cmd}. 命令 ,{cmd}将在所有匹配的行上执行{pattern}

将匹配模式的行附加到寄存器:

:g/pattern/yank A

将匹配行附加到日志文件:

:g/pattern/w >> file.log

当然,如果你想找到匹配标记的行,你可以在你的模式中匹配它。以下模式匹配带有标记的行m

:g/\%'m/w >> file.log

做这样的事情。(注:我是\v用来开启很神奇的)

:g/\v(%'a|%'b|%'m)/yank A

当然,如果模式不起作用,您可以手动执行此操作。而不是标记线只是在你去的时候建立线。只需将一行拉到大写寄存器即可追加。

"Ayy

或者使用单行范围进行写入附加

:.w >> file.log

如需更多帮助,请参阅

:h :g
:h :w_a
:h /\%'m
:h /\v
于 2013-05-01T14:08:31.647 回答
3

您可以执行以下操作:

:redir @a
:silent marks XYZN
:redir END
"ap

这样:marks命令的输出将被重定向到a寄存器。请注意,它只会列出(在上述情况下)X、、Y和标记(作为参数) ZN如果有a寄存器,它将被删除/覆盖。

另请注意,它可能不会提供所需的输出,但会为您提供一个起点......

于 2013-05-01T08:03:07.977 回答
3

我喜欢 Mikeage 的解决方案,尽管我可能会使用多选来解决这个问题- 创建多项选择并操作插件。这还有一个好处是你不会用完标记。

使用该插件,您可以选择带有<Leader>msa或的行:MSAdd。最后,用以下命令拉出所有行:

:let @a=''
:MSExecCmd yank A
于 2013-05-01T18:44:34.280 回答
2

如果在拉入特定寄存器时使用大写的寄存器名称,Vim 将追加拉出的内容,而不是覆盖寄存器的值。

因此,例如:

  • "ayy- 抽出当前行来注册a,覆盖

  • [移动]

  • "Ayy- 附加此行进行注册a

  • [移动]

  • "ap- 粘贴所有拉出的材料

有关:help quotea更多详细信息,请参阅。

于 2013-05-01T11:53:28.997 回答