«Вы не понимаете. Vim — это как язык! Вы будете говорить на Vim, когда будете писать! Когда вы идете на рынок! Вы будете говорить на Vim со своей кошкой! Когда ты будешь думать, в твоей голове будет Слово Vim™! Вы увидите! Это изменит вашу жизнь!»
Именно такие аргументы любой Vim-хиппи будет петь бедным еретикам, пытаясь обратить их в «Вечный редактор». Такой хиппи, как я, который сейчас пишет статью об одном из главных компонентов этого «языка» — тексте-объекте. Повторяйте за мной: слава текстовым объектам!
Их использование — это мощно, это правда; но мы можем сделать лучше. Мы могли бы создавать новые тексты-объекты, как бог создает жизнь! Мы могли бы формировать Хаос, чтобы навести порядок в галактике!
Греческий бог Гефест создал огонь в своей легендарной кузнице. Как и ему, нам тоже нужны инструменты для создания наших собственных текстовых объектов. Что мы можем использовать? Vimscript?
С помощью Neovim мы можем использовать Lua для настройки нашего любимого редактора; мы также можем скомпилировать Vim с поддержкой Lua. На мой взгляд, один из лучших способов научиться настраивать Vim — это брать уже написанные функции в Vimscript и преобразовывать их в Lua.
Преимущества:
- Если вы не знаете Vimscript, анализ кода для преобразования его в Lua покажет вам полезные функции, которые вы сможете использовать для дальнейшей настройки. Это необходимо для использования возможностей Vim.
- Если вы не знаете Lua, вы тоже можете изучить его таким образом. Это отличный язык программирования, используемый многими другими инструментами, такими как, например, фантастический Pandoc.
- Вы получите более глубокое понимание того, как работает Vim, что позволит вам улучшить свой рабочий процесс.
Итак, давайте попробуем силу функций Vimscript в сочетании с конструкциями Lua, реализуя полезные текстовые объекты. Более конкретно мы рассмотрим в этой статье:
- Общие принципы работы с текстовыми объектами.
- Как создать текстовый объект, представляющий линию.
- Как создавать текстовые объекты, разделенные парой символов, например двумя запятыми.
- Как создать очень полезный — и довольно универсальный — текстовый объект, соответствующий некоторому уровню отступа.
Тексты-объекты, которые мы будем создавать, вдохновлены другими авторами из The Great Internet™. Источники вдохновения вы найдете в конце статьи.
Я предполагаю, что вы в той или иной степени владеете Vim. Если вы не понимаете, что происходит в этой статье, вы можете обратиться к моей серии статей по изучению Vim.
Если вы впервые пишете на Lua, я бы посоветовал вам доработать примеры, которые мы рассмотрим в этой статье. Чтобы использовать правильный синтаксис, вам следует держать под рукой краткое руководство, как, например, это.
Готовы ли вы погрузиться в Vimscript, Lua и текстовые объекты? Я уверен, что да! Поехали!
- Что такое текстовый объект?
- Справка Vim
- Сопоставление операторов
- Основы
- Строка: Наш новый текстовый объект
- Справка Vim
- Недостающие текстовые объекты
- Между двумя символами
- К следующему текстовому объекту
- Текстовые объекты на основе отступов
- Основы
- Улучшение реализации
- Сопоставление функции Lua
- Сила объекта Text-Object
- Ссылки
- Учимся играть в Vim: Увлекательное руководство по изучению лучшего редактора
Что такое текстовый объект?
Прежде чем перейти в Vim для создания наших новых восхитительных текстовых объектов, давайте сначала сделаем то, что должен делать любой разработчик, когда ему нужно решить проблему: подумаем. Давайте разложим, что такое текстовый объект:
- Текст-объект — это нажатие клавиш в НОРМАЛЬНОМ режиме с использованием двух клавиш, первая из которых может быть только «a» (для «
a
round») или «i» (для «i
nside»). - Текст-объект представляет собой определенную строку символов с началом и концом.
- Его можно использовать только после оператора или после переключения в ВИЗУАЛЬНЫЙ режим работы с символами (используя «v» в НОРМАЛЬНОМ режиме).
- Оператор действует на текст-объект, а режим VISUAL выделяет сам текст-объект.
- Чтобы применить оператор к некоторым текстовым объектам, курсор не обязательно должен находиться на самом текстовом объекте. В этом случае оператор будет действовать на следующий текстовый объект строки.
Если вы никогда не слышали о правиле 5, оно может изменить вашу жизнь и принести вам славу и богатство за пару дней. Не меньше! Если вы набираете di(
в НОРМАЛЬНОМ режиме, и ваш курсор находится перед парой круглых скобок, вы переместитесь внутрь них. Оператор d
удалит все, что находится внутри. Отлично!
Как я уже говорил выше, текст-объект может начинаться с буквы «a» или «i». Я понимаю текстовые объекты, начинающиеся с «a», как «a
round», даже если справка Vim будет называть их неопределенным артиклем a
, например d
elete a
w
ord. Я предпочитаю «вокруг», потому что такие текстовые объекты часто включают некоторые символы вокруг «внутреннего» текстового объекта. Это хорошая мнемоника для запоминания разницы между ними.
Движения очень похожи на текст-объекты, но это не одно и то же. Использование оператора перед движением приводит к выполнению действия от позиции курсора до конечного результата движения. Текст-объект не обязательно начинается с позиции курсора, и это самое большое различие.
Например, daw
удалит d
вокруг a
орда w
, независимо от буквы слова, на котором находится ваш курсор. Используя движение, dw
удалит от позиции курсора до следующего w
орда.
Теперь, когда мы исследовали пространство проблемы, давайте войдем в пространство решения. Чтобы создать текстовый объект с началом и концом, мы можем просто:
- Выделите нужные нам символы.
- Примените любой оператор к выделению.
Это замечательно, потому что в Vim есть несколько отображений, позволяющих нам легко это сделать.
Справка Vim
:help text-object
:help motion
Сопоставление операторов
Основы
Когда мы нажимаем оператор в НОРМАЛЬНОМ режиме (например, d
, y
или c
), мы беззвучно переключаемся в режим OPERATOR-PENDING. Именно в этом режиме мы будем вводить наше движение (или текст-объект), с которым хотим работать. Затем мы автоматически переключаемся обратно в НОРМАЛЬНЫЙ режим.
Чтобы определить новые текстовые объекты (или движения), которые могут быть использованы в режиме OPERATOR-PENDING, вы можете использовать operator-pending mapping: omap
или, если вам не нужен рекурсивный маппинг, onoremap
. Благодаря им нам нужно беспокоиться только о выборе символов, входящих в наши текстовые объекты; сами операторы нас не волнуют.
Строка: Наш новый текстовый объект
Давайте теперь создадим первый текстовый объект этой статьи: строку.
- Текст-объект
al
(«a
round thel
ine) удалит все, включая возможные отступы в начале. - Текст-объект
il
(i
внутриl
ine) не удалит отступы.
Вот первое отображение для il
:
onoremap <silent> il :<c-u>normal! $v^<cr>
Если вы не знаете, что это значит, вот некоторые пояснения:
Например, если вы нажмете yil
или dil
, ваши операторы y
ank и d
elete будут действовать на наш новый текст-объект. Если мы хотим только выделить его, нам понадобится другое отображение для режима VISUAL:
xnoremap <silent> il :<c-u>normal! $v^<cr>
Теперь вы можете нажать vil
и восхититься потенциалом ваших бесконечных навыков.
Теперь у нас есть «внутренняя» версия нашего текстового объекта; а как насчет «внешней»?
xnoremap <silent> al :<c-u>normal! $v0<cr>
onoremap <silent> al :<c-u>normal! $v0<cr>
Эти отображения следуют тем же принципам, за исключением того, что на этот раз мы выделяем все, включая возможные пробельные символы в начале строки. Мы также можем использовать V
вместо $v0
.
Справка Vim
:help omap-info
Недостающие текстовые объекты
Наши новые текстовые объекты — это здорово, но мы можем сделать лучше. На этот раз мы создадим целую серию, разделенную разными парами символов.
Между двумя символами
Удалить пару круглых скобок очень просто: a(
, a)
, или даже ab
. Как всегда, есть и варианты «внутри». Но как насчет удаления всего между двумя точками? Между двумя дефисами? Между двумя запятыми?
Как насчет создания текстовых объектов, разделенных этими символами: ,
,.
,;
,:
,+
,-
,=
,~
,_
,*
,#
,/
,|
,,
&
, $
, ?
?
Чтобы решить эту проблему, мы можем рассмотреть простой пример:
Hello, how are you, you?
Если мы хотим изменить символы между двумя запятыми, мы можем:
- Подвести курсор к первой запятой.
- Выделить все до второй запятой.
- Включение запятых в выделение или нет будет являться разницей между текстовым объектом «вокруг» и «внутри».
Этот сценарий требует, чтобы наш курсор находился между двумя запятыми, по крайней мере, сейчас. Мы улучшим это в ближайшее время.
Чтобы переместить курсор к первой или второй запятой, мы можем использовать f
, F
, t
и T
в НОРМАЛЬНОМ режиме. Вот возможное решение:
xnoremap <silent> i, :<c-u>normal! T,vt,<cr>
onoremap <silent> i, :<c-u>normal! T,vt,<cr>
xnoremap <silent> a, :<c-u>normal! F,ft,<cr>
onoremap <silent> a, :<c-u>normal! F,ft,<cr>
Мы могли бы повторить эти сопоставления для каждого символа, который мы хотим включить. Но это было бы довольно трудно читать и поддерживать. Вдохновившись фрагментом Zsh, о котором я уже рассказывал в этой статье, мы могли бы:
- Перебрать все различные символы.
- Перебрать все различные режимы, которые мы хотим отобразить (режим OPERATOR-PENDING и режим VISUAL).
- Создавать различные отображения для каждой итерации.
Вот возможная реализация в Vimscript:
let s:chars = [ '_', '.', ':', ',', ';', '<bar>', '/', '<bslash>', '*', '+', '%', '`', '?' ]
for char in s:chars
for mode in [ 'xnoremap', 'onoremap' ]
execute printf('%s <silent> i%s :<C-u>normal! T%svt%s<CR>', mode, char, char, char)
execute printf('%s <silent> a%s :<C-u>normal! F%svf%s<CR>', mode, char, char, char)
endfor
endfor
Мне нравится использовать Vimscript для простых конфигураций, но как только мне нужно добраться до циклов или условий (я ненавижу равенство-операторы в Vimscript), я переключаюсь на Lua. Если вы используете Neovim, или если у вас есть Vim, скомпилированный с Lua, вы можете использовать следующее:
function basic_text_objects()
local chars = { '_', '.', ':', ',', ';', '|', '/', '\', '*', '+', '%', '`', '?' }
for _,char in ipairs(chars) do
for _,mode in ipairs({ 'x', 'o' }) do
vim.api.nvim_set_keymap(mode, "i" .. char, string.format(':<C-u>normal! T%svt%s<CR>', char, char), { noremap = true, silent = true })
vim.api.nvim_set_keymap(mode, "a" .. char, string.format(':<C-u>normal! F%svf%s<CR>', char, char), { noremap = true, silent = true })
end
end
end
return {
basic_text_objects = basic_text_objects
}
Я бы посоветовал вам хранить ваши скрипты Lua в папке lua/<namespace>
; <namespace>
может быть вашим именем пользователя или любым другим именем, которое вы захотите. Например, мои скрипты находятся в $XDG_CONFIG_HOME/nvim/lua/hypnos
.
Затем вы можете напрямую вызывать ваши новые функции в вашем vimrc. Если это файл Vimscript, вам понадобится префикс lua
, как показано ниже:
lua require('<namespace>/text_objects').basic_text_objects()
К следующему текстовому объекту
Сейчас нам нужно, чтобы наш курсор находился между двумя символами, чтобы действовать на наши новые текстовые объекты. Также было бы неплохо иметь возможность действовать с первой парой этих символов, когда наш курсор находится перед ними. Как мы видели выше в этой статье, это уже можно сделать с помощью круглых скобок или кавычек.
Рассмотрим следующий пример:
She felt, suddenly, deeply in love with Vim.
Мы можем попытаться оказаться на первой запятой в паре, независимо от того, находится ли курсор перед ними или между ними. Оттуда мы бы выбрали все до второй запятой. Вот возможное отображение:
onoremap <silent> i, :<C-u>silent! normal! f,F,lvt,<cr>
Представим, что курсор находится на первом d
из suddenly
, между запятыми.
Теперь представим, что наш курсор находится на S
из She
, перед запятыми.
Обратите внимание, что Ex-команда normal!
проваливается на втором шаге. По умолчанию она останавливается на этом, не выполняя шаги 3 и 4. Поэтому мы добавляем здесь Ex-команду :silent!
; она заставит normal!
выполняться до конца.
Для текста-объекта «вокруг» мы можем следовать тем же принципам. Единственное отличие: мы также выделяем две запятые.
onoremap a, :<C-u>silent! normal! f,F,vf,<cr>
Вот окончательный результат на языке Lua:
function basic_text_objects()
local chars = { '_', '.', ':', ',', ';', '|', '/', '\', '*', '+', '%', '`', '?' }
for idx,char in ipairs(chars) do
for idx,mode in ipairs({ 'x', 'o' }) do
vim.api.nvim_set_keymap(mode, "i" .. char, string.format(':<C-u>silent! normal! f%sF%slvt%s<CR>', char, char), { noremap = true, silent = true })
vim.api.nvim_set_keymap(mode, "a" .. char, string.format(':<C-u>silent! normal! f%sF%svf%s<CR>', char, char), { noremap = true, silent = true })
end
end
end
Имейте в виду, что это наивный подход. Во-первых, заставлять команду normal!
не срабатывать, кажется немного халтурой. Кроме того, это довольно сложно для понимания. С учетом этого, иногда хак достаточно хорош, чтобы удовлетворить наши потребности и двигаться вперед. Я бы не стал использовать это в плагине, который может быть использован другими, но для моего собственного использования этого вполне достаточно.
Каждый раз, когда мы создавали наши текстовые объекты, мы сначала формулировали проблему, а затем пытались найти путь к ее решению. Это хороший итеративный подход, но он также означает, что наши текстовые объекты могут не охватывать все возможные сценарии. Мы все еще можем что-то улучшить впоследствии, если увидим, что наши текстовые объекты ведут себя не так, как ожидалось в определенных ситуациях.
Это отличается от установки плагина: вы часто не знаете, как он работает, и не можете итеративно модифицировать его, чтобы он отвечал вашим конкретным потребностям.
Текстовые объекты на основе отступов
Давайте создадим еще один текстовый объект, на этот раз более сложный. Он может быть полезен любому разработчику.
Основы
Если вы посмотрите на текстовые объекты, уже доступные в ванильном Vim, их границы основаны на определенных символах. Есть и другие важные элементы, которые вы найдете в большинстве кодовых баз и которые можно использовать для текстового объекта: отступы.
Вот как выделить наши новые текстовые объекты:
- Получите начальный отступ текущей строки. Это будет эталонный отступ, с которым мы будем сравнивать все остальные строки.
- Двигайтесь вверх строка за строкой, пока отступ равен или выше начального отступа.
- Остановитесь, когда следующая строка уже не будет соответствовать правилу 2, и начните режим VISUAL построчно.
- Двигайтесь вниз, пока отступ не станет равен или больше начального отступа.
Это означает, что наши текстовые объекты включают в себя все строки, имеющие такой же отступ, как и начальный, или выше. Поскольку это поведение сложнее, чем у других созданных нами текстовых объектов, давайте реализуем функцию, которую будем вызывать в наших связках:
function! IndentTextObject()
let startindent = indent(line('.'))
" Move up till we are at the top of the buffer
" or till the indentation is less than the starting one
let prevline = line('.') - 1
while prevline > 0 && indent(prevline) >= startindent
-
let prevline = line('.') - 1
endwhile
" Begin linewise-visual selection
normal! 0V
" Move down till we are at the bottom of the buffer
" or till the indentation is less than the starting one
let nextline = line('.') + 1
let lastline = line('$')
while nextline <= lastline && indent(nextline) >= startindent
+
let nextline = line('.') + 1
endwhile
endfunction
onoremap <silent>ai :<C-U>call IndentTextObject()<CR>
onoremap <silent>ii :<C-U>call IndentTextObject()<CR>
xnoremap <silent>ai :<C-U>call IndentTextObject()<CR>
xnoremap <silent>ii :<C-U>call IndentTextObject()<CR>
Опять же, я всегда предпочитаю использовать Lua, когда все становится немного сложнее:
function select_indent()
local start_indent = vim.fn.indent(vim.fn.line('.'))
local prev_line = vim.fn.line('.') - 1
while prev_line > 0 and vim.fn.indent(prev_line) >= start_indent do
vim.cmd('-')
prev_line = vim.fn.line('.') - 1
end
vim.cmd('normal! 0V')
local next_line = vim.fn.line('.') + 1
local last_line = vim.fn.line('$')
while next_line <= last_line and vim.fn.indent(next_line) >= start_indent do
vim.cmd('+')
next_line = vim.fn.line('.') + 1
end
end
function indent_text_objects()
for _,mode in ipairs({ 'x', 'o' }) do
vim.api.nvim_set_keymap(mode, 'ii', ':<c-u>lua select_indent()<cr>', { noremap = true, silent = true })
vim.api.nvim_set_keymap(mode, 'ai', ':<c-u>lua select_indent()<cr>', { noremap = true, silent = true })
end
end
return {
indent_text_objects = indent_text_objects,
}
Основу функций составляют два цикла while
. Они выполняют:
- Перемещать курсор вверх до тех пор, пока предыдущая строка не будет иметь меньший отступ, чем начальная.
- Начать режим VISUAL построчно (с
normal! 0V
) и двигаться вниз строка за строкой, выбирая те, которые находятся на том же уровне отступа или выше.
Обратите внимание, что для перемещения вверх и вниз мы используем Ex-команды -
и +
. Да, это Ex-команды: попробуйте, например, :+
. Вы также можете использовать normal! k
или normal! <up>
.
Улучшение реализации
Наша маленькая функция работает отлично, но она быстро показывает свои пределы. Возможно, самый очевидный: текст-объект «внутри» и «вокруг» имеют совершенно одинаковое поведение. Ужас и проклятие!
Допустим, что «вокруг» текстового объекта нужно выделить еще две строки, причем первые строки должны иметь меньшие отступы при перемещении вверх и вниз.
Для иллюстрации рассмотрим следующий код. Символ «┃» обозначает курсор:
-- Comment
function super_function()
┃ if true then
print('youpi')
print('wuhu')
end
end
-- Comment
Нажатие dii
удалит весь блок if
, но оставит все остальное нетронутым. Нажатие dai
удалит все, кроме двух комментариев.
Отсюда у нас есть два решения:
- Создайте две разные функции: одну для текстового объекта «вокруг», другую для «внутри».
- Передать булевский флаг для использования текстового объекта «вокруг» или «внутри» в одной и той же функции.
Если мы примем первое решение, у нас будут почти идентичные функции; скорее всего, нам придется менять обе функции каждый раз, когда мы захотим улучшить наши текст-объекты. Поэтому давайте выберем второе решение. Тем не менее, если появляется слишком много условий, поскольку между двумя текстовыми объектами появляется все больше и больше различий, я бы определенно разделил функцию.
Вот возможная реализация:
function select_indent(around)
local start_indent = vim.fn.indent(vim.fn.line('.'))
local prev_line = vim.fn.line('.') - 1
while prev_line > 0 and vim.fn.indent(prev_line) >= start_indent do
vim.cmd('-')
prev_line = vim.fn.line('.') - 1
end
if around then
vim.cmd('-')
end
vim.cmd('normal! 0V')
local next_line = vim.fn.line('.') + 1
local last_line = vim.fn.line('$')
while next_line <= last_line and vim.fn.indent(next_line) >= start_indent do
vim.cmd('+')
next_line = vim.fn.line('.') + 1
end
if around then
vim.cmd('+')
end
end
function indent_text_objects()
for _,mode in ipairs({ 'x', 'o' }) do
vim.api.nvim_set_keymap(mode, 'ii', ':<c-u>lua select_indent()<cr>', { noremap = true, silent = true })
vim.api.nvim_set_keymap(mode, 'ai', ':<c-u>lua select_indent(true)<cr>', { noremap = true, silent = true })
end
end
return {
indent_text_objects = indent_text_objects,
}
Далее, мы могли бы игнорировать пустые строки. Сейчас они нас не особо волнуют, но они неизбежно будут останавливать наше движение вверх и вниз, потому что их уровень отступа всегда будет меньше начального. То есть, если ваш курсор с самого начала не находился на строке без отступов, в этом случае вы выделите весь буфер.
Мы можем определить пустую строку как строку, содержащую только белое пространство (пробелы, табуляции и новые строки). Чтобы узнать, действительно ли предыдущая или следующая строка пустая, мы можем использовать регекс:
local blank_line_pattern = '^%s*$'
Регексы в Lua немного странные: если во многих других системах регексов для обозначения пробелов используется s
, то в Lua — %s
.
Теперь нам нужно проверять на каждой итерации, является ли следующая строка пустой. Для этого мы можем создать небольшую функцию:
local prev_blank_line = function(line) return string.match(vim.fn.getline(line), blank_line_pattern) end
Нам также нужно изменить условия для наших двух циклов while. Например:
while prev_line > 0 and (prev_blank_line(prev_line) or vim.fn.indent(prev_line) >= start_indent) do
И последняя деталь, которая может вам пригодиться. Когда ваш курсор находится на пустой строке, когда вы вызываете текст-объект своими проворными пальцами, вы можете игнорировать нажатие клавиши. Если эта идея покажется вам привлекательной, то перед первым циклом while можно добавить следующее:
if string.match(vim.fn.getline('.'), blank_line_pattern) then
return
end
Теперь мы исправили самые очевидные недостатки нашего текстового объекта. Но мы можем сделать лучше! Как насчет возможности задать счетчик для выбора более низких уровней отступов?
Например, dai
будет работать как сейчас, но d2ai
будет выбирать более низкий уровень отступа, а d3ai
будет выбирать еще больше.
Для этого нам просто нужно увеличить начальный отступ в зависимости от заданного числа. Сейчас мы знаем только уровень отступа текущей строки с помощью нашей переменной start_indent
, но мы не знаем количество отступов для каждого уровня.
Чтобы получить эту информацию, мы можем посмотреть на значение опции shiftwidth
.
Вот реализация:
local start_indent = vim.fn.indent(vim.fn.line('.'))
if vim.v.count > 0 then
start_indent = start_indent - vim.o.shiftwidth * (vim.v.count - 1)
if start_indent < 0 then
start_indent = 0
end
end
Вы можете задаться вопросом о вычислениях:
start_indent = start_indent - vim.o.shiftwidth * (vim.v.count - 1)
Во-первых, vim.v.count
— это счетчик, присвоенный текстовому объекту. В Vimscript это было бы v:count
.
Что касается самого вычисления, то нам нужно умножить полученное значение на количество отступов на уровень (опция shiftwidth
) и вычесть его из отступов текущей строки. Это дает нам количество отступов на один уровень выше.
Мы решаем, что отсчет 1
не должен ничего изменить (dai
такой же, как d1ai
), поэтому мы вычитаем 1
из отсчета. Мы также проверяем, не меньше ли начальный отступ 0, что может произойти, если мы вводим счет на строке без отступа. В этом случае мы устанавливаем начальный отступ равным 0.
Вот заключительная функция:
function select_indent(around)
local start_indent = vim.fn.indent(vim.fn.line('.'))
local blank_line_pattern = '^%s*$'
if string.match(vim.fn.getline('.'), blank_line_pattern) then
return
end
if vim.v.count > 0 then
start_indent = start_indent - vim.o.shiftwidth * (vim.v.count - 1)
if start_indent < 0 then
start_indent = 0
end
end
local prev_line = vim.fn.line('.') - 1
local prev_blank_line = function(line) return string.match(vim.fn.getline(line), blank_line_pattern) end
while prev_line > 0 and (prev_blank_line(prev_line) or vim.fn.indent(prev_line) >= start_indent) do
vim.cmd('-')
prev_line = vim.fn.line('.') - 1
end
if around then
vim.cmd('-')
end
vim.cmd('normal! 0V')
local next_line = vim.fn.line('.') + 1
local next_blank_line = function(line) return string.match(vim.fn.getline(line), blank_line_pattern) end
local last_line = vim.fn.line('$')
while next_line <= last_line and (next_blank_line(next_line) or vim.fn.indent(next_line) >= start_indent) do
vim.cmd('+')
next_line = vim.fn.line('.') + 1
end
if around then
vim.cmd('+')
end
end
Вот и все! Мы создали прекрасный текст-объект силой наших соединенных духов. С радостью и гордостью я нарекаю тебя Божественным Кузнецом Текстового Объекта©.
Сопоставление функции Lua
До сих пор мы использовали некоторые строки Vimscript для отображения наших функций Lua на наши новые текстовые объекты. Neovim 0.7, который вышел за пару дней до публикации этой статьи, позволяет нам напрямую отображать функции Lua без использования Vimscript.
Вы можете попробовать посмотреть, например, :help vim.keymap.set
, чтобы еще больше улучшить наш код.
Сила объекта Text-Object
Как всегда, придумывание новых идей текстовых объектов зависит от ваших потребностей. Я всегда предпочитаю решать болевые точки, которые я замечаю при написании в Vim, вместо того, чтобы пытаться придумать идеи улучшений из ничего. Например, я всегда хотел иметь текстовый объект для работы с функциями; в то же время, я хотел что-то, что могло бы работать с большинством языков программирования. Наличие текстового объекта, основанного на уровнях отступов, является для меня лучшим компромиссом.
Итак, что мы увидели в этой статье?
- Когда вы нажимаете оператор в НОРМАЛЬНОМ режиме, вы переключаетесь в режим OPERATOR-PENDING. Отсюда вы можете дать движение или текст-объект, чтобы оперировать тем, чем вы хотите.
- Текст-объект — это только набор символов, с которыми можно работать, используя операторы.
- Легко создавать базовые текстовые объекты благодаря отображениям, зависящим от оператора,
omap
иonoremap
. - Когда вам нужны более сложные текстовые объекты, проще написать функцию. Тогда вы можете положиться на богатый набор функций Vimscript для перемещения курсора и выбора того, что вам нужно.
- Vimscript — это язык с множеством странных дизайнерских решений. Я предпочитаю использовать Lua, когда поток данных идет по нескольким ветвям.
Хотите больше статей, где мы используем Vimscript и Lua, чтобы улучшить ваши возможности по настройке Vim? Не стесняйтесь высказывать свои мысли, отзывы и улучшения в разделе комментариев. Ставьте лайк, делитесь и любите.
Ссылки
- Vim wiki — Отступ текста-объекта
- Vim wiki — Создание новых текстовых объектов
- Отложенные транзакции — Дилан МакКлюр
- Начало использования Lua в Neovim — Тимофей Штерле
- Выучить X за Y минут — Lua — Тайлер Нейлон
Учимся играть в Vim: Увлекательное руководство по изучению лучшего редактора
Я начал писать очень амбициозное руководство по изучению Vim с нуля. Благодаря отличным отзывам моих читателей, я смогу решить проблемы, на которые жалуются многие новички при изучении Vim. Например:
- Как перемещаться по нескольким файлам и проектам в Vim?
- Как отлаживать в Vim?
- Как искать, находить и заменять?
Это руководство расскажет о наиболее полезных функциях Vim, а также о некоторых мощных плагинах, которые обогатят ваш опыт.
Помогите мне повлиять на мир Vim! Вы можете подписаться на рассылку и рассказать мне обо всем, что вы хотите видеть в книге. Ранняя скидка гарантирована!
Я лично отвечаю на каждое письмо, поэтому не стесняйтесь задавать столько вопросов, сколько хотите. Мне всегда приятно помочь.
И последнее, но не менее важное: Я также написал книгу о создании собственной среды разработки без использования мыши, так что если она вас тоже заинтересовала, нажмите на эту блестящую ссылку.