S.Tominoff

Fullstack JavaScript разработчик

markdown в sublime text

Посмотрим как добавить в sublime text функциональность md редактора.

Однозначно существует множество классных инструментов позволяющих работать с форматом markdown, к примеру, десктопный ReText или онлайн сервис dillinger.io, однако я бы хотел иметь один универсальный редактор, и на мой взгляд, лучше всего на эту роль подходит Sublime Text.

Чтобы конвертировать markdown в html на лету, воспользуемся nodejs модулем markmon. Этот модуль поднимает сервер, получает на вход markdown разметку, конвертирует её и выводит в браузер. Для установки нужен штатный nodejs менеджер пакетов npm (установка nodejs и npm).

 

После установки npm инсталлируем пакет markmon:

npm install -g markmon

Флаг -g означает, что пакет будет установлен как системный (возможно понадобятся права администратора для установки)

 

Далее необходимо установить sublime text модуль markmon real-time markdown preview. Этот модуль предоставляет мост между sublime text и node js модулем markmon.

 

По умолчанию markmon использует библиотеку pandoc для конвертации markdown, чего для большинства случаев должно вполне хватать.

Лично у меня возникла небольшая проблема с использованием pandoc:

 

Видимо у pandoc более строгие требования к синтаксису чем у bitbucket'а. С одной стороны это правильно, и приучает к правильному оформлению, с другой стороны, я хочу видеть конечный результат - как документ будет выглядеть при просмотре репозитория.

 

Кастомный конвертер markdown

 

К счастью, авторы markmon не залочили свою программу на один md конвертор, а предоставили возможность указать свой через параметр command, поэтому можно подключить практически любой другой конвертер.

 

Перепробовав несколько вариантов, я остановился на реализации под ruby от авторов github'а. Для установки потребуется менеджер пакетов ruby - gem.

 

К сожалению, на прямую подружить его с markmon не удалось, поэтому я набросал простой скрипт:

require 'github/markdown'
puts GitHub::Markdown.render(ARGF.read)

 

Скрипт читает стандартный ввод (ARGF.read), конвертирует с помощью GH Markdown и печатает готовый html.

 

Теперь для подключения нужно в настройках st модуля прописать параметр command. Лезем Preferences -> Package Settings -> Markmon -> Settings - User и прописываем настройки:

{
    "command" : "ruby <ПУТЬ К СКРИПТУ>/github_md.rb"
}

 

Останавливаем markmon (ctrl + P -> Markmon exit) и запускаем его заново (ctrl + K, m). Если все сделано верно то наш markdown отобразится в окне браузера:

 

Кастомное оформление

Согласитесь, вывод в браузере не очень то привлекателен. Для кастомизации предусмотрен параметр stylesheet принимающий путь к css файлу с оформлением. Лично я, как человек ленивый, нашел уже готовый вариант оформления markdown – gist от andyferra.

 

 

{
    "command" : "ruby <ПУТЬ К СКРИПТУ>/github_md.rb",
    "stylesheet" : "<ПУТЬ К СКРИПТУ>/css/github.css"
}

 

В результате получаем довольно симпатичное превью:

Подсветка синтаксиса

Реализовать подсветку синтаксиса мне удалось далеко не сразу, т.к. все инструменты ruby, которые я пробовал работали медленнее моих ожиданий, поэтому я решил использовать для раскрашивания кода утилиту GNU Source-highlight от Lorenzo Bettini.

 

GNU Source-highlight представляет собой офигенную (как и всё что сделано в FSF) консольную утилиту принимающую исходник на стандартный ввод (по умолчанию), настройки и формат вывода, и выводящую результат в стандартный вывод.

Для использования этой утилиты из ruby кода хорошо подойдет функция popen — с помощью неё можно запустить команду как внутренний подпроцесс, с возможностью управления его стандартными вводом и выводом.

 

Перед тем как передавать код в Source-highlight, необходимо получить из md разметки блоки кода и информацию об используемом языке. Регулярное выражение (тест на rebular) дробит текст на четыре группы - открывающие апострофы, язык, текст, закрывающие апострофы. Таким образом получаем такой код:

 

md = ARGF.read

# processing ``` blocks
md.gsub! /(?<beg>[`]{3})(?:\n\#\!)?(?<lang>\w+)(?<code>((?!^[`]{3})[\s\S])*)(?<ending>[`]{3})/im do
    beg, lang, body, ending = $~.captures

    # pass body to source-highlight
    IO.popen('source-highlight -s' + lang + ' --tab=4', 'r+') do | pipe |
        pipe.puts(body.strip)
        pipe.close_write
        new_body = pipe.read()

        if new_body.empty?
            body = '<pre>' + body + '</pre>'
        else
            body = new_body
        end
    end
    
    # unwrap <tt> tag
    body.gsub! /\<tt\>(?!\<\/tt\>)*/, "\1"

    body
end

# convert to html with GitHub markdown
puts GitHub::Markdown.render(md)

 

 

Посмотрим что у нас получилось:

 

Вот таким нехитрым способом (лол) можно превратить sublime text в полноценный markdown редактор.

 

Спасибо за внимание!

Репозиторий с исходниками - здесь.