середа, 10 грудня 2014 р.

Не grep’ом единым

Нашёл интересную замену grep‘у: The Silver Searcher. Команда имеет ряд преимуществ перед grep:
  • работает быстрее (можно почитать объяснение автора по поводу способов ускорения)
  • игнорирует файлы, указанные, например, в .gitignore (можно также использовать и .agignore)
  • также автор пишет: “The command name is 33% shorter than ack“. Ну конечно же имя ag в два раза короче grep
Пример для grep:
grep -r CELERYBEAT_SCHEDULE *
Binary file src/.ropeproject/globalnames matches
Binary file src/worker/.celeryconfig.py.swp matches
src/worker/celeryconfig.py:CELERYBEAT_SCHEDULE = {
src/worker/celeryconfig.py:    CELERYBEAT_SCHEDULE["one_per_hour-daylight-%s" % tz] = {
src/worker/celeryconfig.py:    CELERYBEAT_SCHEDULE["three_per_day-%s" % tz] = {
src/worker/celeryconfig.py:    CELERYBEAT_SCHEDULE["one_per_day-%s" % tz] = {
Binary file src/worker/celeryconfig.pyc matches
src/worker/celeryconfig.py~:CELERYBEAT_SCHEDULE = {
src/worker/celeryconfig.py~:    CELERYBEAT_SCHEDULE["one_per_hour-daylight-%s" % tz] = {
src/worker/celeryconfig.py~:    CELERYBEAT_SCHEDULE["three_per_day-%s" % tz] = {
src/worker/celeryconfig.py~:    CELERYBEAT_SCHEDULE["one_per_day-%s" % tz] = {

Как видим, grep обрабатывает лишние файлы. Конечно, можно указать флаг --exclude, но лень :)
Пример для ag:
ag -r CELERYBEAT_SCHEDULE *
src/worker/celeryconfig.py
78:CELERYBEAT_SCHEDULE = {
105:    CELERYBEAT_SCHEDULE["one_per_hour-daylight-%s" % tz] = {
115:    CELERYBEAT_SCHEDULE["three_per_day-%s" % tz] = {
122:    CELERYBEAT_SCHEDULE["one_per_day-%s" % tz] = {

Результат представлен более приятно (и ускорение работы заметно).
Естественно, есть плагин для Vim.

середа, 3 грудня 2014 р.

Крапчасті сомики і деякі можливості Vim

Вчора у мене в акваріумі вперше вилупились малькі крапчастих сомиків. Було вже кілька нерестів в акваріумі з гупіями. Зазвичай ікру самка відкладала на стінках акваріуму. Цього частина ікри була на листку, який я й переклав до банки. Воду в банці я прогрівав десь до 26˚C. Десь за тиждень з’явилось 4 або 5 мальків. Фото поки що не буде, бо малькі дуже маленькі. Сподіваюсь, мені вдасться їх виростити.

P.S. Знак ˚ я виставив за допомогою функціоналу Vim’а, що має назву digraphs - можна вставляти в текст велику кількість подібних спеціальних знаків

середа, 26 листопада 2014 р.

Музей корупції "Межигір'я"

Этим летом мы с Викой побывали в музее коррупции "Межигір'я". Ниже будет небольшой фоторепортаж. О размерах бывшего обиталища Януковича скажу следующее. Сначала мы ездили минут 45 на электромобиле с обзорной экскурсией. Затем взяли на прокат велосипеды и катались еще два часа, рассматривая более подробные разные интересности. Потом еще почти час ходили по зоопарку. Устали довольно сильно. При этом не успели посетить Хонку и так и не нашли дорожку с пеньками. Так что надо будет съездить еще раз.


Вот на таких автомобильчиках проводится обзорная экскурсия.


На входе дают на прокат велосипеды. Обходить пешком все территорию нереально.






На всех фонарных столбах висит Янукович изображен герб семьи Януковичей. К сожалению, видно плохо



Знаменитая Хонка. Название происходит от финского слова "сосна"


Набережная

Экскурсовод сказал, что длина - 6 км., как в Феодосии. Я не измерял, но визуально сравнима с феодосийской

Молоко Батя пил от собственных коров



Прочая живность

Галеон



Тревожить покой Януковича не рекомендовалось

Гараж

Сад...

... и теплица

В зоопарке очень много козлов. Подозреваю, что Янукович чувствовал к ним какую-то близость (хотя и не хорошо сравнивать бедных животных с ним)





Высота забора - 6м.

Слава Україні!


середа, 12 листопада 2014 р.

Проверка правильности ссылок в Markdown-файлах

Введение

В статье Ведение блога на Blogger с помощью Vim я описал ведение блога на Blogger с помощью Vim и специального python-скрипта, который используется для публикации текстов. Как правило, хороший пост содержит некоторое количество ссылок. Естественно, хотелось бы быть уверенным, что ссылки не содержат ошибок. Способ проверки, изложенный в статье не очень подходит, так как предложенный скрипт просто выводит ссылку и результат её проверки. Более удобной бы была проверка в соответствии с идеологией Vim: с помощью :make и quickfix. Рассмотрим, как можно добиться такого функционала.

Выбор инструмента

Для проверки ссылок будем использовать linkchecker. Данный инструмент может проверять как сайты, так и локальные файлы. Также он поддерживает систему плагинов. Например, существуют плагины для проверки ссылок в документах MS Word или pdf-файлах.
Установка:
sudo pip install LinkChecker

Теперь можно проверять файлы:
linkchecker -v --check-extern t.html
LinkChecker 9.3              Copyright (C) 2000-2014 Bastian Kleineidam
...
Start checking at 2014-11-12 16:16:56+003
...
URL        http://xvadim.chgk.info/wb1/'
Name404'
Parent URL file:///Users/vadimkhohlov/work/blogger/t.html, line 6, col 9
Real URL   http://xvadim.chgk.info/wb1/
Check time 1.696 seconds
Size       284B
Result     Error: 404 Not Found
...

Разработка плагина

Инициализация

Файл с кодом плагина должен располагаться в подкаталоге linkcheck/plugins. Задача плагина - извлечь все ссылки из файла. Корректность ссылок будет проверять сам linkchecker.
Класс в нашем случае должен наследоваться от _ContentPlugin:
from . import _ContentPlugin
from .. import log, LOG_PLUGIN
class MarkdownCheck(_ContentPlugin):
    _default_filename_re = re.compile(r'.*\.(markdown|md(own)?|mkdn?)$')

    def __init__(self, config):
        super(MarkdownCheck, self).__init__(config)
        self.filename_re = self._default_filename_re

    def applies_to(self, url_data, pagetype=None):
        return self.filename_re.search(url_data.base_url) is not None
Метод applies_to должен вернуть True если плагин умеет обрабатывать данный файл. linkchecker пытается самостоятельно определить тип файла и передаёт его через параметр pagetype. Однако, в нашем случае он этого сделать не может. Поэтому приходится анализировать имя файла.

Обработка файла

Обрабатывает файл метод check(self, url_data):
_link_res = [re.compile(r'<((https?|ftp):[^\'">\s]+)>', re.I)]
def check(self, url_data):
    content = url_data.get_content()
    self._check_by_re(url_data, content)
def _save_url(self, url_data, content, url_text, url_pos):
    line = content.count('\n', 0, url_pos) + 1
    column = url_pos - content.rfind('\n', 0, url_pos)
    url_data.add_url(url_text.translate(None, '\n '), line=line, column=column)
def _check_by_re(self, url_data, content):
    for link_re in self._link_res:
        for u in link_re.finditer(content):
            self._save_url(url_data, content, u.group(1), u.start(1))
С помощью регулярного выражения метод выбирает автоссылки вида <http://autolink.com> и добавляет их к объекту url_data. Номер строки вычисляется как количество символов \n, а столбец - как расстояние до ближайшего левого \n.

Дополнительные настройки плагина

Для того, чтобы данный плагин был активирован, необходимо в файле ~/.linkchecker/linkcheckerrc добавить строку:
[MarkdownCheck]
Было бы неплохо как-то параметризовать маску имени файла. Например, я, как писал ранее, сохраняю файлы постов блога с расширением blog. Добиться этого можно следующим кодом:
_filename_re_key = "filename_re"
def __init__(self, config):
        super(MarkdownCheck, self).__init__(config)
        self.filename_re = self._default_filename_re
        pattern = config.get(self._filename_re_key)
        if pattern:
            try:
                self.filename_re = re.compile(pattern)
            except re.error as msg:
                log.warn(LOG_PLUGIN, "Invalid regex pattern %r: %s" % (pattern, msg))

    @classmethod
    def read_config(cls, configparser):
        """Read configuration file options."""
        config = dict()
        config[cls._filename_re_key] = configparser.get(cls.__name__, cls._filename_re_key) \
            if configparser.has_option(cls.__name__, cls._filename_re_key) else None
        return config
Скрипт ищет в конфиге параметр с ключем filename_re. Если не находит, использует стандартную маску имён Markdown-файлов. После этого конфиг может быть таким:
[MarkdownCheck]
filename_re=.*.(blog|markdown|md(own)?|mkdn?)$

Установка

Форк с моим кодом лежит на Github. Pull-request я отправил. Пока же можно вручную подложить файл плагина markdowncheck.py в нужное место: .../site-packages/linkcheck/plugins

Настройка Vim

Для настройки Vim необходимо задать две переменные: makeprg - команда, которая будет вызываться по :make errorformat - фильтр, с помощью которого будут из вывода команды выбираться строки с ошибками
Для обработки файла я использую такую команду: linkchecker -v --check-extern -f ~\/work/blogger/lrc -o csv file_name Аргумент --check-extern говорит, что надо проверять не только правильность ссылок, но и их валидность. С помощью -o csv задаётся формат вывода в виде csv-файла, содержащего по одной строке на каждую ссылку. Таким образом, настройки Vim будут следующими:
set makeprg=linkchecker\ -v\ --check-extern\ -f\ ~\/work\/blogger\/lrc\ -o\ csv\ '%'
set errorformat=%-G#%.%#,
                \%-Gurlname;parentname;%.%#,
                \%-G%.%#;True;%.%#,
                \%-G%.%#URLs\ checked%.%#,
                \%.%#;file://%f;;%m;;%.%#;False;%.%#;%l;%c;%.%#;%.%#;%.%#;%.%#;%.%#;%.%#;
Из вывода команды мы отбрасываем все строки, кроме содержащих информацию об ошибочных ссылках (с помощью первых четырёх элементов errorformat). Мила ЙововичПятый элемент errorformat обрабатывает все строки, в которых в седьмом столбце стоит False, т.ё. строки с информацией об ошибке. Назначение некоторых элементов errorformat:
  • %-G - пропустить строку, удовлетворяющую заданному шаблону
  • %f - имя файла
  • %m - текст сообщения об ошибке
  • %l - номер строки
  • %c - номер столбца
  • %.%# - транслируется в регэксп .*

С такими настройками, выполнив команду :make и открыв quickfix-окно, получим следующее:

Теперь можно использовать всю мощь режима quickfix, например, перемещаться по ошибочным ссылкам с помощью :cn.
Приятного блоггинга с помощью лучшего в мире редактора!

пʼятниця, 24 жовтня 2014 р.

Ведение блога на Blogger с помощью Vim

Введение

В последнее время я стал активно гадить писать посты в Blogger. Естественно, захотелось настроить правильный инструмент для упрощения себе жизни. Основных цели было две:
  • упрощение процесса редактирования
  • возможность подготовки черновиков постов в офф-лайн
Для Vim существует несколько плагинов, например Blogger.vim. Однако, у меня он не заработал, выдавая какую-то ошибку.
Основой моих настроек для Vim’а послужила вот эта статья.

Установка скрипта для постинга и его настройка

В указанной выше статье описан скрипт b.py. Скрипт позволяет подготавливать тексты в формате Markdown или reStructuredText. Установка скрипта и необходимых зависимостей описана в документации. Ему необходим конфигурационный файл brc.py подобного содержания:
import re
service = 'blogger'
service_options = {
    'blog': YOUR_BLOG_ID
}
handlers = {
    'Markdown': {
        'match': re.compile(r'.*.(blog|markdown|md(own)?|mkdn?)$'),
        'module': 'bpy.handlers.mkd',
        'options': {
            'config': {
                'extensions': ['footnotes', 'toc'],
            },
            'smartypants': True,
        },
    }
}

С помощью строки
'match': re.compile(r'.*.(blog|markdown|md(own)?|mkdn?)$')
я настраиваю скрипт таким образом, чтобы он воспринимал также файлы с расширением blog.
После подготовки конфига необходимо выполнить авторизацию, как описано в документации. В результате в этом же каталоге будет создан файл b.dat с нужным токеном. Скрипт b.py нужно обязательно запускать из каталога, содержащего файлы brc.py и b.dat.

Установка нужного filetype и подсветки синтаксиса

Файл поста - это частный случай Markdown-файла, поэтому я добавил в ~/.vim/ftdetect/ftdetect.vim следующую строку:
au BufRead,BufNewFile *.blog    set filetype=blog syntax=markdown
Таким образом я сообщаю Vim’у что тип файла будет blog, а вот для подсветки синтаксиса использовать те же правила, что и для Markdown-файлов.

Шаблон нового файла

Скрипт требует, чтобы каждый новый файл поста имел следующий заголовок
!b
service: blogger
title: Some title
labels: List of tags
(после публикации в заголовок будет добавлен ещё ряд полей). Для задания шаблонов создаваемых файлов я использую плагин aperezdc/vim-template. Поэтому добавил в каталог для ведения блога файл .vim-template:*.blog:
!b
service: blogger
title: %FILE%
labels: productivity, Vim, programming


%HERE%

После этого для создания нового поста необходимо ввести команду:
mvim "Ведение блога на Blogger с помощью Vim.blog"
(имя файла становится заголовком поста).

Настройки маппинга

В статье приводится настройка нескольких маппингов для:
  • публикации поста
  • создания html-файла для предварительного просмотра
  • проверки валидности ссылок, упоминаемых в посте
Я оставил только первый, создав файл ~/.vim/ftplugin/blog.vim:
set autoread
map <buffer> <leader>post :exec '!b.py post '.shellescape(expand('%:p'))

Проверку ссылок я не делал, так как предлагаемый автором статьи способ не соответствует идеологии Vim (по-хорошему, проверку следует настроить через makeprg). К тому же, ссылки, как правило, вставляются с помощью копирования, поэтому в проверке валидности особенного смысла нет.
Как было указано ранее, скрипт после публикации поста добавляет в файл дополнительные заголовки. Опция set autoread заставляет Vim автоматически перечитывать файл после его изменения извне.

Snippets

Для подсветки синтаксиса в блоге я использую highlight.js. Естественно, вручную каждый раз вводить <pre><code>...</code></pre> некомильфо. Целесообразно это делать с помощью какого-нибудь сниппета. С другой стороны, как отмечалось выше, файл поста - это частный случай Mardown-файла, поэтому было бы неплохо использовать также сниппеты для таких файлов. С этой целью я создал следующий UltiSnip-файл:
extends markdown

snippet code "code fragment"
<pre><code class="${1:python}">$0
</code></pre>
endsnippet

Дополнительные улучшения

Чтобы ещё больше упростить вставку в текст блога файлов целиком (избежать цепочки действий: написать <pre>… - открыть файл - скопировать - вставить) я написал такую функцию и команду:
func! s:InsertCode(file_name)
    let code_lang = substitute(a:file_name, '[^\.]*\.', '', 'i')
    call setline('.', getline('.').'<pre><code class="'.code_lang.'">')
    norm! o
    call setline('.', getline('.').'</code></pre>')
    norm! k
    exec "r ".a:file_name
endfu

command! -nargs=1 -complete=file Rc call s:InsertCode(<f-args>)

Так как аргументом команды является имя файла, то я указал -complete=file, чтобы Vim при нажатии на Tab выполнял нужное автодополнение.

Заключение

Таким образом, после непродолжительного размахивания напильником, я получил удобный инструмент для создания и редактирования постов.

понеділок, 20 жовтня 2014 р.

Визуализация режима для Zsh Vi Mode

Как известно, для zsh можно включить vim-режим для ввода команд. Однако, существует проблема: не всегда можно быстро понять в каком режиме находишься  - NORMAL или INSERT. Это проблему можно побороть, например, добавив в правую часть приглашения визуализацию текущего режима. Для этого надо добавить в .zshrc:
function zle-line-init zle-keymap-select {
    VIM_PROMPT="%{$fg_bold[yellow]%} [% NORMAL]%  %{$reset_color%}"
    RPROMPT="${${KEYMAP/vicmd/$VIM_PROMPT}/(main|viins)/} $EPS1"
    zle reset-prompt
}
zle -N zle-line-init
zle -N zle-keymap-select

Идея взята здесь

четвер, 16 жовтня 2014 р.

Мини-обзоры Vim-скриптов. Часть III: smartpairs - умное выделение текстовых объектов.

Как известно, Vim содержит серию команд для выделения текстовых объектов.
Например, команда va" выделяет фрагмент текста между ближайшими к курсору кавычками ("), включая их,  а vi" - не включая. Помимо " могут также использоваться символы:
<, >, ", ', `, (, ), [, ], {, } или t для HTML(XML)-тегов и ряд других.
Таким образом можно не только выделять текстовые объекты, но и выполнять над ними действия, т.е. использовать команды c, d, y.

Скрипт smartpairs.vim упрощает работу с текстовыми объектами.

Во-первых, при его использовании вместо перечисленных выше символов достаточно после, например, vi нажать еще раз v (клавишу, конечно же можно переопределить). Скрипт ищет ближайшую пару символов к текущему положению курсора и обрабатывает получившийся текстовый объект. Если еще раз нажать v, скрипт найдет следующую пару символов и расширить границы текущего текстового объекта.

Во-вторых, для более быстрого выделения текстового объекта можно использовать команду vv.

В-третьих,  используемый по умолчанию Uber-режим чередует i- и a- команды над текстовыми объектами.

Также следует сказать, что автор скрипта довольно быстро исправляет найденные баги.

Предыдущие обзоры:
Мини-обзоры Vim-скриптов. Часть I: startify & rooter
Мини-обзоры Vim-скриптов. Часть II: Headlights - меню установленных плагинов