在vim中使用所有标记的行

时间:2013-05-01 07:16:20

标签: vim

通常在查看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

发布了已接受的解决方案

6 个答案:

答案 0 :(得分: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

答案 1 :(得分:6)

迈克奇有个好主意;这是一个更精致的函数版本变成了一个命令:

":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>)

答案 2 :(得分: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

答案 3 :(得分:3)

您可以执行以下操作:

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

这样,:marks命令的输出将被重定向到a寄存器。请注意,它仅列出(在上述情况下)XYZN标记(作为参数),以及是否有{ {1}}注册,它将被删除/覆盖。

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

答案 4 :(得分:3)

我喜欢Mikeage的解决方案,不过我可能会使用multiselect - Create multiple selections and operate插件来解决这个问题。这样做的好处是你不会用完标记。

使用该插件,您可以选择<Leader>msa:MSAdd行。最后,用以下方式猛拉所有行:

:let @a=''
:MSExecCmd yank A

答案 5 :(得分:2)

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

所以,例如:

  • a y y - 向当前行注册a,覆盖

  • [移动]

  • A y y - 将此行追加至注册a

  • [移动]

  • a p - 粘贴所有被拽的材料

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

相关问题