let g:XkbSwitchEnabled = 1 let g:XkbSwitchLib = '/usr/local/lib/libg3kbswitch.so'Реализация g3kb-switch сильно отличается от xkb-switch: он не работает на уровне X протокола, а выполняет удаленные действия в Gnome Shell с помощью синхронных вызовов, передаваемых через шину сообщений D-Bus.
Показаны сообщения с ярлыком vim. Показать все сообщения
Показаны сообщения с ярлыком vim. Показать все сообщения
понедельник, 16 декабря 2019 г.
Новый переключатель раскладки g3kb-switch для Gnome 3 и vim-xkbswitch
Люди говорят (а я проверил), что xkb-switch больше (и наверное уже давно) не работает в Gnome Shell. Поэтому я решил написать его аналог для этой популярной среды. Он называется g3kb-switch и ведет себя практически аналогично xkb-switch. Так же, как и xkb-switch, он может быть настроен для работы с vim-xkbswitch. В базовом варианте для этого нужны всего две строки в файле .vimrc.
воскресенье, 31 января 2016 г.
vim-xkbswitch: управление keymap в нормальном режиме и в строках поиска
На днях добавил указанную фичу в vim-xkbswitch. Суть проста. При выходе из режима ввода (Insert mode) в нормальный режим (Normal mode) хотелось бы, чтобы после ввода команд r и f, а также в режиме поиска в командной строке (команды / и ?), системная раскладка переключалась на ту, что была в режиме ввода. К сожалению, реализовать такое с нуля технически весьма затруднительно. К счастью, можно воспользоваться встроенной в vim поддержкой keymap, и более того, управлять ею с помощью настройки iminsert и imsearch при выходе в нормальный режим.
В общем, если есть желание управлять keymap из vim-xkbswitch, то в файл .vimrc следует добавить такие строки.
let g:XkbSwitchAssistNKeymap = 1 " for commands r and f let g:XkbSwitchAssistSKeymap = 1 " for search lines set keymap=russian-jcukenwin set iminsert=0 set imsearch=0Значение keymap в данном случае зависит от дополнительной раскладки, с которой вы работаете. Если по какой-то причине имя системной раскладки (возвращается бэкенд-библиотекой, например xkb-switch) не совпадает с именем keymap (которое обычно присваивается переменной b:keymap_name в файле keymap), то можно настроить отображение из первого во второе, например
let g:XkbSwitchKeymapNames = {'ru' : 'ru_keymap'}Здесь ru — имя системной раскладки, а ru_keymap — предполагаемое значение b:keymap_name. Если вы работаете с несколькими раскладками одновременно (например, стандартной для нормального режима американской, русской и украинской), то возможно при выходе из режима ввода вы захотите, чтобы keymap указывал на ту из трех раскладок, которая была использована последней. Для этого вам понадобится динамическая настройка keymap, которую можно задействовать с помощью следующих настроек в .vimrc (вместо тех, что были приведены выше).
let g:XkbSwitchAssistNKeymap = 1 " for commands r and f let g:XkbSwitchAssistSKeymap = 1 " for search lines let g:XkbSwitchDynamicKeymap = 1 let g:XkbSwitchKeymapNames = {'ru' : 'russian-jcukenwin', \ 'uk' : 'ukrainian-jcuken'}Обратите внимание, здесь не требуется настройка keymap по умолчанию (хотя и не возбраняется), а в качестве значений в словаре g:XkbSwitchKeymapNames используются имена keymap, а не значения b:keymap_name. Если в нормальном режиме вы захотите переключиться на стандартную раскладку нормального режима, то просто временно зайдите в режим ввода и в нем переключитесь на соответствующую раскладку (это можно также сделать командой
:setlocal iminsert=0). В строке поиска то же самое можно сделать сочетанием клавиш Ctrl-^.
Все это хорошо, но есть одна серьезная проблема. Системный индикатор раскладки будет по-прежнему показывать стандартную в нормальном режиме раскладку, ведь vim-xkbswitch здесь не действует, а keymap не влияет на системную раскладку. На помощь приходит статусная строка, которую можно легко настроить для отображения значения keymap, когда iminsert равен 1, в плагине Powerline. Индикатор keymap будет отображать активную keymap раскладку для команд r и f и строк поиска, в случае, если iminsert равен 1, в то время как индикатор системной раскладки будет отображать стандартную для нормального режима раскладку. В режиме ввода индикатор keymap не действует, поскольку vim-xkbswitch отключает keymap установкой iminsert в 0. Такое решение, кстати, позволяет пользователю видеть, какая раскладка станет активной при переходе из нормального режима в режим ввода, а это здо́рово, на мой взгляд!
Я покажу, как настроить индикатор keymap в старом Powerline, в новейших репликах типа vim-airline действия должны быть похожи. Итак, в файле autoload/Powerline/Segments.vim в массиве, передаваемом в функцию Pl#Segment#Init() перед строкой, содержащей слово fileformat, вставляем строки
\ Pl#Segment#Create('keymap_name' , \'%{&iminsert && exists("b:keymap_name") ? b:keymap_name : ""}', \ Pl#Segment#Modes('!N')),, в файле autoload/Powerline/Themes/default.vim (или в другом файле темы Powerline, в зависимости от того, какую тему вы используете) в список, передаваемый в функцию Pl#Theme#Buffer(), перед строкой, содержащей слово fileformat, вставляем строку
\ , 'keymap_name', и, наконец, в файле autoload/Powerline/Colorschemes/default.vim (или в другом файле цветовой схемы Powerline, если вы используете нестандартную схему), в произвольном месте списка, передаваемого в функцию Pl#Colorscheme#Init(), вставляем строки
\ Pl#Hi#Segments(['keymap_name'], { \ 'n': ['brightestorange', 'gray2'], \ 'i': ['brightestorange', 'darkestblue'], \ }), \После этого выполняем команду
:PowerlineClearCache, перезагружаем vim и наслаждаемся индикацией keymap. Напоминаю, что стандартная в нормальном режиме раскладка отображаться не будет. Вот так может выглядеть статусная строка Powerline с индикатором keymap (обратите внимание на оранжевые буквы ru).
четверг, 23 октября 2014 г.
vim: ввод символов с ударением
Все время забываю, как это делается, поэтому запишу сюда как напоминание.
Прежде всего, здесь можно почитать, как вводить составные и юникодные символы в vim. А здесь приведена таблица с составными диакритическими знаками Unicode. Составные они потому, что комбинируются вместе с предыдущим введенным символом в новый единый символ.
В русской типографике для обозначения ударения можно использовать символ U+0301. Соответственно, для того, чтобы ввести, например, символ и́, нужно сначала ввести собственно и, а затем <C-v>u0301. Это действительно тяжело запомнить, и к тому же приходится временно переключать раскладку для ввода символа u, поэтому в .vimrc можно записать маппинг, например такой:
" insert combining acute accent when writing Russian texts easily imap <C-v>ё <C-v>u0301Теперь достаточно ввести и, а затем <C-v>ё. Как указано в комментарии, этот маппинг подходит только для ввода русского текста, поскольку ссылается на символ ё в своем определении. Обычно в русских раскладках буква ё расположена на месте тильды в левом верхнем углу клавиатуры, поэтому данный маппинг мне кажется и удобным, и логичным.
среда, 13 августа 2014 г.
Наклонное начертание шрифта (italic) в gnome-terminal и vim
Наклонное начертание поддерживается в последних версиях gnome-terminal (вроде бы, начиная с версии 3.6.1). Вот картинка-подтверждение.
Выглядит круто! К сожалению, сия красота в mate-terminal не доступна.
Для того, чтобы наклонный шрифт заработал в vim, просто запустить vim в gnome-terminal недостаточно. Вот здесь отличное руководство (см. секцию vim). Я, однако, не советую просто вписать новое значение TERM=xterm-256color-italic в .bashrc, если вы пользуетесь другими терминалами. Вместо этого лучше записать туда строки
[ "$COLORTERM" = "gnome-terminal" ] && toe -a | grep xterm-256color-italic > /dev/null 2>&1 && TERM=xterm-256color-italicTeперь переменная среды TERM будет автоматически устанавливаться в новое значение только внутри gnome-terminal и только в случае наличия в системе или в вашей домашней директории скомпилированного файла terminfo xterm-256color-italic. Update. Сегодня на своей Fedora 20 обновил MATE desktop до версии 1.8. Наклонных шрифтов в mate-terminal не появилось. В общем, собрал патч для старого vte, проверил на своем компьютере и послал в багзиллу Red Hat, вот сюда. Так что пользуйтесь, кому надо. Патч накладывается на версию vte 0.28.2 и совместим с SRPM пакетом Fedora 20. Мои настройки .bashrc теперь выглядят так:
case $COLORTERM in gnome*|mate*) toe -a | grep xterm-256color-italic > /dev/null 2>&1 && TERM=xterm-256color-italic || TERM=xterm-256color ;; konsole*) TERM=xterm-256color ;; esac
четверг, 9 января 2014 г.
vim: плагин publish_helper
Работу, начатую здесь и здесь, решил оформить в виде плагина vim (страница на гитхабе и страница на www.vim.org). Полная документация доступна по ссылкам, а также внутри плагина. Плагин состоит из двух частей. Первая часть - это собственно скрипт на viml, в котором определены команды MakeHtmlCodeHighlight (переименованная и улучшенная MakeBlogArticle) и MakeTexCodeHighlight (тоже улучшенная по сравнению с первой реализацией). Вторая часть написана на haskell и представляет собой фильтр для pandoc (фильтры доступны в pandoc начиная с версии 1.12), который позволяет подменять исходные блоки кода (CodeBlock) внутри абстрактного синтаксического дерева, представляющего документ, на неформатированные блоки (RawBlock), содержащие подсвеченный с помощью vim код.
Для того, чтобы показать как это работает, возьмем оригинальный пример из руководства пользователя pandoc, в котором приведена классическая реализация быстрой сортировки на haskell, и добавим туда еще пару образцов кода.
Идем дальше. Сохраняем этот пример в файле example.md и генерируем HTML файл example.html с помощью pandoc и фильтра vimhl из нашего плагина.
Это цвета схемы lucius с правильной подсветкой синтаксиса всех образцов. А теперь создадим аналогичный PDF документ.
Для того, чтобы показать как это работает, возьмем оригинальный пример из руководства пользователя pandoc, в котором приведена классическая реализация быстрой сортировки на haskell, и добавим туда еще пару образцов кода.
### Original example from [*Pandoc User's Guide*](http://johnmacfarlane.net/pandoc/README.html#fenced-code-blocks) ~~~~ {#mycode .haskell .numberLines hl="vim" startFrom="100"} qsort [] = [] qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ qsort (filter (>= x) xs) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ### Small C++ code sample ~~~~ {.cpp hl="vim"} G4UIQt * qtSession( dynamic_cast< G4UIQt * >( session ) ); if ( qtSession ) { qtSession->AddMenu( histoMenuHandle, histoMenuLabel ); BuildMenuTree( qtSession, histoMenuHandle, gDirectory->GetList() ); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ### Content of my *~/.vimrc.pandoc* ~~~~ {#vimrc_pandoc .vim .numberLines hl="vim"} syntax on filetype on filetype indent on filetype plugin on filetype plugin indent on let g:lucius_style = 'light' let g:lucius_contrast = 'high' let g:lucius_contrast_bg = 'high' set nocp " for line breaks with backslashes colorscheme lucius let g:PhCtrlTrans = 0 let g:PhHtmlPreAttrs = 'style="white-space: pre-wrap;"' runtime plugin/publish_helper.vim ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Это синтаксическая подсветка цветовой схемы lucius для типа файла pandoc, который будет доступен, если вы установите плагин для pandoc отсюда. Я вставил ее сюда из vim дословно с помощью команды MakeHtmlCodeHighlight.
Идем дальше. Сохраняем этот пример в файле example.md и генерируем HTML файл example.html с помощью pandoc и фильтра vimhl из нашего плагина.
pandoc --standalone -t html -F vimhl -o example.html example.mdПолучаем файл example.html с таким содержимым:
Original example from Pandoc User's Guide
100 qsort [] = [] 101 qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ 102 qsort (filter (>= x) xs)
Small C++ code sample
G4UIQt * qtSession( dynamic_cast< G4UIQt * >( session ) ); if ( qtSession ) { qtSession->AddMenu( histoMenuHandle, histoMenuLabel ); BuildMenuTree( qtSession, histoMenuHandle, gDirectory->GetList() ); }
Content of my ~/.vimrc.pandoc
1 syntax on 2 3 filetype on 4 filetype indent on 5 filetype plugin on 6 filetype plugin indent on 7 8 let g:lucius_style = 'light' 9 let g:lucius_contrast = 'high' 10 let g:lucius_contrast_bg = 'high' 11 12 set nocp " for line breaks with backslashes 13 colorscheme lucius 14 15 let g:PhCtrlTrans = 0 16 let g:PhHtmlPreAttrs = 'style="white-space: pre-wrap;"' 17 18 runtime plugin/publish_helper.vim
Это цвета схемы lucius с правильной подсветкой синтаксиса всех образцов. А теперь создадим аналогичный PDF документ.
pandoc --standalone -t latex -F vimhl -o example.tex example.mdОткрываем файл example.tex и вставляем в преамбулу строки
\usepackage{color} \usepackage{xcolor} \usepackage{fancyvrb} \newcommand{\VerbBar}{|} \newcommand{\VERB}{\Verb[commandchars=\\\{\}]} \DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}} \usepackage{framed} \newenvironment{Shaded}{ \definecolor{shadecolor}{rgb}{1.0, 1.0, 0.9} \setlength\parskip{0cm} \setlength\partopsep{-\topsep} \addtolength\partopsep{0.2cm} \begin{shaded} \scriptsize }{\end{shaded}}Зачем это нужно, вы можете прочесть в документации к плагину. Завершаем генерацию example.pdf.
latexmk -pdf exampleВот скриншот получившегося документа:
среда, 30 октября 2013 г.
Прямое цитирование подсветки синтаксиса из vim в tex
В предыдущей статье я показал, как с помощью pandoc экспортировать статьи в формате HTML в формат tex. Поскольку статьи в моем блоге содержат множество примеров исходного кода, то необходимо, чтобы pandoc умел их правильно подсвечивать. С этой задачей pandoc справляется неплохо, делегируя ее исполнение библиотеке highlighting-kate; если же какой-то язык не поддерживается (например VimL), то можно воспользоваться пакетом latex minted.
Всё это прекрасно. Однако выяснилось, что некоторые статьи данного блога (например эта) требуют прямого цитирования подсветки vim, поскольку в них, собственно, обсуждается как vim подсвечивает код и приводятся примеры. Я рассказывал, как я вставляю подсвеченный исходный код из vim в статьи блога здесь. Главная идея - волшебная команда vim MakeBlogArticle, которая преобразует выделенный текст (или весь буфер) в формат HTML с сохраненной подсветкой синтаксиса. MakeBlogArticle использует в качестве бэкенда скрипт TOhtml, поэтому реализовать ее не сложно. Теперь же нам нужна подобная команда MakeTexCodeHighlight, которая будет транслировать выделенный текст (или весь буфер) в некоторое представление tex, совместимое с документами, сгенерированными pandoc. Требования к совместимости понятны. Поскольку pandoc для подсветки исходного кода генерирует среду Shaded, реализованную через fancyvrb, то результирующий документ должен находиться внутри тэгов
Давайте реализуем команду MakeTexCodeHighlight.
Прежде всего нам понадобятся функции, определяющие цвета текста и фона синтаксической группы элемента под курсором. Вот их реализация:
Теперь напишем функцию write_latex_code_highlights(). Она будет выполнять основную работу по созданию документа: открывать окно для нового буфера, вводить открывающие и закрывающие тэги tex и, собственно, тело документа на основании списка, возвращенного функцией split_synids().
Опциональный третий аргумент write_latex_code_highlights() преобразует белый текст в черный. Белый текст может появиться в результате исчезновения синтаксических групп при переходе в новую цветовую схему. Дело в том, что я использую расширенную цветовую схему для отображения тэгов ctags (см. эту статью), и при замене ее на lucius все группы, добавленные ctags, исчезают, при этом функция GetFgColorUnderCursor() возвращает почему-то значение ffffff, соответствующее белому цвету, хотя реальный цвет "потерянных" элементов черный. В общем этот третий аргумент можно рассматривать как хак и в реальности он вряд ли нужен.
Вот определение команды MakeTexCodeHighlight:
Пример.
Код на C++:
Update. Заметил, что MakeTexCodeHighlight неправильно обрабатывает эти дословные символы ^M, ^D и т.п. Команда MakeBlogArticle делает это правильно, видимо в TOhtml они предварительно транслируются.
Update 2. В функции split_synids() тоже есть контрольные символы ^Y и ^E. Во всех случаях их использования можно избежать. Вообще, их появление в скрипте связано с эмуляцией действий пользователя в терминале с помощью комады normal. Если мы найдем соответствующие функции в API VimL, то команда normal будет не нужна. В самом деле, для сохранения и восстановления окна в API VimL предусмотрены функции winsaveview() и winrestview() - использование их вместо эмуляции действий пользователя в split_synids() упростит эту функцию и поможет избежать побочных эффектов, связанных с возможным ремаппингом ^Y и ^E пользователем. В функции write_latex_code_highlights() команда normal с контрольными символами используется для эмуляции ввода пользователем строк. В VimL есть функция append(), которая может легко заменить эту эмуляцию и, соответственно, убрать контрольные символы из кода write_latex_code_highlights() и упростить ее понимание.
Всё это прекрасно. Однако выяснилось, что некоторые статьи данного блога (например эта) требуют прямого цитирования подсветки vim, поскольку в них, собственно, обсуждается как vim подсвечивает код и приводятся примеры. Я рассказывал, как я вставляю подсвеченный исходный код из vim в статьи блога здесь. Главная идея - волшебная команда vim MakeBlogArticle, которая преобразует выделенный текст (или весь буфер) в формат HTML с сохраненной подсветкой синтаксиса. MakeBlogArticle использует в качестве бэкенда скрипт TOhtml, поэтому реализовать ее не сложно. Теперь же нам нужна подобная команда MakeTexCodeHighlight, которая будет транслировать выделенный текст (или весь буфер) в некоторое представление tex, совместимое с документами, сгенерированными pandoc. Требования к совместимости понятны. Поскольку pandoc для подсветки исходного кода генерирует среду Shaded, реализованную через fancyvrb, то результирующий документ должен находиться внутри тэгов
\begin{Shaded} \begin{Highlighting}[] ... \end{Highlighting} \end{Shaded}, а внутри своего тела использовать цветовые тэги \textcolor.
Давайте реализуем команду MakeTexCodeHighlight.
Прежде всего нам понадобятся функции, определяющие цвета текста и фона синтаксической группы элемента под курсором. Вот их реализация:
fun! <SID>get_color_under_cursor(bg) let synId = synID(line("."), col("."), 1) let name = synIDattr(synId, "name") if name == '' return 'none' endif let layer = a:bg ? "bg" : "fg" return <SID>Xterm2rgb256(synIDattr(synIDtrans(synId), layer)) endfun fun! GetFgColorUnderCursor() return <SID>get_color_under_cursor(0) endfun fun! GetBgColorUnderCursor() return <SID>get_color_under_cursor(1) endfunФункция get_color_under_cursor() - рабочая лошадка, выполняющая задания двух основных функций: GetFgColorUnderCursor() и GetBgColorUnderCursor(). Ее задача очень простая - выдать шестнадцатиричное значение цвета под курсором. Выражение
synIDattr(synIDtrans(synId), layer)возвращает номер этого цвета для 256-цветного терминала (да, я ограничился текстовой версией vim, в gvim это работать не будет!), а функция Xterm2rgb256() должна вернуть окончательное шестнадцатиричное число в виде строки. Функции Xterm2rgb256() в vim нет, мы должны ее реализовать. К счастью, подобных функций в разных плагинах vim полно. Многие из них используют обычную таблицу соответствия, однако я нашел аналитическую реализацию данной функции в плагине Colorizer. Вот адаптированная версия Xterm2rgb256(), возвращающая шестнадцатиричное число в виде строки:
" next Xterm2rgb... conversion functions are adopted from plugin Colorizer.vim fun! <SID>Xterm2rgb16(color) " 16 basic colors let r=0 let g=0 let b=0 let basic16 = [ \ [ 0x00, 0x00, 0x00 ], \ [ 0xCD, 0x00, 0x00 ], \ [ 0x00, 0xCD, 0x00 ], \ [ 0xCD, 0xCD, 0x00 ], \ [ 0x00, 0x00, 0xEE ], \ [ 0xCD, 0x00, 0xCD ], \ [ 0x00, 0xCD, 0xCD ], \ [ 0xE5, 0xE5, 0xE5 ], \ [ 0x7F, 0x7F, 0x7F ], \ [ 0xFF, 0x00, 0x00 ], \ [ 0x00, 0xFF, 0x00 ], \ [ 0xFF, 0xFF, 0x00 ], \ [ 0x5C, 0x5C, 0xFF ], \ [ 0xFF, 0x00, 0xFF ], \ [ 0x00, 0xFF, 0xFF ], \ [ 0xFF, 0xFF, 0xFF ] \ ] let r = basic16[a:color][0] let g = basic16[a:color][1] let b = basic16[a:color][2] return printf("%02x%02x%02x", r, g, b) endfun fun! <SID>Xterm2rgb256(color) let r=0 let g=0 let b=0 " 16 basic colors if a:color < 16 return <SID>Xterm2rgb16(a:color) " color cube color elseif a:color >= 16 && a:color < 232 " the 6 value iterations in the xterm color cube let valuerange6 = [ 0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF ] let color=a:color-16 let r = valuerange6[(color/36)%6] let g = valuerange6[(color/6)%6] let b = valuerange6[color%6] " gray tone elseif a:color >= 232 && a:color <= 255 let r = 8 + (a:color-232) * 0x0a let g = r let b = r endif return printf("%02x%02x%02x", r, g, b) endfunТеперь мы можем определить команды vim для того, чтобы комфортно получать значения цветов синтаксического элемента под курсором из терминала (для нашей основной цели эти команды не нужны, разве что только для отладки):
command GetFgColorUnderCursor echo GetFgColorUnderCursor() command GetBgColorUnderCursor echo GetBgColorUnderCursor()Следующим шагом будет реализация функции split_synids(), которая будет разбивать текст внутри области текста, ограниченной значениями номеров строк, переданных ей в качестве аргументов, на отдельные элементы, включающие в себя имя синтаксического элемента, его содержание (т.е. соответствующую подстроку), номер строки, в которой он находится, а также значения цветов текста и фона в шестнадцатиричном формате.
fun! <SID>split_synids(fst_line, last_line) let result = [] let save_cursor = getpos('.') let save_winline = winline() call setpos('.', [0, a:fst_line, 1, 0]) let cursor = getpos('.') while cursor[1] <= a:last_line let old_synId = '^' let old_start = cursor[2] let cols = col('$') if cols == 1 let cursor[1] += 1 let cursor[2] = 1 call setpos('.', cursor) continue endif while cursor[2] <= cols let synId = synIDattr(synID(line('.'), col('.'), 1), 'name') let fg = toupper(GetFgColorUnderCursor()) let bg = toupper(GetBgColorUnderCursor()) let cursor[2] += 1 call setpos('.', cursor) if synId != old_synId if old_synId != '^' call add(result, \ {'name': old_synId, \ 'content': strpart(getline('.'), old_start - 1, \ cursor[2] - old_start - 1), \ 'line': line('.'), 'fg': old_fg, 'bg': old_bg}) endif let old_synId = synId let old_start = cursor[2] - 1 endif let old_fg = fg let old_bg = bg endwhile call add(result, \ {'name': synId, \ 'content': strpart(getline('.'), old_start - 1, \ cursor[2] - old_start - 1), \ 'line': line('.'), 'fg': fg, 'bg': bg}) let cursor[1] += 1 let cursor[2] = 1 call setpos('.', cursor) endwhile call setpos('.', save_cursor) let move = winline() - save_winline if move != 0 let dir = move < 0 ? '^Y' : '^E' exe "normal ".abs(move).dir endif return result endfunВ переменной result будем сохранять список синтаксических элементов. Манипуляции с save_cursor и save_winline нужны для восстановления положения курсора и окна после завершения работы функции. Внутренний цикл while обходит элементы одной строки слева направо, добавляя информацию о встреченных синтаксических областях в result. Для этой цели вызываются функции GetFgColorUnderCursor() и GetBgColorUnderCursor(), которые идентифицируют синтаксический элемент под курсором. Возвращенное ими значение (строка, представляющая шестнадцатиричное число) переводится в верхний регистр: это будет нужно в итоговом документе, так как latex почему-то не любит нижний регистр в шестнадцатиричных числах (во всяком случае это верно для тэгов \textcolor). Внешний цикл while перебирает строки сверху вниз.
Теперь напишем функцию write_latex_code_highlights(). Она будет выполнять основную работу по созданию документа: открывать окно для нового буфера, вводить открывающие и закрывающие тэги tex и, собственно, тело документа на основании списка, возвращенного функцией split_synids().
fun! <SID>write_latex_code_highlights(fst_line, last_line, ...) let colors = g:colors_name colorscheme lucius let parts = <SID>split_synids(a:fst_line, a:last_line) exe "colorscheme ".colors let save_paste = &paste new +set\ nowrap\ paste normal a\begin{Shaded}^M\begin{Highlighting}[]^M let old_line = a:fst_line let line = old_line for hl in parts let line = hl['line'] while line > old_line normal o let old_line += 1 endwhile let part = escape(hl['content'], '\{}_$%') let part = substitute(part, '\\\\', '\\textbackslash{}', 'g') let fg = hl['fg'] " small hack to paint syntax group links that could have been lost " after switching colorscheme in black instead white if a:0 && a:1 && fg == 'FFFFFF' let fg = '000000' endif if fg != 'NONE' && part !~ '^\s*$' let part = '\textcolor[HTML]{'.fg.'}{'.part.'}' endif exe "normal a".part endfor while line < a:last_line normal o let line += 1 endwhile normal a^M0^D\end{Highlighting}^M\end{Shaded}^[gg set ft=tex if !save_paste set nopaste endif endfunКод, в общем-то, не должен вызывать затруднений. Прокомментирую лишь некоторые моменты. Я уже писал, зачем при создании документов для публикации я заменяю рабочую цветовую схему на схему lucius: просто она светлая и более подходит для создания статей, чем моя стандартная темная схема. Элементы ^M, ^D и ^[ в коде состоят не из двух символов; это одиночные символы, соответствующие вводу <Enter>, Ctrl-D и <Esc>. Чтобы их ввести в редакторе vim, наберите Ctrl-V и, удерживая клавишу Ctrl, соответствующий символ (M, D или <Esc>). Команда new устанавливает в новом буфере значения nowrap (чтобы строки не заворачивались - нет смысла) и paste (чтобы vim не выполнял вредную автоматическую индентацию текста). Поскольку значение paste устанавливается глобально, то оно восстанавливается при выходе из функции. Внутри цикла for собранные функцией split_synids() синтаксические элементы выводятся с помощью normal a, новые строки добавляются с помощью normal o. При выводе в буфер все символы {, }, _, $ и % слэшируются, а символ \ заменяется на \textbackslash{} - если этого не сделать, то возможны ложные интерпретации строк буфера как команд latex! Если цвет fg данного элемента не NONE, то он обрамляется тэгом \textcolor[HTML]{}{}.
Опциональный третий аргумент write_latex_code_highlights() преобразует белый текст в черный. Белый текст может появиться в результате исчезновения синтаксических групп при переходе в новую цветовую схему. Дело в том, что я использую расширенную цветовую схему для отображения тэгов ctags (см. эту статью), и при замене ее на lucius все группы, добавленные ctags, исчезают, при этом функция GetFgColorUnderCursor() возвращает почему-то значение ffffff, соответствующее белому цвету, хотя реальный цвет "потерянных" элементов черный. В общем этот третий аргумент можно рассматривать как хак и в реальности он вряд ли нужен.
Вот определение команды MakeTexCodeHighlight:
command -range=% MakeTexCodeHighlight \ silent call <SID>write_latex_code_highlights(<line1>, <line2>, 1)Теперь можно выделять нужные строки в буфере (без выделения команда обработает весь буфер) и, после ввода команды MakeTexCodeHighlight, копировать текст в новом окне и вставлять его в документ tex, созданный pandoc.
Пример.
Код на C++:
int main( void ) { return 0; }Код tex, сгенерированный MakeTexCodeHighlight:
\begin{Shaded} \begin{Highlighting}[] \textcolor[HTML]{005F87}{int} \textcolor[HTML]{008700}{main}\textcolor[HTML]{870087}{(} \textcolor[HTML]{005F87}{void} \textcolor[HTML]{870087}{)} \textcolor[HTML]{870087}{\{} \textcolor[HTML]{005FAF}{return} \textcolor[HTML]{AF5F00}{0}\textcolor[HTML]{870087}{;} \textcolor[HTML]{870087}{\}} \end{Highlighting} \end{Shaded}(кстати, чтобы вставить сюда этот результат я сначала выполнил MakeTexCodeHighlight, а затем, уже в новом буфере, MakeBlogArticle).
Update. Заметил, что MakeTexCodeHighlight неправильно обрабатывает эти дословные символы ^M, ^D и т.п. Команда MakeBlogArticle делает это правильно, видимо в TOhtml они предварительно транслируются.
Update 2. В функции split_synids() тоже есть контрольные символы ^Y и ^E. Во всех случаях их использования можно избежать. Вообще, их появление в скрипте связано с эмуляцией действий пользователя в терминале с помощью комады normal. Если мы найдем соответствующие функции в API VimL, то команда normal будет не нужна. В самом деле, для сохранения и восстановления окна в API VimL предусмотрены функции winsaveview() и winrestview() - использование их вместо эмуляции действий пользователя в split_synids() упростит эту функцию и поможет избежать побочных эффектов, связанных с возможным ремаппингом ^Y и ^E пользователем. В функции write_latex_code_highlights() команда normal с контрольными символами используется для эмуляции ввода пользователем строк. В VimL есть функция append(), которая может легко заменить эту эмуляцию и, соответственно, убрать контрольные символы из кода write_latex_code_highlights() и упростить ее понимание.
вторник, 20 августа 2013 г.
vim: редактирование файлов от имени суперпользователя, добавление новых сегментов Powerline
Настроить редактирование системных файлов от имени суперпользователя на домашнем компьютере несложно. Заводим файл в директории /etc/sudoers.d/ с произвольным именем, например users. Помещаем в него строки
Что здесь нехорошо? Собственно то, что мы дали пользователю username возможность выполнить любую системную команду с привилегией суперпользователя! Не забываем, что из vim можно выполнить системную команду с помощью :!. Именно поэтому в первом предложении я написал на домашнем компьютере: не стоит давать такие привилегии обычному пользователю username на промышленном сервере.
Последнее украшательство - добавление алиасов в файл .bashrc:
Всё это прекрасно, но хотелось бы, чтобы vim каким-нибудь образом отмечал то, что мы редактируем файл от имени суперпользователя. Что ж, это достаточно легко сдедать с помощью плагина Powerline. Лично я по-прежнему использую старую версию плагина, которую можно загрузить отсюда, поэтому следующий рецепт относится именно к ней.
Итак, наша задача - добавить новый сегмент, на котором, в случае, если пользователь редактирует файл от имени суперпользователя, во всех режимах vim будет красоваться жирная, хорошо заметная надпись SUDO на красном фоне. Поскольку это сообщение достаточно важное, пусть оно будет находиться в начале статусной строки. Для этого в файле .vim/autoload/Powerline/Segments.vim перед строкой
Далее помещаем новый сегмент на первую позицию списка всех сегментов. Для этого в файле .vim/autoload/Powerline/Themes/default.vim добавляем строку
Хорошо, но не очень. Видите темно-красные артефакты вокруг стрелки с SUDO? Исследование показало, что они связаны с сегментом paste_indicator, когда его текст соответствует пустой строке. Вы можете убедиться в этом выполнив
В нормальном режиме при установленном paste это выглядит так:
Host_Alias LOCAL = desktop Cmnd_Alias VIM = /usr/bin/vim, /usr/bin/vimdiff Defaults!VIM env_keep += "HOME" username LOCAL = NOPASSWD: VIMЗдесь имя desktop соответствует имени локального хоста. Если вы специально не изменяли это имя в вашей системе, то вместо desktop напишите localhost. Алиас хоста LOCAL используется в последней строке и разрешает редактирование файлов от имени суперпользователя только с локального компьютера. Имя username соответствует имени учетной записи пользователя, которому будет позволено редактировать файлы с помощью sudo. В данном примере мы разрешили пользователю username запускать программы vim и vimdiff от имени суперпользователя без ввода пароля. Кроме того, в третьей строке мы попросили sudo использовать оригинальное значение переменной окружения $HOME: это нужно для того, чтобы vim загружал скрипт .vimrc и все дополнительные плагины из домашней директории пользователя username, а не из директории суперпользователя.
Что здесь нехорошо? Собственно то, что мы дали пользователю username возможность выполнить любую системную команду с привилегией суперпользователя! Не забываем, что из vim можно выполнить системную команду с помощью :!. Именно поэтому в первом предложении я написал на домашнем компьютере: не стоит давать такие привилегии обычному пользователю username на промышленном сервере.
Последнее украшательство - добавление алиасов в файл .bashrc:
alias svim='sudo vim' alias svimdiff='sudo vimdiff'Теперь vim с правам суперпользователя можно вызывать как svim, а vimdiff - как svimdiff.
Всё это прекрасно, но хотелось бы, чтобы vim каким-нибудь образом отмечал то, что мы редактируем файл от имени суперпользователя. Что ж, это достаточно легко сдедать с помощью плагина Powerline. Лично я по-прежнему использую старую версию плагина, которую можно загрузить отсюда, поэтому следующий рецепт относится именно к ней.
Итак, наша задача - добавить новый сегмент, на котором, в случае, если пользователь редактирует файл от имени суперпользователя, во всех режимах vim будет красоваться жирная, хорошо заметная надпись SUDO на красном фоне. Поскольку это сообщение достаточно важное, пусть оно будет находиться в начале статусной строки. Для этого в файле .vim/autoload/Powerline/Segments.vim перед строкой
\ Pl#Segment#Create('paste_indicator' , '%{&paste ? "PASTE" : ""}', Pl#Segment#Modes('!N')),добавим похожую строку
\ Pl#Segment#Create('sudo_indicator' , '%{empty($SUDO_USER) ? "" : "SUDO"}', Pl#Segment#Modes('!N')),Это и есть новый сегмент, который мы назвали sudo_indicator (первый аргумент функции Pl#Segment#Create()). Второй аргумент Pl#Segment#Create() соответствует коду, который будет выполнен для определения текста сегмента. В нашем случае мы опираемся на тот простой факт, что команда sudo определяет переменную окружения $SUDO_USER, в которой записано имя пользователя, получившего привилегии суперпользователя, соответственно, если эта переменная определена (то есть vim был запущен из sudo), то второй аргумент будет равен SUDO, иначе - пустой строке. Третий параметр: Pl#Segment#Modes('!N') - говорит о том, что если текущее окно не в фокусе, то данный сегмент не будет отображаться - это нам вполне подходит.
Далее помещаем новый сегмент на первую позицию списка всех сегментов. Для этого в файле .vim/autoload/Powerline/Themes/default.vim добавляем строку
\ , 'sudo_indicator'перед строкой
\ , 'paste_indicator'а в файле .vim/autoload/Powerline/Colorschemes/default.vim описываем цветовые характеристики сегмента:
\ \ Pl#Hi#Segments(['sudo_indicator'], { \ 'n': ['brightgreen', 'brightestred', ['bold']], \ }),(это можно поместить, например, за определением
\ Pl#Hi#Segments(['SPLIT'], { \ 'n': ['white', 'gray2'], \ 'N': ['white', 'gray0'], \ 'i': ['white', 'darkestblue'], \ }),). Если вы используете другую тему или цветовую схему Powerline (то есть не default), то данные определения нужно поместить в соответствующие файлы. Итак, почти все готово, обновляем кэш Powerline:
:PowerlineClearCacheи открываем какой-нибудь файл с помощью svim. Вот какую статусную строку я увидел после этих изменений:
Хорошо, но не очень. Видите темно-красные артефакты вокруг стрелки с SUDO? Исследование показало, что они связаны с сегментом paste_indicator, когда его текст соответствует пустой строке. Вы можете убедиться в этом выполнив
:set pasteи
:set nopasteнесколько раз. К сожалению, как я понял, данная версия Powerline не способна удовлетворительно решить проблему с сегментом, который может содержать пустое значение. Если такой сегмент находится не в самом начале списка сегментов, то мы будем время от времени получать подобные стрелочные артефакты. В нашем случае возможны четыре решения данной проблемы:
- удалить сегмент paste_indicator (плохо);
- сделать так, чтобы надпись в paste_indicator присутствовала всегда (т.е. PASTE или NOPASTE - тоже не очень хорошо - зачем нам избыточная информация);
- перенести индикатор SUDO в комбинированный сегмент fileinfo (см. .vim/autoload/Powerline/Segments.vim), тоже не очень хорошо - придется использовать серый фон;
- сделать так, чтобы фон индикатора paste_indicator всегда соответствовал фону следующего постоянного сегмента mode_indicator. В этом случае цвет стрелочных артефактов будет совпадать с цветом фона следующего сегмента и, соответственно, они должны бесследно исчезнуть;
\ \ Pl#Hi#Segments(['paste_indicator'], { \ 'n': ['brightestred', 'brightgreen', ['bold']], \ 'i': ['brightestred', 'white', ['bold']], \ 'v': ['brightestred', 'brightorange', ['bold']], \ 'r': ['brightgreen', 'brightred', ['bold']], \ 's': ['brightestred', 'gray5', ['bold']], \ }),После перзагрузки кэша Powerline и запуска svim я получил следующие картинки:
В нормальном режиме при установленном paste это выглядит так:
Подписаться на:
Сообщения (Atom)








