вторник, 20 августа 2013 г.

vim: редактирование файлов от имени суперпользователя, добавление новых сегментов Powerline

Настроить редактирование системных файлов от имени суперпользователя на домашнем компьютере несложно. Заводим файл в директории /etc/sudoers.d/ с произвольным именем, например users. Помещаем в него строки
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 не способна удовлетворительно решить проблему с сегментом, который может содержать пустое значение. Если такой сегмент находится не в самом начале списка сегментов, то мы будем время от времени получать подобные стрелочные артефакты. В нашем случае возможны четыре решения данной проблемы:
  1. удалить сегмент paste_indicator (плохо);
  2. сделать так, чтобы надпись в paste_indicator присутствовала всегда (т.е. PASTE или NOPASTE - тоже не очень хорошо - зачем нам избыточная информация);
  3. перенести индикатор SUDO в комбинированный сегмент fileinfo (см. .vim/autoload/Powerline/Segments.vim), тоже не очень хорошо - придется использовать серый фон;
  4. сделать так, чтобы фон индикатора paste_indicator всегда соответствовал фону следующего постоянного сегмента mode_indicator. В этом случае цвет стрелочных артефактов будет совпадать с цветом фона следующего сегмента и, соответственно, они должны бесследно исчезнуть;
Лично я воспользовался последним вариантом и переопределил paste_indicator в .vim/autoload/Powerline/Colorschemes/default.vim как
    \
    \ 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 это выглядит так:

 

Комментариев нет:

Отправить комментарий