Введение
В статье Ведение блога на 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/'
Name
404'
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.
Приятного блоггинга с помощью лучшего в мире редактора!
Немає коментарів:
Дописати коментар