Я не знаю хорошего способа сделать это с помощью макросов, но я вижу несколько вариантов, которые могут помочь:
Интенсивное использование «нормального» * 1003 *
Это самый близкий к вашему макросу вариант, но не очень приятный: сделайте ваш сохраненный файл похожим на это:
" 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:
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
.