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

Рубрика "Секреты Вим". Диалоги и выбор

Привет, коллеги. Сегодня поговорим о диалоге с Вим: о ситуациях, когда он спрашивает, а вы отвечаете. Речь не идет о подтверждении действий, о которых мы уже говорили, хотя это тоже диалоги. Речь пойдет о выборе вариантов. В графической версии Вим есть и настоящие диалоги. Они доступны через упомянутую уже команду :confirm, через функции browse() и browserdir(), команду :browse, функцию inputdialog(), команды :promptfind и :promptrepl. Команда :browse принимает команду для открытия или записи файла, вроде tabnew или split или w, и через диалоговое окно выясняет, о каком файле идет речь. Функции browse() и browsedir() выводят окошки для выбора файла или каталога и возвращают имя выбранного файла (с путем) или путь к каталогу. Функция inputdialog() работает как input(), но не через специальную строку ввода, а через диалоговое окошко. Команды :promptfind и :promptrepl запрашивают строку поиска (и замены). В консоли таких диалогов нет, но при открытии файла можно открыть каталог и спокойно

Привет, коллеги. Сегодня поговорим о диалоге с Вим: о ситуациях, когда он спрашивает, а вы отвечаете. Речь не идет о подтверждении действий, о которых мы уже говорили, хотя это тоже диалоги. Речь пойдет о выборе вариантов.

https://gimpbnksb.ru/_fr/2/4997076.gif
https://gimpbnksb.ru/_fr/2/4997076.gif

В графической версии Вим есть и настоящие диалоги. Они доступны через упомянутую уже команду :confirm, через функции browse() и browserdir(), команду :browse, функцию inputdialog(), команды :promptfind и :promptrepl.

Команда :browse принимает команду для открытия или записи файла, вроде tabnew или split или w, и через диалоговое окно выясняет, о каком файле идет речь.

Функции browse() и browsedir() выводят окошки для выбора файла или каталога и возвращают имя выбранного файла (с путем) или путь к каталогу.

Функция inputdialog() работает как input(), но не через специальную строку ввода, а через диалоговое окошко.

Команды :promptfind и :promptrepl запрашивают строку поиска (и замены).

В консоли таких диалогов нет, но при открытии файла можно открыть каталог и спокойно выбрать там файл:

:tabnew . (текущий каталог)
или :tabnew %:h (каталог, в котором текущий файл)
или :split $HOME

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

При сохранении файла у нас есть автодополнение, позволяющее с комфортом набрать путь к файлу.

Строка ввода и без окна прекрасно работает, а поиск и замена вообще в окне не нуждаются. Здесь я только напомню про магию, которой можно сделать перманентно меньше (set nomagic), если вам чаще надо искать текст, а не регулярное выражение, или можно вообще почти полностью отключить при данном поиске (ключ \V), так что особый смысл имеют только слеш \ и завершитель (обычно / но не обязательно он). То же касается регистра символов, который можно включить или отключить (set ignorecase), включить умное распознавание (set smartcase), при котором qwe будет искаться без учета регистра, а Qwe с учетом, или включить/отключить в данном поиске ключами \с, \С. Очень полезны флаги hls (подсвечивать найденное, подсветку снимает :noh) и incsearch, при котором поиск ведется по ходу набора искомого, что очень удобно и полезно.

А мы сегодня поговорим о функции confirm(). Она предлагает пользователю выбор и возвращает номер выбранного пункта (или нуль). Принимает от одного до четырех параметров. Обязательный один: это вопрос. Если больше ничего нет (то есть, вариантов не предлагается), то выбор один: "ОК". Либо ОК, либо отмена по <ESC> (и возвращается нуль).

Например:

if(confirm("Выходим?")) | execute ":qa!" | endif

Второй аргумент - это варианты выбора; это строка, в которой варианты разделены символом конца строки \n. Например,

let b:exit=confirm("Выходим?", "&Да\n&Нет\nНе &знаю\&Только этот файл\n&Объясни"))

Символ & помечает букву после себя как горячую клавишу для выбора. В общем-то, другого способа выбрать и нет. По умолчанию это первая буква варианта. Если буква русская, то и вводить ее надо в русской раскладке, и потребуется системная раскладка. Можно предусмотреть латинские горячие клавиши: "Да(&Y)\nНет(&N)".

Третий аргумент - это номер варианта по умолчанию (если пользователь просто нажмет ввод). По умолчанию номер по умолчанию первый.

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

Вот как воплотить выбор из картинки, что выше (Горячие клавиши k, l, h являются в Вим стрелками вверх, вправо и влево):

let b:chosen=0
while(!b:chosen)
let choice = confirm("А ты бы что выбрал?", "Должность воеводы&k\nМоре водки&l\nДевочки&h", 3)
if choice == 0
echo "Что-то надо выбрать!"
elseif choice == 3
echo "Согласен."
let b:chosen=1
else
echo "А я бы девочек выбрал."
let b:chosen=1
endif
endwhile

В оконной версии будет выведено диалоговое окошко, а варианты будут кнопочками. Их размещение можно настраивать.

С помощью этой функции ваш скрипт может задавать пользователю вопросы. Можно сделать текстовую игру, если есть дерево вариантов, или диагност проблем (Прибор включен в сеть? Горит ли неонка? Жужжит ли что-то у ей внутре?)

Вы можете использовать эту функцию в привязках и меню, чтобы предлагать пользователю выбор. К примеру,

:let texs=['pdflatex','xelatex','latex','None']
:map <F6> :let b:out= eval( 'system("'. texs[confirm('Which TeX?', join(texs,"\n")-1] . ' '.expand('%').'")')<CR>

Эти строки можно выполнить один раз, в .vimrc например. В списке texs мы задаем разные компиляторы теха. И вешаем на клавишу следующий каскад: в переменную b:out (локальную для буфера) записываем результат вычисленного выражения; оно состоит в вызове функции, вызывающей внешнюю команду; она состоит из вызова компилятора, которому передается текущий файл (его имя извлекается из символа %, обозначающего текущий файл); компилятор выбирает функция confirm. Варианты выбора конструируются из списка компиляторов.

Единственный недостаток этой конструкции в том, что при отмене (вернется нуль) получится элемент списка номер -1, а это последний элемент. Можно задать последним элементом что-то фиктивное, вроде None, чтобы тихо выйти: такой команды нет, так что результатом будет "command not found", и ничего страшного.

В переменной b:out будет выдача на STDOUT. Вы можете ее потом посмотреть через :echo.

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

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