Рабочее окружение: LaTeX+Mercurial+SCons ∞
Думаю ни для кого не является секретом, что LaTeX - стандарт формата исходного текста статей по физико-математическим дисциплинам. При написании статей я использую некоторые технические приемы, которые позволяют немного упорядочить процесс работы над статьей. Я расскажу о них в порядке их "внедрения" в своё рабочее окружение. Что характерно, используемые инструменты написаны на Python ;-)
Расположение файлов
Это первое, что я сделал: разделил контент и управляющие конструкции. Для типичной статьи это выглядит примерно так:
- defs.tex - файл с новыми командами, переопределениями, подключениями пакетов
- _draft.tex - файл-обертка для черновика
- final.tex - файл-обертка для конечного варианта
- article.tex - содержимое
Зачем нужны _draft и final: бывает так, что статьи пишутся для конкретного журнала и тогда стилевой файл известен изначально; бывает так что журнал определяется в процессе дописывания статьи и стилевой файл или требования по оформлению становятся известны в последний момент. Разделение контента и стилей/служебных конструкций позволяет, имея одно и то же содержимое, на первых этапах не беспокоиться за оформление, а на поздних этапах - без особых затрат видеть как материал будет выглядеть в журнале.
Для пояснения я приведу пример с содержимым.
defs.tex - файл со служебными данными:
%% defs.tex --- файл со служебными данными
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[russian,english]{babel}
\usepackage{floatflt}
\usepackage{longtable}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{cite}
\usepackage{graphicx}
\usepackage{eucal}
\renewcommand{\thesection}{\arabic{section}}
\renewcommand{\thefigure}{\thesection.\arabic{figure}}
\renewcommand{\theequation}{\arabic{section}.\arabic{equation}}
\renewcommand{\d}{\partial}
_draft.tex - файл-обертка для черновика:
%% _draft.tex --- файл-обертка для черновика
\documentclass[a4paper]{article}
\include{defs} % вставляем содержимое служебных инструкций из defs.tex
\usepackage{fancyhdr}
\pagestyle{fancy}
\rhead{}
\lhead{}
\rfoot{\scriptsize{Черновик}} % в нижнем колонтитуле слева "Черновик"
\begin{document}
\include{article} % вставляем содержимое статьи
\end{document}
final.tex - файл-обертка для конечного варианта:
%% final.tex --- файл-обертка для конечного варианта
\documentclass[12pt,a4paper]{article}
\include{defs} % вставляем содержимое служебных инструкций из defs.tex
\textwidth=165mm
\textheight=240mm
\oddsidemargin=3mm
\evensidemargin=3mm
\topmargin=0cm
\headheight=0mm
\headsep=0mm
\renewcommand{\baselinestretch}{1.2} % интерлиньяж
\frenchspacing
\begin{document}
\include{article} % вставляем содержимое статьи
\end{document}
И содержимое статьи:
%% article.tex --- статья
% Сгенерирована Яндекс.Рефератами
\section{Изобарический определитель системы линейных уравнений: основные моменты}
Вещество необходимо и достаточно. Плазменное образование, если рассматривать
процессы в рамках специальной теории относительности, стохастично
концентрирует лептон, в итоге приходим к логическому противоречию.
Если предварительно подвергнуть объекты длительному вакуумированию,
плазма однородно возбуждает неопровержимый резонатор так, как это могло
бы происходить в полупроводнике с широкой запрещенной зоной.
Гомогенная среда перманентно нейтрализует барионный магнит даже в случае
сильных локальных возмущений среды. Уравнение в частных производных
стабилизирует изоморфный фонон в полном соответствии с законом сохранения
энергии. Расслоение, даже при наличии сильных аттракторов,
в принципе специфицирует погранслой, что неудивительно.
Абсолютно сходящийся ряд позитивно тормозит неопровержимый сверхпроводник
в том случае, когда процессы переизлучения спонтанны. Лемма оправдывает
действительный неопределенный интеграл независимо от расстояния до горизонта
событий. Метод последовательных приближений последовательно отталкивает
вихрь в том случае, когда процессы переизлучения спонтанны. Относительная
погрешность, в первом приближении, заряжает абсолютно сходящийся ряд,
даже если пока мы не можем наблюсти это непосредственно. Контрпример
стремительно масштабирует скачок функции даже в случае сильных локальных
возмущений среды. Линейное программирование возбуждает интеграл от функции,
обращающейся в бесконечность вдоль линии в полном соответствии с законом
сохранения энергии.
Интересно отметить, что взрыв концентрирует квазар, и это неудивительно,
если вспомнить квантовый характер явления. Алгебра заряжает расширяющийся
объект почти так же, как в резонаторе газового лазера. По сути, экситон
традиционно отражает линейно зависимый полином, что и требовалось доказать.
Однако не все знают, что кристаллическая решетка оправдывает разрыв, даже
если пока мы не можем наблюсти это непосредственно.
При таком расположении файлов, для "компиляции" нужно запускать _draft.tex
либо final.tex, с article.tex ничего не получится - нет
необходимых LaTeX'у инструкций о типе документа.
Mercurial
Тут всё легко и просто: всё лежит в hg-репозитории. До Mercurial я использовал Subversion, это не принципиально. В общем, всё равно в какой именно VCS вы будете хранить содержимое, главное чтобы хранили :-). Это не раз меня спасало в различных ситуациях. Про Mercurial на русском очень хорошо написал Александр Соловьев, рекомендую.
SCons
SCons я стал использовать недавно, но результат мне нравится. SCons - это инструмент сборки, по типу Make. Что мне понравилось в SCons: он из коробки умеет правильно работать с .tex (знает как их "компилировать" и знает, что .aux, .log и т.д. - мусор), и у него более вменяемый синтаксис, чем у Make.
Для нашей текущей статьи Sconstruct выглядит примерно так:
DEFAULT_TARGET = '_draft.dvi'
DRAFT = '_draft'
FINAL = 'final'
env = Environment()
env.Alias('draft', DRAFT+'.dvi')
env.Alias('final', FINAL+'.dvi')
common_texs = ['defs.tex', 'article.tex']
draft_dvi = env.DVI(DRAFT+'.dvi', DRAFT+'.tex')
Depends(draft_dvi, common_texs)
final_dvi = env.DVI(FINAL+'.dvi', FINAL+'.tex')
Depends(final_dvi, common_texs)
Default(DEFAULT_TARGET)
Сам SCons достаточно навороченный инструмент, но я его использую по-простому,
без изысков. Здесь объявление альясов (чтобы использовать scons draft вместо
scons _draft.dvi), указание двух целей: draft_dvi, final_dvi - и их зависимости,
определение цели по умолчанию.
Для частных случаев нюансы могут различаться (к примеру, в _draft и final подключены разные наборы исходных файлов), но в целом, я использую такой Sconstruct как шаблон.
Теперь "компиляция" черновика выглядит так: scons, а конечного варианта
scons final. Очистка директории от мусора, соответственно scons -c и
scons -c final. Рабочий пример можете посмотреть в sandbox.
Бонус: tiprev keyword
В добавок расскажу про совсем свежую штуку. Давно я хотел, чтобы вместо
"Черновик" в нижнем колонтитуле писалось "Черновик, ревизия N", тогда
разбираться в ворохе распечатанных версий было бы проще. Большинство
VCS (по крайней мере, Subversion и Mercurial это могут, CVS тоже) умеют
вставлять в файл номер последней ревизии, в которой файл был изменен.
Делается это при помощи ключевых слов (keuwords), что-то вроде $Id$ или $Rev$.
Но тут поджидает небольшое разочарование: основной контент находится в
article.tex, а конструкция, задающая колонтитул - в _draft.tex. Естественно,
в этом случае $Rev$ будет показывать ревизию последнего изменения _draft.tex,
а нам нужно, чтобы он показывал последнюю ревизию репозитория. И вот для
такого нет встроенных средств. Так что мне пришлось
манкипатчить соответствующий
плагин Keywords, чтобы вместо $tiprev$ подставлялась последняя ревизия
репо. Сам манкипатч
можно посмотреть в sandbox.
Использование банально -- нужно в hgrc перед включением плагина keywords включить
мой "плагин":
[extensions]
tiprev_keyword = /path/to/tiprev_keyword.py
hgext.keyword =
[keyword]
**.tex =
[keywordmaps]
tiprev = {tiprev}
rev = {rev}
После этого можно переписывать в _draft.tex колонтитул на
\rfoot{\scriptsize{Черновик, $tiprev$}}
Последний бонус немного "не доточен", в том плане что он реагирует
на название ключевого слова, а не на его значение (в плагине keywords
каждое ключевое слово раскрывается стандартными шаблонами,
например $Revision$ -- это {node|short}), но связываться с шаблонами
мне не особо хотелось, тем более ключевые слова в шаблонах ({node}, {author} и т.д.)
захардкодены так, что не подберешься.
В общем, не особо изящно, зато работает.
В качестве заключения пара ссылок по теме:
