Найти тему
Блокнот математика

Рубрика "Секреты Вим". Переход на вкладку с данным файлом

Привет, коллеги. Есть целый ряд редакторов, поддерживающих концепцию вкладок. И во многих, если вы открываете файл, уже открытый во вкладке, то просто попадаете на эту вкладку.

Вим тоже поддерживает вкладки, но ведёт себя иначе: открывая файл в новой или текущей вкладке, вы получаете то, что заказывали. То, что у вас открыто две, три, сорок две копии файла - Вим не будет волновать.

Это не Вим, это просто много (слишком!) вкладок.
Это не Вим, это просто много (слишком!) вкладок.

Однако в графической версии (gvim), которой я не пользуюсь, такая возможность есть. Это команда drop, которой можно выполнять и другие команды. Например, drop file.txt откроет файл, если он еще не открыт; а если открыт, то Вим сделает активным окно с этим файлом. А drop tab file.txt откроет файл в новой вкладке либо перейдет на вкладку с файлом.

В консольной версии эта команда не работает. Она, вообще, для drag-and-drop нужна была. И я решил сделать себе средство открывать файлы в таком стиле. А я всегда открываю файл в новой вкладке через :tabnew, а если расщепляю окно, то стремлюсь именно к этому, и тот же файл где-то еще меня в этом случае не волнует. Поэтому мне просто нужна команда, которая покажет мне вкладку с указанными файлом: откроет новую или отыщет старую.

Решение такое:

function! LookForFile(f)
for i in range(tabpagenr('$'))
let buflist = tabpagebuflist(i + 1)
for b in buflist
if bufname(b) == a:f
execute "normal " . (i+1) . "gt"
endif
endfor
endfor
endfunc
:command! -nargs=1 -complete=file Tabnew :call LookForFile(<f-args>)

Разбираем строка за строкой. Мы определяем функцию, восклицательный знак предписывает перезаписать функцию, если такая уже есть. У функции один параметр f.

Далее мы перебираем все вкладки. Номер вкладки дает функция tabpagenr, аргумент '$' просит номер последней вкладки. Функция range(n) создает список от нуля до n-1, по которому мы пускаем цикл. Короче, цикл по номерам вкладок, в нем i+1 - это номер текущей вкладки.

Функция tabpagebuflist возвращает список номеров буферов, которые во вкладке открыты.

Пускаем по нему цикл с переменной b. Функция bufname возвращает имя файла, который с буфером связан. Сравниваем его аргументом функции. Аргумент снабжён префиксом a:.

Если совпало, то выполняем переход на нужную вкладку командной нормального режима. Можно было бы и прервать цикл, но можно и не прерывать.

Всё. Если с открытым буфером связан точно такое имя файла, то этот файл и откроется. Точнее, вкладка с ним, сам файл может быть в другом окне в той же вкладке.

Теперь команда. Мы создаем свою команду, а свои команды обязательно с большой буквы. У команды один аргумент (имя файла, который будем открывать). Включено автодополнения именно по именам файлов, то есть можно ввести часть имени и нажать таб, чтобы посмотреть варианты или достроить до полного, если вариант один. Работа команды сводится к вызову функции с передачей ей имени файла.

Всё. Теперь можно открывать файлы командой :Tabnew и если файл уже открыт, то откроется вкладка с ним.

Можно усовершенствовать разработку: открывать именно окно с файлом, а не просто вкладку, например. Функция win_findbuf(bufnr) возвращает список номеров окон, содержащих данный буфер (буфер с данным номером). И можно перейти к нужному окну командой нормального режима <C-W) w, указав перед нею номер окна. Или используйте функцию win_gotoid, которая перейдет в окно по номеру. Да и вообще много функций есть для окон.

Если файл открыт несколько раз, то откроется последняя вкладка, в которой он открыт: это можно пресечь, завершив цикл при первом обнаружении файла. Тогда откроется первая. Можно показать все и дать выбрать... но это уже на ваш тонкий вкус. Меня устраивает и так, как есть.

Самое неприятное, это что если файл открыт один раз по полному имени, например, /usr/porn/file.txt, а потом он же открыт из текущего каталога или по относительному пути вроде ../file.txt, то имена у файлов формально разные и совпадение не будет обнаружено. Не смертельно, конечно. Можно исправить и это, но не вижу необходимости.

Что ещё можно (и несложно) сделать, это вывести сообщение о том, что файл открыт более одного раза, и указать, где.

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

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