Привет, коллеги. Сегодня рассмотрим некоторые возможности экспертного уровня. Но знать, что они есть, полезно. В конце заметки даны ссылки на предыдущие статьи цикла, а также, как обычно, путеводители по рубрике и каналу в целом.
1. Первая тема: возможность заблокировать переменную. Можно заблокировать переменную, чтобы ее нельзя было изменить: командой lockvar. Если это список или словарь, то блокировка защитит его от изменений, но если его элемент сам список или словарь, то этот вложенный объект изменять можно.
Это логично, если помнить, что переменная-список (или словарь) есть просто указатель на структуру данных. Менять указатель нельзя, а вот то, на что он указывает - можно.
Однако можно указать глубину вложенности, например lockvar 1 name - так по умолчанию. А если lockvar 2 name, то нельзя менять заблокированный список или словарь и его элементы-списки (или словари), а вот их элементы менять можно. А если добавить восклицательный знак, то переменная блокируется абсолютно, до любой вложенности: lockvar! name.
Если две переменные указывают на один список или словарь (помним, что let a=b наводит a на тот же список, на которой указывает b), то блокировка одной переменной, разумеется, блокирует и другую.
Разблокировать переменную позволяет unlockvar. Она во всем аналогична lockvar, включая и вложенность.
2. Теперь обсудим вывод сообщений на экран. Мы уже знаем команду echo, которая принимает одно или более выражений (через пробел) и выводит их, разделяя пробелом. Чтобы разделительный пробел не ставился, соединяйте выражения оператором конкатенации (точка .).
Первое выражение идет с новой строки, остальные на той же, что и первое. Можно начать новую строку, вставив \n в двойных кавычках. А символ \r позволит сместить курсор в начало строки и перезаписать текст.
После echo не может идти комментарий. Также не надо путать ее с одноименной командой bash: echo и !echo суть разные вещи!
Вариант echon не добавляет символ конца строки, позволяя дополнить строку. Пример:
for i in range(42)
echon "\r" i
sleep
endfor
Этот цикл будет крутить счетчик в начале строки. Задержку в одну секунду искусственно добавили. А можно так:
let dash = ['-','/','|','\']
for i in range(12) | echon "\r".b:dash[i%4] | sleep | endfor
Будет крутиться палочка. Бывает полезно загипнотизировать пользователя.
Вывод можно сделать цветным, используя группы для раскраски синтаксиса. Для этого служит команда echohl. Она делает указанную группу рабочей для всего вывода, поэтому потом, когда надобность отпадет, надо вернуться к группе NONE: echohl None. Например:
echohl ErrorMsg | echo "Don't panic!!!" | echohl None
Групп много, см. highlight-groups. Также можно посмотреть их
:so $VIMRUNTIME/syntax/hitest.vim
Вы можете создавать свои или менять существующие. Так что в ваших силах не просто выводить сообщения, но делать это красиво.
Более того, вы можете выводить сообщения-предупреждения и сообщения об ошибках. Для этого есть варианты echomsg и echoerr.
Сообщение сохраняется в истории сообщений. Выводить можно текст и числа, но не списки и не словари. Все выражения сначала вычисляются, а потом выводятся (echo выводит результат каждого выражения по мере вычисления). При вызове echoerr из скрипта или функции, будет добавлен номер строки. При вызове ее из блока try, бросается исключение, а не выводится сообщение. Об исключениях был отдельный материал.
3. Проследим разницу между командами execute, eval, source, expand.
Первая выполняет результат выражения как :команду. Если выражений больше одного, они соединяются в одно через пробел. Это позволяет создавать динамические команды, например, сохранить текст в файл, имя которого в переменной. А команда :normal позволяет использовать и нормальный режим, через который есть доступ ко вставке...
Две хитрости из Справки: execute позволяет применить конвейер для команд, к которым они неприменим:
:execute '!ls' | echo 'ok'
И ещё позволяет избежать вставки спецсимволов литерально в текст скрипта:
:execute "normal ixxx\<Esc>"
Команда source выполняет скрипт, записанный в файл.
Функция eval() выполняет строку и возвращает результат. Выполняет не команду командной строки, а код. Правда, надо иметь в виду, что вещественное число в строку автоматически не превращается, и тем более в другую сторону. Функция удобна как раз как обратна к функции string(): последняя превращает что-то в строку, а eval восстанавливает исходное значение.
В целом, функция eval является мощным и небезопасным орудием. По сути, это интерпретатор скриптового языка. Вы можете сделать всё то же самое, записав код в файл и выполнив его через source. Но eval еще возвращает значение.
Наконец, функция expand() раскрывает файловые шаблоны и спецсимволы в выражении. Отчасти она работает как команда ls в bash: как ls *.tex выведет все тех-файлы, так и expand('*.tex') вернет строку, в которой будут имена этих файлов, разделенные символом <NL>. Может она обрабатывать и спецсимволы с модификаторами, такие как % (текущий файл) и :e (откусить расширение).
Она не выполняет код, в отличие от двух других команд. Однако она вычисляет выражение, а туда могут входить любые функции. Подробнее о ней будет отдельный материал.
Также к экспертным возможностям я бы отнес режим отладки (будет отдельный материал) и ссылки на функции, да и возможность включать их в словари, превращая их в инкапсулированные объекты: это мы уже обсуждали и, может быть, позже я приведу примеры.
Удачи, коллеги!
Что уже было по скриптовому языку Вим: