вторник, декабря 23, 2008

Все форматы документа из одного исходника: asciidoc сотоварищи

Я уже давно использую asciidoc для написания сколько-нибудь больших текстов. Почти все статьи в этом блоге, включая эту, подготовлены с помощью Asciidoc.

Asciidoc - это транслятор простейшего языка разметки текста в любой другой язык разметки. Разметка asciidoc очень простая, практически вы пишете plain text, только выделяете заголовки знаками = в начале строки, полужирный текст - *звёздочками*, курсив - 'кавычками', итд. Абзацы разделяются пустой строкой. А на выходе может быть всё что угодно, это зависит от так называемого backend-a, поведение которого описывается в конфиге. В поставке доступны бэкенды для xhtml, html4 и docbook. Docbook, в свою очередь, теоретически можно отконвертировать во что угодно.

На днях я готовил доклад для одного семинара, и мне хотелось получить его сразу в нескольких форматах: html и pdf, как минимум. И ещё бы надо к нему презентацию… И хорошо бы план доклада. И, конечно, не хочется для каждого формата готовить текст.

HTML (точнее, xhtml 1.1) делается с помощью asciidoc. Все остальные форматы, теоретически, можно получить из docbook, который можно получить с помощью asciidoc. Только вот на практике мне так и не удалось за полдня заставить ни один из конверторов docbook нормально работать с русскими буквами. Также в комплекте asciidoc есть экспериментальный бэкенд latex, но он как-то странно работает с кусками кода, которые мне нужно поместить в tex-файл в неизменном виде (речь идёт о формулах): половина формул куда-то проглатываются.

Кроме всего прочего, мне нужно в доклад включать фрагменты диалога с консольными программами (в данном случае - с maxima и с R). Так как в ходе подготовки доклада что-то может меняться, неохота каждый раз делать copy-paste из консоли. Надо бы, чтобы в исходник вставлять только запросы к программам - а вызываются программы и вставляется вывод пусть автоматически.

В общем, в итоге я написал скрипт lmaxima.py, который делает следующее: читает входной файл, и копирует его в выходной. Если встречает строку вида "program>> команды", то по пайпу передаёт эти команды указанной программе, и её ответ вставляет в выходной файл. Если встречает строку вида "program|tex>> команды" - то указанные команды оборачивает в функцию tex(). Таким образом, lmaxima.py работает как препроцессор для asciidoc. Одна из тонкостей состоит в том, как вставлять в документ формулы, которые выдаёт maxima. Если выводить надо в html, то формулы пропускаются через tex, и в выходной файл вставляется картинка (строка image:chtoto.png[]). Если же выводить надо в pdf, то lmaxima указывается ключ -i, и в выходной файл вставляется непосредственно tex-код.

Т.к. latex-бэкенд к asciidoc работает странно, пришлось писать свой конвертер из подмножества asciidoc-разметки в tex (благо, основная часть разметки asciidoc очень простая). Называется он у меня vsml.py. Заодно vsml.py умеет следующее:

  • С ключом -c - добавляет в документ оглавление (latex-овская команда \tableofcontents),

  • с ключом -p - "выдирает" из исходника только заголовки, и составляет содержание документа (план доклада, в моём случае),

  • с ключом -b - создаёт исходник для презентации (класс beamer); в презентацию попадают заголовки и картинки.

vsml понимает ещё и некоторые "надстройки" над синтаксисом asciidoc. Так, с помощью строчек "//{" и "//}" (asciidoc их воспринимает как комментарии) можно создавать вложенные куски текста. По умолчанию они выводятся как обычно, однако vsml.py можно задать ключ -l с числовым параметром, и он будет выводить только текст с "уровнем вложенности" не больше заданного; это позволяет оформлять более и менее необязательные части текста, и из одного исходника создавать документы разной степени подробности. А с помощью строчки вида "//.Тут заголовок" можно создавать (под)заголовки, которые не будут видны нигде, кроме презентации.

Конечно, вручную писать все эти команды с ключами каждый раз долго, поэтому я написал небольшой Makefile:

all: report.pdf report.html presentation.pdf plan.pdf
clean:
rm report.pdf report.html presentation.pdf
rm presentation.tex report.asciidoc report.vsml
rm plan.tex plan.pdf
plan.pdf: plan.tex
pdflatex $<
plan.tex: report.vsml
vsml.py -p < $< > $@
report.pdf: report.tex
pdflatex $<
presentation.pdf: presentation.tex
pdflatex $<
report.html: report.asciidoc
asciidoc $<
report.asciidoc: math-report
lmaxima.py $< $@
presentation.tex: report.vsml
vsml.py -b < $< > $@
report.tex: report.vsml
vsml.py < $< > $@
report.vsml: math-report
lmaxima.py -i $< $@


PS: мне тут подсказывают: добавь ещё festival, оно за тебя и доклад прочитает :)

7 комментариев:

  1. > практически вы пишете plain text, только выделяете заголовки знаками = в начале строки, полужирный текст - *звёздочками*, курсив - 'кавычками', итд
    Это же wiki-разметка о_О

    ОтветитьУдалить
  2. Да, много общего с вики-разметкой. Некоторые вещи отличаются, но в целом - из этой серии.

    ОтветитьУдалить
  3. так из LaTeX все что угодно тоже генерится... уж pdf,html и слайды точно :)

    а из R можно делать LaTeX

    ОтветитьУдалить
  4. У latex разметка всё-таки значительно сложнее, чем asciidoc :)

    >> а из R можно делать LaTeX

    нука-нука, с этого места поподробней? :)

    ОтветитьУдалить
  5. удивляете :) Sweave

    пример кушать не захотело "Ваш код HTML не может быть принят: Tag is not allowed"

    внутри R

    Sweave ( "test-Sweave.Rnw" )

    ОтветитьУдалить
  6. А, ну да :) Правда, это literate programming конкретно для R...

    ОтветитьУдалить
  7. Ну не совсем уже и "летерате" :) Скорее просто написание документов на латексе не заморачиваясь вставкой графики, R-кода и вывода ...

    вот кстате то же для maxima

    http://melusine.eu.org/syracuse/maxima/pmaxima/

    many worked examples, and a script named pMaxima which processes scripts containing text and Maxima commands into LaTeX documents. Web site maintained by Jean-Michel Sarlat

    ОтветитьУдалить