如何注释VIM宏

4

有没有可能对宏进行注释并重放它。

示例

不是:

  dddwj

我想评论并执行以下片段。
  dd # Delete line
  dw # Delete word
  j  # Move to next line

一些背景

我们使用PICT来生成测试用例输入(全对测试)。由于这是一个迭代的过程,因此在后续运行之间需要调整生成代码的宏。如果所有内容都在一行上且没有注释,修改宏会很困难。

PICT运行的输出可能类似于以下内容:

1 cInstallationX Pu380
2 cInstallationY U400

可以使用宏将其转换为测试用例。
procedure TWatchIntegrationTests.Test1;
begin
  //***** Setup
  builder
    .withInstallation(cInstallationX)
    .withIsotope(Pu380)
  .Build;

  //***** Execute
  CreateAndCollectWatches;

  //***** Verify
  VerifyThat
    .toDo;
end;

procedure TWatchIntegrationTests.Test2;
begin
  //***** Setup
  builder
    .withInstallation(cInstallationY)
    .withIsotope(U400)
  .Build;

  //***** Execute
  CreateAndCollectWatches;

  //***** Verify
  VerifyThat
    .toDo;
end;
2个回答

11

我不知道使用宏的好方法,但我可以看到几个可能会有所帮助的选项:

大量使用 'normal'

这是最接近您宏选项的方法,但不是非常好:使您保存的文件看起来像这样:

" Delete line
normal dd
" Delete word
normal dw
" Move to next line
normal j

复杂的替换

这个方法使用正则表达式,但是为了让这些正则表达式易于理解,进行了详细的注释(基于实际例子)。

let pattern  = '^'              " Start of line
let pattern .= '\(\d\+\)'       " One or more digits (test number)
let pattern .= '\s\+'           " Space or tab as delimiter
let pattern .= '\(\k\+\)'       " Installation name
let pattern .= '\s\+'           " Space or tab as delimiter
let pattern .= '\(\a\+\d\+\)'   " One or more alphabetic characters, then one or more spaces (isotope)
let pattern .= '\s*$'           " Any spaces up to the end of the line

let result  = 'procedure TWatchIntegrationTests.Test\1;\r'
let result .= 'begin\r'
let result .= '  //***** Setup\r'
let result .= '  builder\r'
let result .= '    .withInstallation(\2)\r'
let result .= '    .withIsotope(\3)\r'
let result .= '  .Build;\r'
let result .= '\r'
let result .= '  //***** Execute\r'
let result .= '  CreateAndCollectWatches;\r'
let result .= '\r'
let result .= '  //***** Verify\r'
let result .= '  VerifyThat\r'
let result .= '    .toDo;\r'
let result .= 'end;\r'

exe '%s!' . pattern . '!' . result . '!'

将其放入函数中

考虑到这已经变得相当复杂,我可能会这样做,因为它给了更多的调整空间。按照我的理解,你想在空格上拆分该行并使用三个字段,所以可以尝试如下代码:

" A command to make it easier to call
" (e.g. :ConvertPICTData or :'<,'>ConvertPICTData)
command! -range=% ConvertPICTData <line1>,<line2>call ConvertPICTData()

" Function that does the work
function! ConvertPICTData() range
    " List of lines producing the required template
    let template = [
                \ 'procedure TWatchIntegrationTests.Test{TestNumber};',
                \ 'begin',
                \ '  //***** Setup',
                \ '  builder',
                \ '    .withInstallation({Installation})',
                \ '    .withIsotope({Isotope})',
                \ '  .Build;',
                \ '',
                \ '  //***** Execute',
                \ '  CreateAndCollectWatches;',
                \ '',
                \ '  //***** Verify',
                \ '  VerifyThat',
                \ '    .toDo;',
                \ 'end;',
                \ '']

    " For each line in the provided range (default, the whole file)
    for linenr in range(a:firstline,a:lastline)
        " Copy the template for this entry
        let this_entry = template[:]

        " Get the line and split it on whitespace
        let line = getline(linenr)
        let parts = split(line, '\s\+')

        " Make a dictionary from the entries in the line.
        " The keys in the dictionary match the bits inside
        " the { and } in the template.
        let lookup = {'TestNumber': parts[0], 
                    \ 'Installation': parts[1],
                    \ 'Isotope': parts[2]}

        " Iterate through this copy of the template and 
        " substitute the {..} bits with the contents of
        " the dictionary
        for template_line in range(len(this_entry))
            let this_entry[template_line] = 
                        \ substitute(this_entry[template_line], 
                        \   '{\(\k\+\)}', 
                        \   '\=lookup[submatch(1)]', 'g')
        endfor

        " Add the filled-in template to the end of the range
        call append(a:lastline, this_entry)
    endfor

    " Now remove the original lines
    exe a:firstline.','.a:lastline.'d'
endfunction

使用Python实现

这种任务可能更容易用Python来完成:

import sys

template = '''
procedure TWatchIntegrationTests.Test%(TestNumber)s;
begin
  //***** Setup
  builder
    .withInstallation(%(Installation)s)
    .withIsotope(%(Isotope)s)
  .Build;

  //***** Execute
  CreateAndCollectWatches;

  //***** Verify
  VerifyThat
    .toDo;
end;
'''

input_file = sys.argv[1]
output_file = input_file + '.output'

keys = ['TestNumber', 'Installation', 'Isotope']

fhIn = open(input_file, 'r')
fhOut = open(output_file, 'w')

for line in fhIn:
    parts = line.split(' ')
    if len(parts) == len(keys):
        fhOut.write(template % dict(zip(keys, parts)))
fhIn.close()
fhOut.close()

要使用这个功能,将其保存为(例如)pict_convert.py 并运行:

python pict_convert.py input_file.txt
它会生成input_file.txt.output作为结果。

非常令人印象深刻。如果您不知道如何使用宏并且查看您所知道的内容使我认为这是不可能的。您的函数实现对我来说看起来足够匹配。我会尝试一下。 - Lieven Keersmaekers
1
很高兴你喜欢它!我还添加了一种使用Python的替代方法:如果你想批量转换大量文件,这比Vim更容易使用。 - DrAl

4
首先,让我指出@Al发布了几个非常优秀的解决方案,我建议您使用那些方案而不是我即将发布的方案。特别是因为那些方案似乎在某些情况下不起作用(原因我不理解)。
话虽如此,在这种情况下,以下内容似乎可以实现您想要的功能。它假设在正常模式下未用于移动光标。将其映射到:“其中是cmline模式的注释字符。这意味着在这种情况下是开始注释的字符。结尾处的换行符停止注释。 #只是为了使我们处理注释更清晰。(^[应输入为单个转义字符)。
:nmap <Space> :"
iHallo wereld^[             # Insert text (in dutch, better change that)
Fe                          # Move backwards to e
x                           # Delete
;                           # Move to next e
ro                          # Change to o
Fa                          # Move backwards to a
re                          # Change to e
A!^[                        # Add exclamation mark

+1 但是我发布的只是实际“宏”的一部分。 Al发布的函数对我们来说是最佳匹配。 预先感谢您的努力。 - Lieven Keersmaekers
在翻译中,Lieven @PvdHeijden说:“+1,但是我发布的只是真正“宏”的一部分。像Al发布的那样使用函数对我们来说是最好的匹配。再次感谢您的努力。” - sehe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接