Найти в Дзене
Блокнот математика

Рубрика "Секреты Вим". Распознавание типа нового файла

Привет, коллеги. Сегодня разберем пример использования скриптового языка. Будут использованы автокоманды и распознавание типа файла, так что эти темы стоит предварительно изучить, если вы с ними не знакомы.

Пример из книги Robbins A et al, Learning Vim and vi editors, 7ed, 2008. Мы его немного доработаем.

Немного магии
Немного магии

Итак, задача. Вим может распознавать тип файла, что важно для подсветки синтаксиса, отступов, специальной настройки и не только для этого. При распознавании Вим опирается на расширение файла и при необходимости заглядывает в содержимое. Поэтому, если файл без расширения (или с неизвестным Виму расширением) содержит узнаваемый код, то Вим распознает тип верно; если пустой файл содержит нужное расширение, то тоже верно. А вот если пустой файл и расширение не дает подсказки, Вим не сможет распознать тип.

Типичная ситуация, если вы пишете скрипт на bash без расширения .sh или на Перле, например, без расширения .pl.

Помочь делу несложно: есть команда filetype detect. Но почему бы не вызвать ее автоматически, когда в файле появится некий текст?

Решение, предложенное в книге, таково. Создадим автокоманду, которая обрабатывает события "курсор сместился в режиме вставки": CursorMovedI. Эти события, скажем прямо, нередки, так что лучше не злоупотреблять. Мы и не будем. Итак, команда:

augroup newFileDetection
autocmd CursorMovedI * call CheckFileType()
augroup END

Создали новую группу и в ней одну (пока) автокоманду. Она не привязана к имени файла (любое годится, так как символ *) и вызывает функцию. Которая имеет вид:

function CheckFileType()
if exists("b:countCheck") == 0
let b:countCheck = 0
endif
let b:countCheck += 1
if &filetype == "" && b:countCheck > 20 && b:countCheck < 200
filetype detect
elseif b:countCheck >= 200 || &filetype != ""
autocmd! newFileDetection
endif
endfunction

Итак, сначала мы проверяем, создана ли переменная b:countCheck. Переменная локальна для буфера (префикс b:). Если не создана, то создадим и поместим туда нуль.

Теперь она точно есть. Увеличим на единицу (это мы считаем вызовы, по сути дела, причем для каждого буфера отдельно, что удобно). Но функция вызывается при нажатии на клавишу в режиме вставки, так что можно сказать, что считаем введенные символы. Правда, стертые идут как введенные - ну, мелочи.

Далее мы проверяем три условия: тип файла (опция filetype) пока не определился, символов введено уже по меньшей мере двадцать (может хватить, чтобы определиться), но не слишком много. Если двести символов уже ввели, то хватит ерундой заниматься: не получится распознать тип и хватит дергать функцию на каждое нажатие клавиши!

Если все три условия выполнены, пытаемся распознать тип.

Если же нет, то проверяем дальше. Если символов уже двести насчитали или тип уже распознан, сворачиваем всё и удаляем все автокоманды в группе.

Это решение рассчитано на запуск Вима для редактирования одного этого файла. Тип распознается и команда удаляется. При новом запуске она возникнет снова. Но если вы откроете новую вкладку, то ничего не выйдет: команда уже удалена.

Что бы я добавил, так это еще одну автокоманду:

autocmd BufNewFile * autocmd CursorMovedI * call CheckFileType()

И удалять тогда надо не всё в группе, а только автокоманду CursorMovedI: замените строку

autocmd! newFileDetection

на

autocmd! CursorMovedI

Теперь получается красиво! Если файл распознался, автокоманда не будет работать. При открытии нового файла она опять появится. Набрав шебанг, вы увидите, что тип распознан. Если же вы затеяли что-то писать (стихи или что-то в этом роде), Вим через 200 символов уберет автокоманду, чтобы не мешала.

Удачи, коллеги!

Научно-популярные каналы на Дзене: путеводитель
Новости популярной науки12 марта 2022