Простой способ выровнять текст в столбцах - использовать плагин Tabular или Align .Если ни один из них не готов, можно использовать следующие несколько хитрые (и немного громоздкие), но прекрасно работающие (для рассматриваемого случая) команды. 1,2
:let m=0|g/\ze -- /let m=max([m,searchpos(@/,'c')[1]])
:%s//\=repeat(' ',m-col('.'))
Цель первой команды - определить ширину столбца слева от разделителя (здесь я предполагаю --
).Ширина рассчитывается как максимальная длина текста в первом столбце среди всех строк.Команда :global
используется для перечисления строк, содержащих разделитель (другие строки не требуют выравнивания).Атом \ze
, расположенный сразу после начала шаблона, устанавливает конец матча в той же позиции, где он начинается (см. :help \ze
).Изменение границ соответствия не влияет на работу команды :global
, шаблон написан таким образом, чтобы соответствовать потребностям следующей команды замещения: поскольку эти две команды могут использовать один и тот же шаблон, его можно опуститьво втором.
Команда, которая запускается на совпавших строках,
:let m=max([m,searchpos(@/,'c')[1]])
вызывает функцию searchpos()
для поиска шаблона, используемого в родительской команде :global
,и получить положение столбца матча.Шаблон упоминается как @/
с использованием последнего регистра шаблона поиска (см. :help
"/
).Это использует тот факт, что команда :global
обновляет регистр /
, как только он начинает выполняться.Флаг c
, передаваемый в качестве второго аргумента в вызове searchpos()
, позволяет сопоставить первый символ строки (:global
помещает курсор в самое начало строки для выполнения команды), поскольку он можетбудь то, что нет текста слева от разделителя.Функция searchpos()
возвращает список, первый элемент которого является номером строки совпадающей позиции, а второй - позицией столбца.Если команда выполняется в строке, строка соответствует шаблону содержащей команду :global
.Поскольку searchpos()
должен искать один и тот же шаблон, на этой строке определенно есть совпадение.Поэтому интерес представляет только столбец, начинающий сопоставление, поэтому он извлекается из возвращаемого списка с помощью индекса [1]
.Эта самая позиция равна ширине текста в первом столбце строки плюс один.Таким образом, m
устанавливается на максимум его текущего значения и этой позиции столбца.
Вторая команда,
:%s//\=repeat(' ',m-col('.'))
дополняет первое вхождение разделителя во всех строкахкоторые содержат его, с количеством пробелов, которые отсутствуют, чтобы текст перед разделителем занимал m
символов, минус один.Эта команда является глобальной заменой, заменяющей пустой интервал непосредственно перед разделителем (см. Комментарий о команде :global
выше) результатом вычисления выражения (см. :help sub-replace-\=
)
repeat(' ',m-col('.'))
repeat()
Функция повторяет свой первый аргумент (в виде строки) количество раз, указанное во втором аргументе.Поскольку при каждой замене курсор перемещается в начало сопоставления с образцом, m-col('.')
в точности соответствует количеству пробелов, необходимых для смещения разделителя вправо для выравнивания столбцов (col('.')
возвращает текущую позицию курсора в столбце).
1 Ниже приведена однострочная версия этой пары команд.
:let m=0|exe'g/\ze -- /let m=max([m,searchpos(@/,"c")[1]])'|%s//\=repeat(' ',m-col('.'))
2 В предыдущих редакцияхОтветом для команд были следующие:
:let p=[0]|%s/^\ze\(.*\) -- /\=map(p,'max([v:val,len(submatch(1))+1])')[1:0]/
:exe'%s/\ze\%<'.p[0].'c -- /\=repeat(" ",'.p[0].'-col("."))'
Те, кто интересуется этими конкретными командами, могут найти подробное описание в истории правок.