\documentclass{article} \usepackage{minted} \begin{document} Here is a \textbf{C++} Hello World example: \begin{minted}[fontsize=\tiny,linenos=false,gobble=2]{c++} #include <iostream> int main( void ) { std::cout << "Hello world" << std::endl; return 0; } \end{minted} Here is a \textbf{Python} Hello World example: \begin{minted}[fontsize=\tiny,linenos=false,gobble=2]{python} #!/usr/bin/python print "Hello, World!" \end{minted} Here is a \textbf{Unknown} Hello World example: \begin{minted}[fontsize=\tiny,linenos=false,gobble=2]{unknown} $my_directive <- { p : 10 }; { p : 20 } end $my_directive \end{minted} Bye. \end{document}
Видите, гипотетический язык Unknown уже подсвечивается странно, а сейчас мы вставим киллер-код на sh, который полностью уничтожит синтаксис tex:
\documentclass{article} \usepackage{minted} \begin{document} Here is a highlight killer: \begin{minted}[fontsize=\tiny,linenos=false,gobble=2]{sh} #!/usr/bin/sh a=$HOME; hello_world="Hello world" \end{minted} Here is a \textbf{C++} Hello World example: \begin{minted}[fontsize=\tiny,linenos=false,gobble=2]{c++} #include <iostream> int main( void ) { std::cout << "Hello world" << std::endl; return 0; } \end{minted} Here is a \textbf{Python} Hello World example: \begin{minted}[fontsize=\tiny,linenos=false,gobble=2]{python} #!/usr/bin/python print "Hello, World!" \end{minted} Here is a \textbf{Unknown} Hello World example: \begin{minted}[fontsize=\tiny,linenos=false,gobble=2]{unknown} $my_directive <- { p : 10 }; { p : 20 } end $my_directive \end{minted} Bye. \end{document}
Это катастрофа! Я хочу, чтобы это выглядело так:
\documentclass{article} \usepackage{minted} \begin{document} Here is a highlight killer: \begin{minted}[fontsize=\tiny,linenos=false,gobble=2]{sh} #!/usr/bin/sh a=$HOME; hello_world="Hello world" \end{minted} Here is a \textbf{C++} Hello World example: \begin{minted}[fontsize=\tiny,linenos=false,gobble=2]{c++} #include <iostream> int main( void ) { std::cout << "Hello world" << std::endl; return 0; } \end{minted} Here is a \textbf{Python} Hello World example: \begin{minted}[fontsize=\tiny,linenos=false,gobble=2]{python} #!/usr/bin/python print "Hello, World!" \end{minted} Here is a \textbf{Unknown} Hello World example: \begin{minted}[fontsize=\tiny,linenos=false,gobble=2]{unknown} $my_directive <- { p : 10 }; { p : 20 } end $my_directive \end{minted} Bye. \end{document}
Участок с sh подсвечен синтаксисом sh, с C++ - синтаксисом C++, с Python - синтаксисом Python, а нечто непонятное Unknown - синтаксисом texZone из файла syntax/tex.vim. Язык программирования - параметр minted в фигурных скобках - подсвечен отдельно, в данном случае цветом цветовой группы Special.
Теперь о том, как этого добиться. Поскольку плагин Vimwiki уже умеет загружать синтаксическую подсветку для разных языков программирования (об этой возможности Vimwiki я рассказывал здесь), то пусть он потрудится и для tex. Я не шучу! Мы напишем наш after-syntax файл $HOME/.vim/after/syntax/tex.vim в котором будет использован вызов VimwikiGet() и слегка адаптированная функция vimwiki#base#nested_syntax()! Вот его содержание, а комментарии ниже:
" content highlights inside lstlisting must be disabled syntax region texZone start="\\begin{lstlisting}" end="\\end{lstlisting}" " fallback option for minted is also texZone syntax region texZone start="\\begin{minted}" end="\\end{minted}" if !exists('g:tex_hl_minted') || g:tex_hl_minted == 0 finish endif " Vimwiki's function vimwiki#base#nested_syntax() adaptation function! s:nested_syntax(hltype, filetype, start, end) abort " From http://vim.wikia.com/wiki/VimTip857 let ft=toupper(a:filetype) let group='textGroup'.ft if exists('b:current_syntax') let s:current_syntax=b:current_syntax " Remove current syntax definition, as some syntax files (e.g. cpp.vim) " do nothing if b:current_syntax is defined. unlet b:current_syntax endif " Some syntax files set up iskeyword which might scratch vimwiki a bit. " Let us save and restore it later. " let b:skip_set_iskeyword = 1 let is_keyword = &iskeyword try " keep going even if syntax file is not found execute 'syntax include @'.group.' syntax/'.a:filetype.'.vim' execute 'syntax include @'.group.' after/syntax/'.a:filetype.'.vim' catch endtry execute 'syntax match texExtCodeLang "{\@<='.a:hltype.'\ze}"' execute 'syntax region texMintedStart start="\\begin{minted}" end="}" '. \ 'contains=texSectionMarker,texBeginEnd,texExtCodeLang '. \ 'nextgroup=@'.group.' contained' let &iskeyword = is_keyword if exists('s:current_syntax') let b:current_syntax=s:current_syntax else unlet b:current_syntax endif execute 'syntax region textSnip'.ft. \ ' start="'.a:start.'" end="'.a:end.'"'. \ ' contains=@'.group.',texMintedStart '. \ 'containedin=texDocZone,texPartZone,texChapterZone,'. \ 'texSectionZone,texSubSectionZone,texSubSubSectionZone,'. \ 'texParaZone,texSubParaZone,texAbstract keepend' " A workaround to Issue 115: Nested Perl syntax highlighting differs from " regular one. " Perl syntax file has perlFunctionName which is usually has no effect due to " 'contained' flag. Now we have 'syntax include' that makes all the groups " included as 'contained' into specific group. " Here perlFunctionName (with quite an angry regexp "\h\w*[^:]") clashes with " the rest syntax rules as now it has effect being really 'contained'. " Clear it! if ft =~ 'perl' syntax clear perlFunctionName endif endfunction let s:regStart = '\\begin{minted}\s*\n*\(\[\_[^]]*\]\)*\s*\n*{' let s:regEnd ='\ze\\end{minted}' let s:nested = VimwikiGet('nested_syntaxes') if !empty(s:nested) for [s:hl_syntax, s:vim_syntax] in items(s:nested) if s:vim_syntax == 'tex' continue endif call s:nested_syntax(s:hl_syntax, s:vim_syntax, \ s:regStart.s:hl_syntax.'}', s:regEnd) endfor endif hi link texExtCodeLang Special
Чтобы это правильно работало, не забудьте вставить в .vimrc определение g:WikiGlobal.nested_syntaxes с указанием тех языков программирования, которые вы намерены подсвечивать в Vimwiki и Tex / minted. Кроме того, добавьте туда строки
let g:tex_isk = '48-57,a-z,A-Z,192-255,_' let g:tex_hl_minted = 1Теперь комментарии по коду. Первые два определения syntax region указывают, что мы хотим подсвечивать области, начинающиеся с \begin{lstlisting} или \begin{minted} и заканчивающиеся на \end{lstlisting} или \end{minted} соответственно, одним цветом региона texZone. Директива lstlisting - это часть пакета tex listings, который похож на minted, но, в отличие от последнего, использует не Python Pygments, а какие-то собственные алгоритмы. Его было бы тоже неплохо подсвечивать синтаксисом используемого языка программирования, но, к сожалению, в listings , в отличие от minted, язык задается в отдельной директиве.
Почему мы здесь задаем одноцветную подсветку texZone и для minted тоже? Ведь мы собирались использовать полноценный синтаксис языка программирования внутри его региона! Ответ прост - это fallback режим для языков типа Unknown, не указанных в g:WikiGlobal.nested_syntaxes. Более точные определения синтаксических регионов для всех сконфигурированных в g:WikiGlobal.nested_syntaxes языков задаются в цикле for в нижней части приведенного кода. Переменная s:nested, являющаяся выходным значением функции VimwikiGet(), содержит маппинг, заданный в переменной g:WikiGlobal.nested_syntaxes.
Главная задача цикла for - настройка уточненных синтаксических регионов minted для всех сконфигурированных языков программирования (кроме собственно tex - иначе мы получим одноцветный регион texZone для всех языков). В цикле происходит вызов функции s:nested_syntax() - слегка видоизмененной vimwiki#base#nested_syntax(). Изменений там немного. Во-первых изменен прототип: первым аргументом добавлен ключ из элемента g:WikiGlobal.nested_syntaxes - он нужен для формирования синтаксической области texExtCodeLang - см. далее, и убран последний аргумент textSnipHl, который соответствовал ненужному нам matchgroup в синтаксическом регионе textSnip<Lang> (где <Lang> - синтаксическая группа, соответствующая конфигурируемому языку). Добавлены определения syntax match texExtCodeLang и syntax region texMintedStart, который внесен в список contains в определении syntax region textSnip<Lang>. Определение синтаксического региона textSnip
Синтаксический регион texMintedStart соответствует началу области minted и соответствует сложному регулярнуму выражению, заданному в переменной s:regStart. Сложность выражения позволяет разбивать отдельные элементы преамбулы \begin{minted} на отдельные строки. Область texExtCodeLang соответствует спецификации языка программирования в преамбуле minted и будет подсвечиваться цветом группы Special (см. последнюю строку приведенного кода).
Ну вот собственно и все, теперь все подсвечивается правильно. Спасибо Vimwiki!
Напоследок хочу уточнить, что указание переменной g:tex_isk будет работать только в последних версиях syntax/tex.vim. Например, в стандартном пакете vim в Fedora 17 используется старая версия этого файла, поэтому я положил текущую версию из репозитория vim к себе в $HOME/.vim/syntax/. Вообще, g:vim_isk нужен нам только для задания символа подчеркивания (_) в качестве символа iskeyword для файлов tex. В нашем случае это исправит возможные искажения синтаксиса внутри регионов minted, если в них используются символы подчеркивания. Для файлов tex символ подчеркивания был убран из списка iskeyword по каким-то соображениям, однако в последних версиях syntax/tex.vim появилась возможность вернуть его с помощью переменной g:tex_isk. Если у вас старая версия syntax/tex.vim и вы не хотите устанавливать новую версию в $HOME/.vim/syntax/, то можете просто добавить строку
setlocal iskeyword+=_в файл $HOME/.vim/after/syntax/tex.vim.
Комментариев нет:
Отправить комментарий