|
Предыдущие частиСодержаниеБиблиотеки скриптовИногда бывают ситуации, когда нужно в разных плагинах, которые вы делаете, использовать один и тот же кусок кода. Конечно, можно его просто копировать из одного плагина в другой, но лучше всего оформить его в виде функции, находящейся в библиотеке, тогда при нахождении ошибки в этом участке кода не придется искать где этот же кусок кода находится в другом плагине, а будет достаточно исправить функцию в библиотеке. Библиотеки могут быть полезны, если вам в разных скриптах потребуется, например, функция для чтения файлов в определенном формате, или функция для особой обработки текста. В основном функции из таких библиотек используются внутри других скриптов, и они не предназначены для использования их конечным пользователем. Для организации такой библиотеки скриптов служат директории autoload, расположенные, как и директории plugin, в нескольких местах: в корневой директории Vim, в поддиректории after и в домашней директории пользователя. Подробно расположение директорий плагинов мы разбирали в прошлой части. Для создания библиотеки скриптов нужно соблюдать следующие требования к именам функций: Если функция Foo() содержится в файле autoload/bar.vim, то объявление функции должно выглядеть следующим образом (обратите внимание на имя): function! bar#Foo() ... endfunction Имя Foo() должно начинаться с заглавной буквы, так как эта функция будет глобальной, а перед именем функции должно располагаться имя файла bar (без расширения .vim), которое отделяется решеткой #. При вызове этой функции также необходимо указывать ее имя в таком же виде: call bar#Foo() Разработчики Vim на этом не остановились и сделали возможность хранить скрипты в поддиректориях, в этом случае и имена функций тоже должны содержать имена поддиректорий, разделяя их вместо символа "/" символом решетки "#". Например, если функция Foo() расположена в скрипте, который, в свою очередь, расположен в директории autoload/myscripts/cool/bar.vim, то функция должна быть объявлена следующим образом: function myscripts#cool#bar#Foo() ... endfunction Именно с таким именем ее и придется вызывать командой call: call myscripts#cool#bar#Foo() Давайте для примера напишем Hello Word из библиотечной функции. Создадим файл hello.vim в директории autoload/myscripts/cool. В качестве содержимого этого файла будет следующий простой код: function! myscripts#cool#hello#Hello(name) return "Hello, " . a:name endfunction Теперь после перезапуска редактора мы можем выполнить следующую команду: :echo myscripts#cool#hello#Hello("Vim") В результате получим вполне ожидаемое: Hello, Vim Плагины для определенных типов файловОпределение типов файловВ Vim есть возможность создавать плагины, которые будут работать только с определенными типами файлов. Для начала давайте разберемся в том что из себя представляют эти самые типы файлов. Типы файлов и расширения файлов - это не одно и то же, хотя и есть возможность задать как должен называться тип файла для определенных расширений. Например, если открыть файл с расширением .py или .pyw, то тип файла будет называться "python". Самый примитивный способ задания типа файла состоит в том, чтобы для уже открытого файла выполнить следующую команду :set filetype=mytype Теперь открытый файл будет иметь тип "mytype" до следующего открытия этого файла. При этом, если открытый файл до этого использовал раскраску синтаксиса, то она будет отключена, так как для типа "mytype" плагин синтаксиса не установлен. Если аналогичным образом мы вернем файлу его старый тип, для которого раскраска синтаксиса установлена, то текст опять станет цветным. Про плагины для раскраски синтаксиса мы поговорим чуть позже в этой статье. Каждый раз при открытии файлов задавать их тип вручную не удобно, поэтому в Vim существует возможность автоматически их определять. Для этого можно использовать команду autocmd, или в сокращенном виде - au. Эта команда в упрощенном виде имеет следующий синтаксис: :autocmd {event} {pat} {cmd} Здесь пропущены два необязательных параметра, которыми мы пользоваться не будем, для более подробной информации об этой команде выполните команду :help au. Эта команда работает следующим образом. Если возникает событие, перечисленное в параметре {event} (несколько событий перечисляются через запятую), и при этом событие относится к файлу, имя которого совпадает с шаблоном {pat}, то вызывается команда {cmd}. Полный список событий можно найти в документации, если ввести команду :help autocmd-events. Для примера, существуют события, возникающие при открытии файла или при создании нового файла (именно их мы и будем использовать), события, возникающие при записи файла на диск, при операциях с буферами (создание, удаление, переключение) и много других событий. В качестве шаблона файлов {pat} можно использовать как обычные файловые шаблоны наподобие *.txt, так и регулярные выражения. В качестве {cmd} может выступать как простая команда, так и вызов функции, которая должна быть предварительно объявлена. Давайте создадим правило, по которому будет создаваться новый тип файлов. Пусть это будет тип "pmwiki" для файлов с маской "*.pmwiki" (как я уже не один раз говорил в прошлых частях, pmwiki - это вики-нотация, в которой я набираю эту статью). Для осуществления нашей задумки нам достаточно добавить в файл _vimrc/.vimrc следующую строку: autocmd BufRead,BufNewFile *.pmwiki set filetype=pmwiki Этой командой мы говорим, что при возникновении события открытия (BufRead) или создания (BufNewFile) файла, который удовлетворяет маске *.pmwiki, должна вызываеться команда set filetype=pmwiki, которая и устанавливает тип файла как "pmwiki". Поделюсь еще одной полезной настройкой, которой я пользуюсь. При сохранении текущей сессии в Vim с помощью команды mksession (открытые файлы, расположение буферов на экране и т.п.) в качестве имени файла с сессией я задаю расширение .session. А в файле настроек _vimrc/.vimrc у меня прописана следующая строка: autocmd BufRead *.session so % Благодаря этому как только в Vim открывается файл с таким расширением, вызывается команда выполнения этого файла как скрипта ('so %', или в полном виде source % ), что приводит к автоматическому восстановлению сессии. ftpluginНу что ж, пришло время заняться непосредственно плагинами. Плагины, которые должны работать только с файлами определенных типов, располагаются в директории ftplugin. При их написании нужно соблюдать некоторые правила. Во-первых, должно выполняться одно из следующих трех условий:
Второе правило написания таких плагинов относится к исходному тексту плагина. Так же как и для обычных плагинов, которые мы рассматривали в прошлой части, мы должны предоставить пользователю возможность не загружать наш плагин без удаления самого файла плагина. Это самое второе правило разработчики плагинов понимают по-разному. Дело в том, что в документации написано, что необходимо вставить следующий код в самое начало исходника плагина: " Only do this when not done yet for this buffer if exists("b:did_ftplugin") finish endif let b:did_ftplugin = 1 Тогда пользователь сможет заблокировать загрузку плагина, добавив в свой файл .vimrc/_vimrc следующую команду: let b:did_ftplugin = 1 Но если пользователь добавит эту строку в свой файл настроек, то будут заблокированы все плагины, использующие переменную b:did_ftplugin, поэтому некоторые разработчики используют другое имя переменной, чтобы пользователь мог блокировать именно их плагин, а не все. Надо сказать, что плагины, которые прилагаются к Vim по умолчанию, написаны таким образом, что используют именно переменную с именем b:did_ftplugin, но мне лично больше нравится, когда используют другое имя, так как в этом случае у пользователя появляется больше возможностей для настройки своего Vim. В завершение этого раздела давайте модернизируем плагин, который мы создавали в конце пятой части. Напомню, что там мы делали плагин, который создавал оглавление для статей, набранных в нотации pmWiki. Так как теперь у нас для pmWiki есть свой тип файлов, то сделаем так, чтобы плагин работал только для буферов, в которых открыт этот тип файлов. Не будем повторно разбирать то как работает этот плагин, нас в данный момент интересует его начало, чтобы иметь наглядное представление с чего начинаются подобные плагины. " Function for pmWiki (ftplugin) " Last Change: 2009 Sen 19 " Maintainer: Jenyay <jenyay.ilin@gmail.com> " License: This file is placed in the public domain. if exists("b:did_pmwiki_ftplugin") finish endif let b:did_pmwiki_ftplugin = 1 function! s:PmTitles() " Регулярное выражение для нахождения якоря let l:pattern_anchor = '\m^\[\[#\([a-zA-Z0-9_]*\)\]\]' " Регулярное выражение для нахождения заголовка let l:pattern_title = '\m^!!\s*\(.*\)$' " Количество строк в файле let l:count = line ("$") " Сюда будут добавляться строки оглавления let l:result = [] " Проходимся по всем строкам в буфере. for n in range (1, l:count) " Получим номер строки по ее номеру " Строки в буфере нумеруются с 1 let l:currline = getline (n) " Для каждой строки проверим соответствует ли она шаблону с якорем let l:anchor = matchlist (l:currline, l:pattern_anchor) if len (l:anchor) != 0 " Если строка соответствует, то список не будет пустым " Теперь проверим соответствует ли следующая строка шаблону заголовка let l:nextline = getline (n + 1) let l:title = matchlist (l:nextline, l:pattern_title) if len (l:title) != 0 " Если и заголовок найден, создадим строку оглавления let l:resline = printf ("* [[#%s | %s]]", l:anchor[1], l:title[1]) call add (l:result, l:resline) endif endif endfor " Добавим ссылку на комменатрии call add (l:result, "* [[#comments | Комментарии]]") " Получить положение курсора в виде списка: " [номер буфера, " номер строки, " номер столбца, " параметр при использовании опции virtualedit] let l:cursor = getpos(".") " Вставим полученное оглавление в ту строку, где сейчас стоит курсор call append (l:cursor[1], l:result) " Удалим все переменные unlet l:pattern_anchor l:pattern_title l:count unlet! l:resline l:nextline l:title l:anchor l:currline endfunction command PmTitles call s:PmTitles() Кроме проверки на необходимость загружать сам плагин в самое начало добавлены комментарии с информацией о плагине. Кроме этого было бы неплохо еще добавить файл с документацией (как это делать было написано в прошлой статье), но в данный момент мы не будем этим заниматься. Раскраска синтаксисаЕще один тип плагинов, которые работают для определенных типов файлов, являются плагины синтаксиса. Именно благодаря им Vim раскрашивает ключевые слова, операторы и другие элементы в исходных текстах программ. Разумеется, что мы можем создавать свои плагины синтаксиса, которые могут сделать более удобной работу с теми файлами, для редактирования которых используется Vim. Например, это могут быть файлы, в которых используются редкая нотация (да все та же pmWiki), или это могут быть обычные текстовые файлы, в которых вы хотели бы выделять отдельные элементы. Тема создания плагинов синтаксиса, вообще говоря, довольно большая, поэтому мы рассмотрим только самые основы. Процесс создания файла синтаксиса можно разделить на два этапа: сначала определяются элементы синтаксиса, которые должны быть раскрашены, а затем определяется то, как они будут раскрашиваться. Первый этап выполняется с помощью команды syntax, а второй с помощью команды highlight. Несмотря на то, что используется всего две команды, количество возможных параметров у них достигло такого количества, что иногда одну и ту же команду при разных наборах параметров удобнее рассматривать как разные команды. В этом разделе мы будем создавать файл синтаксиса для раскраски текста в нотации pmWiki. Выделение элементов синтаксисаПервое, что нам нужно сделать, это создать группу элементов, которые будут раскрашиваться однотипно. Типичным случаем таких элементов являются ключевые слова, комментарии, строковые константы и тому подобные элементы. Для начала создадим в папке syntax пустой файл с именем pmwiki.vim. Давайте сделаем так, чтобы к тексте pmWiki раскрашивались ключевые слова, заголовки и ссылки, а текст между тремя одинарными кавычками выделялся полужирным шрифтом. Для этого сначала воспользуемся командой syntax в следующем виде: syntax [{настройки}] {тип} {группа} {определение} [{настройки}] Здесь {тип} - это один из трех возможных типов синтаксиса:
Более подробно работу со всеми этими типами синтаксиса мы еще разберем на примерах. Необязательные параметры {настройки} могут быть заданы как в начале, непосредственно после команды syntax, в самом конце или даже между перечислением ключевых слов в {определении}. Параметр {группа} определяет имя группы, к которым относится элемент синтаксиса, определяемый командой. Так как разработчики Vim старались унифицировать раскраску синтаксиса, чтобы ключевые слова для разных языков программирования раскрашивались одинаково, то большое количество групп уже созданы, и их раскраска уже задана в плагине тем, которые находятся в директории colors. Если элемент синтаксиса не попадает в уже существующую группу, то раскраска этого элемента становится сложнее, так как затем надо будет указать как будет раскрашиваться новая группа. К стандартным относятся следующие группы:
Внутри почти каждой из этих групп (кроме Comment, Underlined, Ignore, Error и Todo) существуют еще и подгруппы, которые позволяют более гибко настраивать раскраску. Например, внутри группы Type, предназначенной для раскраски типов переменных, есть подгруппы StorageClass, Structure и Typedef. Список всех стандартных групп с их подгруппами вы можете увидеть, если наберете в командной строке Vim команду :help group-name. Кроме того, мы можем увидеть все существующие группы (не только стандартные), если введем команду :highlight (или в сокращенном виде просто :hi). Создание раскраски pmWikiДавайте, наконец, начнем заполнять файл раскраски pmwiki.vim. Первое, что мы сделаем - это научим Vim выделять ключевые слова, и начнем мы с ключевого слова Attach, которое создает ссылку на файл, прикрепленный к странице. Добавим в файл pmwiki.vim следующие строки: if exists("b:current_syntax") finish endif let b:current_syntax="pmwiki" syntax keyword Keyword Attach В самом начале файла мы определяем переменную b:current_syntax, это требование ко всем плагинам синтаксиса. На последней строке мы создаем ключевое слово Attach, раскраска которого теперь будет соответствовать раскраске остальных ключевых слов. На следующем скриншоте вы можете увидеть как это слово раскрашивается при моих настройках: ![]() Для первого раза неплохо, однако такое применение команды syntax заставит Vim подкрашивать слово Attach даже в тексте (кстати, ключевые слова по умолчанию регистрозависимы). ![]() Было бы лучше, если бы раскрашивалось только слово Attach: с двоеточием, однако ключевые слова могут содержать только те символы, которые заданы параметром iskeyword (или сокращенно isk). По умолчанию для Windows значение этого параметра равно "@,48-57,_,128-167,224-235", а для остальных систем - "@,48-57,_,192-255". Первой идеей было, добавить в iskeyword еще и знак двоеточия, а затем определить синтаксис как syntax keyword Keyword Attach:, однако у меня это не сработало. Для решения этой проблемы существует другой способ с использованием типа синтаксиса match: if exists("b:current_syntax") finish endif let b:current_syntax="pmwiki" syntax match Keyword /Attach:/ Здесь для группы Keyword выделяются элементы синтаксиса, которые соответствуют регулярному выражению Attach: (без прямых слешей). Теперь раскрашенный текст будет выглядеть следующим образом: ![]() В нотации pmWiki многие команды задаются между символами (: ... :), давайте научим Vim выделять и их. Для этого можно использовать тот же тип синтаксиса match, но проще всего использовать тип region, в котором удобно задавать начало и конец выделяемой области. Добавим в конец файла синтаксиса новую строку, содержимое файла теперь выглядит следующим образом: if exists("b:current_syntax") finish endif let b:current_syntax="pmwiki" syntax match Keyword /Attach:/ syntax region Statement start=/(:/ end=/:)/ Здесь мы используем группу Statement, для которого Keyword является подгруппой. В файле темы Vim, которая у меня используется Statement и Keyword раскрашиваются одинаково, в результате раскрашенный текст будет выглядеть следующим образом: ![]() Главное отличие типа match от region в том, что синтаксические конструкции, определенные с помощью типа match не могут разрываться переносом строки, а элементы синтаксиса region могут быть многострочными. Давайте добавим еще два элемента синтаксиса в наш плагин раскраски: if exists("b:current_syntax") finish endif let b:current_syntax="pmwiki" syntax match Keyword /Attach:/ syntax region Statement start=/(:/ end=/:)/ syntax match Underlined /\M[[\.\{-}]]/ syntax match Statement /%\w*%/ Предпоследняя строка делает подчеркнутыми ссылки, которые задаются в двойных квадратных скобках. Здесь для наглядности мы используем немагический режим регулярных выражений (определяемый строкой \M), чтобы не нужно было бы добавлять обратный слеш перед каждым символом квадратных скобок. Также здесь используется выражение { - }, которое работает так же, как и * с той разницей, что * старается найти наибольший участок текста, совпадающий с регулярным выражением (жадный алгоритм), а {-} ищет наименьший участок текста (нежадный алгоритм). Последняя строка выделяет команды, заключенные между символами процента. Теперь раскрашенный текст будет выглядеть следующим образом: ![]() Использование нестандартных групп синтаксисаДо сих пор мы обходились только стандартными группами для определения синтаксиса, однако часто требуется больше видов раскраски, чем предоставляется по умолчанию. В этом случае в команде syntax мы просто задаем имя группы, которую хотим создать, а затем необходимо указать с помощью команды highlight (или сокращенно hi) каким образом эта группа должна быть раскрашена. Общий формат команды highlight следующий: highlight {группа} {параметры} Здесь {группа} - название группы, определенной с помощью оператора syntax или имя стандартной группы. С помощью команды highlight можно указывать разные цвета для графического и консольного режима Vim, для темы с темным фоном и светлым. У команды highlight довольно много параметров, поэтому перечислим только некоторые из них.
Давайте теперь создадим несколько нестандартных групп Сначала сделаем так, чтобы Vim выделял заголовки, которые обозначаются двумя или большим количеством восклицательных знаков, которые стоят в начале строки. Заголовки будут выделяться желтым фоном. Для этого нам нужно добавить всего две строки: syntax match header /^!!\+.\+/ highlight header ctermbg=Yellow guibg=Yellow В первой строки мы создаем группу header, которая должна соответствовать написанному регулярному выражению. На второй строке мы указываем как эта группа должна раскрашиваться. Здесь мы указали, что в цветном терминале и в gVim должен быть желтый фон. На черно-белом терминале эта группа выделяться не будет. На следующем скриншоте видно как будет выглядеть заголовок: ![]() Следующий пример показывает как можно сделать полужирное выделение текста, размещенного между тройными одинарными кавычками: syntax region bold start=/'''/ end=/'''/ highlight bold term=bold cterm=bold gui=bold В результате мы получим следующий внешний вид: ![]() Чуть выше мы уже определили раскраску для команд между скобками (: ... :), однако, если мы хотим какие-нибудь команды выделить отдельно, то достаточно определить новую раскраску, которая по сути будет являться частным случаем другой группы. Для примера сделаем так, чтобы команда (: title :) выделялась полужирным шрифтом и пурпурным цветом: syntax region titleCommand start=/(:title/ end=/:)/ highlight titleCommand ctermfg=Magenta guifg=Magenta cterm=bold term=bold gui=bold Теперь текст в нотации pmWiki, использующий все раскрашиваемые элементы, будет выглядеть следующим образом: ![]() Полностью файл раскраски теперь выглядит следующим образом: if exists("b:current_syntax") finish endif let b:current_syntax="pmwiki" syntax match Keyword /Attach:/ syntax region Statement start=/(:/ end=/:)/ syntax match Underlined /\M[[\.\{-}]]/ syntax match Statement /%\w*%/ syntax match header /^!!\+.\+/ highlight header ctermbg=Yellow guibg=Yellow syntax region bold start=/'''/ end=/'''/ highlight bold term=bold cterm=bold gui=bold syntax region titleCommand start=/(:title/ end=/:)/ highlight titleCommand ctermfg=Magenta guifg=Magenta cterm=bold term=bold gui=bold Формально текст с командой title попадает под две группы: titleCommand и Statement, однако из-за того, что группа titleCommand объявлена ниже, то приоритет отдается именно ей. На этом давайте пока прервемся, тема создания плагинов синтаксиса довольно объемная и ей можно посвятить целую статью, а то и не одну. Как всегда, жду ваших комментариев. Пожалуйста, оцените материал
|