Журнал LinuxFormat - перейти на главную

LXF94:LaTeX

Материал из Linuxformat
(Различия между версиями)
Перейти к: навигация, поиск
(Создаём свои …)
м (оформление)
 
(не показаны 13 промежуточных версий 3 участников)
Строка 1: Строка 1:
 +
{{цикл/LaTeX}}
 +
 
== Начала программирования ==
 
== Начала программирования ==
 
''ЧАСТЬ 11 Завершая этот длинный цикл статей, '''Евгений Балдин''' посмотрит на LaTeX глазами профессионального программиста.''
 
''ЧАСТЬ 11 Завершая этот длинный цикл статей, '''Евгений Балдин''' посмотрит на LaTeX глазами профессионального программиста.''
Строка 9: Строка 11:
 
…команды, окружения и прочее. Возникшая в процессе набора простенькая надоедливая проблема наверняка решена, и не один раз. С другой стороны, при нарастающей квалификации бывает проще изобрести этот велосипед заново в удобной на текущий момент форме, например:
 
…команды, окружения и прочее. Возникшая в процессе набора простенькая надоедливая проблема наверняка решена, и не один раз. С другой стороны, при нарастающей квалификации бывает проще изобрести этот велосипед заново в удобной на текущий момент форме, например:
  
 +
<source lang=latex>
 
  \newcommand{\ee}{\ensuremath{e^{+}e^{-}}\xspace}
 
  \newcommand{\ee}{\ensuremath{e^{+}e^{-}}\xspace}
 +
</source>
  
 
Новые команды часто создаются для комбинаций, используемых исключительно в математическом окружении. Команда \ensuremath обеспечивает это окружение независимо от текущего режима:
 
Новые команды часто создаются для комбинаций, используемых исключительно в математическом окружении. Команда \ensuremath обеспечивает это окружение независимо от текущего режима:
Строка 15: Строка 19:
 
[[Image:Latex 11 1.jpg|right|thumb|300px|Рис. 1.]]
 
[[Image:Latex 11 1.jpg|right|thumb|300px|Рис. 1.]]
  
 +
<source lang=latex>
 
  \(J/\psi\to\ee\) является одним из подвидов \ee-рассеяния.
 
  \(J/\psi\to\ee\) является одним из подвидов \ee-рассеяния.
 +
</source>
  
 
Команда \xspace из одноимённого пакета добавляет в конце команды пробел в случае, если за ней не следует знаков препинания, то есть избавляет от необходимости самому вставлять явный пробел после команды.
 
Команда \xspace из одноимённого пакета добавляет в конце команды пробел в случае, если за ней не следует знаков препинания, то есть избавляет от необходимости самому вставлять явный пробел после команды.
Строка 21: Строка 27:
 
Имеются три основные структуры, которые позволяют создавать свои или переименовать уже имеющиеся макросы:
 
Имеются три основные структуры, которые позволяют создавать свои или переименовать уже имеющиеся макросы:
  
 +
<source lang=latex>
 
  \newcommand{«команда»}[N][«зн. по ум.»]{«определение»}
 
  \newcommand{«команда»}[N][«зн. по ум.»]{«определение»}
 
  \renewcommand{«команда»}[N][«зн. по ум.»]{«определение»}
 
  \renewcommand{«команда»}[N][«зн. по ум.»]{«определение»}
 
  \providecommand{«команда»}[N][«зн. по ум.»]{«определение»}
 
  \providecommand{«команда»}[N][«зн. по ум.»]{«определение»}
 +
</source>
  
 
\newcommand определяет новую команду. Если такая команда уже существует, то при компиляции генерируется ошибка. \renewcommand переопределяет уже существующую команду. В свою очередь, \providecommand создаёт новую команду, если на момент описания такой команды не было, и ничего не делает в противном случае.
 
\newcommand определяет новую команду. Если такая команда уже существует, то при компиляции генерируется ошибка. \renewcommand переопределяет уже существующую команду. В свою очередь, \providecommand создаёт новую команду, если на момент описания такой команды не было, и ничего не делает в противном случае.
  
В каждом из этих макросов есть два обязательных параметра: это имя команды и её описание. Если команде необходимо передать параметр/параметры, то первый необязательный аргумент (N) должен принять значение от одного (1) до девяти (9). В [[LXF85|LXF85]] (см. прилагаемый диск) обсуждался макрос для дублирования знака в формуле при переносе её на следующую строку (\(a+b\hm{=}c\)):
+
В каждом из этих макросов есть два обязательных параметра: это имя команды и её описание. Если команде необходимо передать параметр/параметры, то первый необязательный аргумент (N) должен принять значение от одного (1) до девяти (9). В [[LXF85:LaTeX|LXF85]] (см. прилагаемый диск) обсуждался макрос для дублирования знака в формуле при переносе её на следующую строку (\(a+b\hm{=}c\)):
  
 +
<source lang=latex>
 
  \newcommand*{\hm}[1]{#1\nobreak\discretionary{}%
 
  \newcommand*{\hm}[1]{#1\nobreak\discretionary{}%
 
   {\hbox{$\mathsurround=0pt #1$}}{}}
 
   {\hbox{$\mathsurround=0pt #1$}}{}}
 +
</source>
  
 
Вместо знака решётки (#) с цифрой после него при компиляции макроса подставляется соответствующий параметр. В данном случае параметр был только один, и можно сказать, что его значение сохраняется в «переменной» #1.
 
Вместо знака решётки (#) с цифрой после него при компиляции макроса подставляется соответствующий параметр. В данном случае параметр был только один, и можно сказать, что его значение сохраняется в «переменной» #1.
Строка 37: Строка 47:
  
 
Наличие второго необязательного параметра в макросах определения новых команд позволяет определить первый параметр создаваемой команды как параметр по умолчанию:
 
Наличие второго необязательного параметра в макросах определения новых команд позволяет определить первый параметр создаваемой команды как параметр по умолчанию:
 +
 +
[[Image:Latex 11 2.jpg|right|thumb|300px|Рис. 2.]]
 +
 +
<source lang=latex>
 +
\newcommand{\exmpl}[1][умолчанию]%
 +
            {<<значение по #1>>}
 +
Сравните \exmpl{} и \exmpl[требованию].
 +
</source>
 +
 +
Для определения нового окружения используется команда \newenvironment, например:
 +
 +
[[Image:Latex 11 3.jpg|right|thumb|300px|Рис. 3.]]
 +
 +
<source lang=latex>
 +
\newenvironment{outlined}{\hrule\begin{center}}%
 +
                  {\end{center}\smallskip\hrule}
 +
\begin{outlined}
 +
  Выделенный текст.
 +
\end{outlined}
 +
</source>
 +
 +
Формальное описание этой команды похоже на описание \newcommand:
 +
 +
<source lang=latex>
 +
\newenvironment{«окружение»}[N][«зн. по ум.»]%
 +
                {«код, открывающий окружение»}%
 +
                {«код, закрывающий окружение»}
 +
</source>
 +
 +
Точно так же, как и в случае \newcommand, созданному окружению можно передавать параметры. Подставлять параметры можно только
 +
в коде, открывающем окружение. Кроме создания нового окружения, можно также переопределять уже имеющиеся с помощью аналогичной
 +
команды \renewenvironment.
 +
 +
В разделе, посвящённом описанию презентационного класса beamer [[LXF91:LaTeX|(LXF85]]), упоминалось ещё об одной возможности создавать новые именованные окружения с помощью команды \newtheorem:
 +
 +
[[Image:Latex 11 4.jpg|right|thumb|300px|Рис. 4.]]
 +
 +
<source lang=latex>
 +
\newtheorem{Texmpl}{Пример}
 +
\begin{Texmpl}[Теорема Пифагора]\label{th:1}
 +
  Пифагоровы штаны во все стороны равны.
 +
\end{Texmpl}
 +
\begin{Texmpl}\label{th:2}
 +
  Мудрость ограничена, а глупость бесконечна.
 +
\end{Texmpl}
 +
Можем сослаться первую теорему:~\ref{th:1},
 +
а можно и на вторую:~\ref{th:2}
 +
</source>
 +
 +
Команда \newtheorem имеет две формы:
 +
 +
<source lang=latex>
 +
\newtheorem{«теорема»}[«существующая теорема»]{«заголовок»}
 +
\newtheorem{«теорема»}{«заголовок»}[«имя счётчика»]
 +
</source>
 +
 +
Каждая из форм имеет по два соответствующих обязательных аргумента и по одному необязательному. В первом случае это имя уже существующей теоремы, с которой следует иметь совместную нумерацию. Во втором случае в качестве необязательного параметра передаётся имя уже существующего счётчика, на основе которого строится нумерация. О том, что такое счётчики и как их определять, речь пойдёт далее.
  
 
=== Счётчики и другие переменные ===
 
=== Счётчики и другие переменные ===
 +
 +
«Другие переменные» уже обсуждались в разделе Определённые «размеры» и переменные «длины» ([[LXF89:LaTeX|LXF89]]). Операции с этими переменными выполнялись с помощью команд \newlength, \setlength и \addtolength. Аналогично, в LaTeX представлена и целочисленная арифметика с использованием счётчиков в качестве переменных:
 +
 +
[[Image:Latex 11 5.jpg|right|thumb|300px|Рис. 5.]]
 +
 +
<source lang=latex>
 +
\newcounter{MyCount}\setcounter{MyCount}{5}
 +
Значение MyCount равно \arabic{MyCount},
 +
или~\alph{MyCount}, или \Asbuk{MyCount}.\par
 +
\addtocounter{MyCount}{1550}
 +
\arabic{MyCount} эквивалентно \Roman{MyCount}.
 +
</source>
 +
 +
Новый счётчик создаётся с помощью команды \newcounter. При создании он инициализируется нулём. Создание счётчика является глобальной операцией, то есть при компиляции информация о нём не исчезнет, даже если новый счётчик был определён внутри окружения. Для присвоения счётчику другого значения используется команда \setnewcounter, а для изменения на какое-то определённое число – \addtocounter.
 +
 +
В отличие от длин, основная роль которых – помнить размеры определённого бокса, счётчики используются для отображения какой-либо структурной информации. Поэтому особое внимание уделяется представлению значения счётчика в тексте. Чтобы просто отобразить численное значение счётчика с помощью арабских цифр, используется команда \arabic{счётчик}. Для римской числовой нотации необходимо воспользоваться командой \Roman и \roman – заглавные и строчные буквы соответственно. Счётчик может быть также представлен буквой
 +
алфавита: \alph – латинская строчная, \asbuk – кириллическая строчная и \Asbuk – кириллическая заглавная.
 +
 +
В стандартных классах уже определён набор счётчиков, в которых хранятся номера страницы (счётчик page), раздела (соответственно, счётчики part, chapter, section, subsection, subsubsection и т.д.), подстрочного примечания (счётчик footnote), плавающих окружений (счётчики figure и table) и формул (equation). При создании счётчика также автоматически создаётся команда с префиксом \the перед именем счётчика. Вызов такой команды выводит значение счётчика. При выводе номера раздела, плавающего объекта, уравнения и тому подобного используются именно такого рода команды, поэтому, переопределив \the-команду, можно немного изменить стиль, например, следующая команда предписывает в дальнейшем маркировать все страницы в римском стиле:
 +
 +
<source lang=latex>
 +
\renewcommand{\thepage}{\Roman{page}}
 +
</source>
 +
 +
На базе счётчиков можно организовывать иерархические структуры, то есть можно указывать зависимости:
 +
 +
[[Image:Latex 11 6.jpg|right|thumb|300px|Рис. 6.]]
 +
 +
<source lang=latex>
 +
\newcounter{Main}\addtocounter{Main}{10}
 +
\newcounter{Dep}[Main]\addtocounter{Dep}{10}
 +
Было: \theMain.\theDep\par
 +
\stepcounter{Main}
 +
Стало: \theMain.\theDep
 +
</source>
 +
 +
При создании нового счётчика можно создать связь с уже существующим, указав имя существующего счётчика в качестве необязательного параметра. В примере выше счётчик Dep зависит от счётчика Main. Эта связь проявляется в том, что при увеличении значения базового
 +
счётчика (Main) на единицу с помощью команды \stepcounter подчинённый счётчик (Dep) обнуляется. Обычно новый счётчик устанавливают в
 +
подчинение счётчикам разделов (section).
 +
 +
Команда \refstepcounter{счётчик} отличается от \stepcounter тем, что помимо обнуления всех зависимых счётчиков, \refstepcounter опреде-
 +
ляет значение, выводимое командой ссылки \ref, как текст, создаваемый \the-командой:
 +
 +
<source lang=latex>
 +
% окружение "Задача"
 +
\newcounter{Problem}[section]
 +
\renewcommand{\theProblem}{\thesection.\arabic{Problem}}
 +
\newenvironment{Problem}[0]{%
 +
\par\refstepcounter{Problem}%
 +
\theProblem\,}%
 +
{\par}%
 +
</source>
 +
 +
Здесь определено окружение Problem и одноимённый счётчик. Счётчик Problem зависит от счётчика раздела. Вывод счётчика \theProblem переопределён как номер раздела, за которым следует уже сам счётчик. Внутри окружения счётчик Problem увеличивается на единицу с помощью команды \refstepcounter{счётчик}. Результат использования нового окружения представлен в следующем примере:
 +
 +
[[Image:Latex 11 7.jpg|right|thumb|300px|Рис. 7.]]
 +
 +
<source lang=latex>
 +
\begin{Problem}\label{ex:1}
 +
  Задача раз
 +
\end{Problem}
 +
\begin{Problem}\label{ex:2}
 +
  Задача два
 +
  \end{Problem}
 +
Ссылки на раз~\ref{ex:1} и два~\ref{ex:2}.
 +
</source>
 +
 +
При работе с переменными LaTeX также могут помочь следующие пакеты:
 +
 +
*calc Макропакет из коллекции tools для арифметических вычислений, уже упоминавшийся в разделе calc (LXF89). Этот пакет переопределяет команды типа \newcounter так, что в них можно использовать арифметические выражения, хотя и с некоторыми ограничениями. Подробности в файле calc.pdf.
 +
*ifthen Макропакет, в котором определены команды условного перехода \ifthenelse и цикла \whiledo. Подробности в файле ifthen.pdf. Также
 +
можно присмотреться к усовершенствованной версии этого пакетаxifthen.
 +
*fmtcount Представляет различные форматы (двоичный, восьмеричный, шестнадцатеричный и т.д.) отображения счётчиков (fmtcount.pdf).
 +
*multido Определяет оператор цикла \multido (multido.pdf).
 +
*tokenizer Позволяет разбивать текстовые списки на элементы (tokenizer.pdf).
 +
*totpages Даёт возможность узнать число страниц в документе и тому подобную информацию (totpages.pdf).
 +
*xkeyval Улучшенная версия пакета keyval, который позволяет передавать/принимать в качестве параметров пары значений «key=value» (xkeyval.pdf).
  
 
=== Создаём свой пакет ===
 
=== Создаём свой пакет ===
 +
 +
Предположим, что вы уже владеете искусством программирования в среде LaTeX. Чтобы распространить свои наработки, следует организовать исходные тексты в удобном для дальнейшей поддержки, передаче и установке виде. Можно и не стараться, если вас не интересует конечный результат, но знать, как правильно устроен пакет, полезно и новичку, так как эффективное обучение программированию напрямую связано с изучением уже существующего кода.
 +
 +
В LaTeX-сообществе принято распространять свои пакеты и документацию к ним в виде автономных файлов с расширением dtx (DTX-файлы). Для автоматической установки пакетов используются инструкции, записанные в файлах с расширением ins (INS-файлы). Для более подробной информации следует обратиться к инструкции «How to Package Your LaTeX Package», созданной Скотом Пакиным [Scott Pakin]. Файл dtxtut.pdf, как обычно, можно найти в стандартной поставке LaTeX или на CTAN. Вместе с документацией идут файлы примеров [c]skeleton.dtx и [c]skeleton.ins.
 +
 +
За работу с DTX-файлами отвечает пакет doc и сопутствующая ему утилита DOCSTRIP (файл docstrip.pdf). Основная идея пакета doc состоит в совмещении кода с документацией, что облегчает поддержку и развитие пакета.
  
 
==== Установочный INS-файл ====
 
==== Установочный INS-файл ====
 +
 +
Для извлечения кода и документации из DTX-пакета следует написать специальный установочный файл. Набор инструкций достаточно
 +
стереотипен:
 +
 +
<source lang=latex>
 +
%% Стандартный копирайт по выбору (рекомендуется LPPL/GPL)
 +
%%
 +
%% Первый шаг - загрузка DOCSTRIP.
 +
\input docstrip.tex
 +
%% Подробный отчёт о каждом шаге хорош только когда пакет
 +
%% отлаживается.
 +
\keepsilent
 +
%% Директория, в которую устанавливается пакет. Имя
 +
%% директории является относительным по отношению к
 +
%% базовой директории $(TEXMF).
 +
\usedir{tex/latex/{«имя пакета»}}
 +
%% Определение преамбулы, которая вставляется во все
 +
%% сгенерированные файлы. Обычно это информация об авторе
 +
%% и пожелания пользователям.
 +
\preamble
 +
  Текст преамбулы
 +
\endpreamble
 +
%% Извлечение файлов пакета из dtx. Основной шаг,
 +
%% который может повторяться несколько раз.
 +
\generate{\file{«извлекаемый файл»}{\from{«dtx-файл»}{метка}}}
 +
 +
 +
%% Информация для пользователя. Всегда что-то полезно сказать
 +
%% после установки.
 +
\obeyspaces
 +
\Msg{******************************************************
 +
**}
 +
\Msg{* Здорово, что Вы поставили этот пакет. *}
 +
\Msg{* Прочитайте документацию перед использованием! *}
 +
\Msg{******************************************************
 +
**}
 +
%% Метка конца установочного файла.
 +
\endbatchfile
 +
</source>
  
 
==== Пакетный DTX-файл ====
 
==== Пакетный DTX-файл ====
 +
 +
Пакетный DTX-файл содержит в себе и код с комментариями, и текст описания пакета. Структура DTX-файла позволяет получить печатную документацию после прогона через LaTeX. Код с комментариями тоже может стать частью документации. Это шаг по направлению к «грамотному программированию» [literate programming].
 +
 +
Наличие комментариев в коде заставляет повторять процедуру компиляции дважды. В первый раз отрабатывается LaTeX-код, а затем комментарии. Во втором случае знак % перед комментарием игнорируется, и текст комментария передаётся на вход LaTeX, если он (комментарий) не окружён командами \iffalse-\fi.
  
 
===== Пролог =====
 
===== Пролог =====
 +
 +
В начале следует, естественно, добавить информацию об авторе:
 +
 +
<source lang=latex>
 +
%\iffalse meta-comment
 +
% Этот текст не обрабатывается LaTeX’ом. Слово meta-comment
 +
%добавлено просто для удобства чтения кода человеком и
 +
%означает, что этот текст предназначен именно для него (человека).
 +
%\fi
 +
</source>
 +
 +
В ins-файле в команде \generate использовался параметр «метка». Он говорит DocStrip, что следует выбирать строки, которые следуют за
 +
комментарием и конструкцией <метка> или между тэгами <*метка> и </метка>. Далее идёт код заголовка пакета, соответствующего метке
 +
«метка»:
 +
 +
<source lang=latex>
 +
% \iffalse
 +
%<метка> \NeedsTeXFormat{LaTeX2e}
 +
%<метка> \ProvidesPackage{«имя пакета»}
 +
%<метка> [<ГГГГ>/<ММ>/<ДД> v<версия> <краткое описание>]
 +
</source>
 +
 +
Строчку «<ГГГГ>/<ММ>/<ДД> v<версия> <краткое описание>» нужно заменить на дату, версию и краткое описание, соответственно. Закончить пролог необходимо следующими словами, создающими основную документацию:
 +
 +
<source lang=latex>
 +
%<*driver>
 +
\documentclass{ltxdoc}
 +
\usepackage{«имя пакета»}
 +
\begin{document}
 +
\DocInput{«dtx-файл»}
 +
\end{document}
 +
%</driver>
 +
% \fi
 +
</source>
 +
 +
Это единственная часть, относящаяся к документации, которая не начинается со знака комментария (%).
 +
 +
В прологе можно указывать ещё некоторое количество инструкций, уточняющих формат создаваемой документации.
  
 
===== Пользовательская документация =====
 
===== Пользовательская документация =====
 +
 +
Прежде всего, следует учесть, что подавляющий объём описаний для пакетов LaTeX сделан на английском языке. Для этого есть довольно
 +
веские основания, связанные с размером англоязычной аудитории.
 +
 +
Написание документации для DTX-пакета ничем не отличается от написания обычного LaTeX-документа, за тем исключением, что не следует забывать о знаке комментария (%) в начале строки:
 +
 +
<source lang=latex>
 +
% \title{Пакет \textsf{«имя пакета»}}
 +
% \author{«Ваше имя» \\ \texttt{«Ваш e-mail»}}
 +
% \maketitle
 +
% текст документации
 +
</source>
 +
 +
К стандартным LaTeX-командам секционирования уровня paragraph добавляются \DescribeMacro{макрос} и \DescribeEnv{окружение}.
  
 
===== Код с комментариями =====
 
===== Код с комментариями =====
 +
 +
Даже если допустить, что лучшая документация для программиста – это сам код, то для нормального человека описательный текст все равно будет предпочтительнее. Проблема совмещения кода и описания является основной причиной возникновения «грамотного программирования».
 +
 +
Код обычно начинается сразу же за пользовательской документацией:
 +
 +
<source lang=latex>
 +
%\StopEventually{\PrintIndex}
 +
%% Описание окружения.
 +
%\begin{environment}{«имя окружения»}
 +
%% Аналогично, существует окружение macros, для описания
 +
%% новых команд.
 +
% \begin{macrocode}
 +
«Здесь идёт код, вида:»
 +
\newenvironment{«имя окружения»}{начало}{окончание}
 +
% \end{macrocode}
 +
%\end{environment}
 +
 +
%\Finale
 +
\endinput
 +
</source>
 +
 +
Команда \StopEventually{} отмечает начало кода и принимает в качестве параметра команду, которую следует выполнить в конце документации – например, распечатать алфавитный указатель \PrintIndex.
 +
 +
Любой код следует обрамлять с помощью окружения macrocode. Это позволит включить его в печатную документацию. Есть две особенности для этого окружения, которые следует учитывать:
 +
 +
*Между % и \begin{macrocode} должно быть ровно четыре (4) пробела. Аналогичное правило действует и для \end{macrocode},
 +
*Внутри этого окружения не должно быть текста, начинающегося с %. Внутри окружений environment и macros может быть несколько вставок кода и текста.
  
 
==== Пакетирование ====
 
==== Пакетирование ====
 +
 +
Часто LaTeX-пакеты распространяются в виде одного DTX-файла. Существует способ включить установочный INS-файл в файл пакета:
 +
 +
<source lang=latex>
 +
%<*batchfile>
 +
\begingroup
 +
 +
  «Содержание ins-файла»
 +
 +
\endgroup
 +
%</batchfile>
 +
</source>
 +
 +
Следует только убрать заключительную команду \endbatchfile, чтобы LaTeX мог скомпилировать остальное.
 +
 +
Всё. Для распространения свой пакет лучше всего поместить на CTAN. Для выгрузки следует обратиться к ресурсу http://www.ctan.org/upload. Всегда необходим краткий README с описанием. Собранная документация в виде PDF-файла также является хорошим тоном.
  
 
=== Напутствие ===
 
=== Напутствие ===
Строка 59: Строка 347:
  
 
LaTeX-цикл в Linux Format подошёл к концу. Честно говоря, я сам за это время узнал много нового для себя. Надеюсь, мне удалось поделиться этими знаниями с вами. В этой информации нет никакой чёрной магии – всё просто и логично, и эта информация полезна, так как позволяет автоматизировать одно из самых сложных ремёсел человеческой цивилизации – создание книг. Пишите тексты, большие и маленькие: они не пропадут.
 
LaTeX-цикл в Linux Format подошёл к концу. Честно говоря, я сам за это время узнал много нового для себя. Надеюсь, мне удалось поделиться этими знаниями с вами. В этой информации нет никакой чёрной магии – всё просто и логично, и эта информация полезна, так как позволяет автоматизировать одно из самых сложных ремёсел человеческой цивилизации – создание книг. Пишите тексты, большие и маленькие: они не пропадут.
 +
 +
----
 +
 +
=== Внимание! ===
 +
 +
Политика создания названий команд в TeX-подобной среде такова, что для новых пакетов необходимо придумывать новые команды. Это сделано для обеспечения абсолютной совместимости сверху вниз. К сожалению, подобная политика в случае бездумного использования слов может привести к «захватыванию» подходящих сочетаний. Примером правильного именования служит пакет listings, где вместо, казалось бы, подходящего по названию окружения listing используется lstlisting.

Текущая версия на 08:34, 16 декабря 2008

Содержание

[править] Начала программирования

ЧАСТЬ 11 Завершая этот длинный цикл статей, Евгений Балдин посмотрит на LaTeX глазами профессионального программиста.

LaTeX не просто даёт возможность набирать текст – он позволяет его программировать, а следовательно, перекладывать часть своей работы на компьютер. Привычка думать – одна из самых необычных особенностей разумного человека. Она позволяет экономить силы и время.

[править] Создаём свои …

…команды, окружения и прочее. Возникшая в процессе набора простенькая надоедливая проблема наверняка решена, и не один раз. С другой стороны, при нарастающей квалификации бывает проще изобрести этот велосипед заново в удобной на текущий момент форме, например:

 \newcommand{\ee}{\ensuremath{e^{+}e^{-}}\xspace}

Новые команды часто создаются для комбинаций, используемых исключительно в математическом окружении. Команда \ensuremath обеспечивает это окружение независимо от текущего режима:

(thumbnail)
Рис. 1.
 \(J/\psi\to\ee\) является одним из подвидов \ee-рассеяния.

Команда \xspace из одноимённого пакета добавляет в конце команды пробел в случае, если за ней не следует знаков препинания, то есть избавляет от необходимости самому вставлять явный пробел после команды.

Имеются три основные структуры, которые позволяют создавать свои или переименовать уже имеющиеся макросы:

 \newcommand{«команда»}[N][«зн. по ум.»]{«определение»}
 \renewcommand{«команда»}[N][«зн. по ум.»]{«определение»}
 \providecommand{«команда»}[N][«зн. по ум.»]{«определение»}

\newcommand определяет новую команду. Если такая команда уже существует, то при компиляции генерируется ошибка. \renewcommand переопределяет уже существующую команду. В свою очередь, \providecommand создаёт новую команду, если на момент описания такой команды не было, и ничего не делает в противном случае.

В каждом из этих макросов есть два обязательных параметра: это имя команды и её описание. Если команде необходимо передать параметр/параметры, то первый необязательный аргумент (N) должен принять значение от одного (1) до девяти (9). В LXF85 (см. прилагаемый диск) обсуждался макрос для дублирования знака в формуле при переносе её на следующую строку (\(a+b\hm{=}c\)):

 \newcommand*{\hm}[1]{#1\nobreak\discretionary{}%
  {\hbox{$\mathsurround=0pt #1$}}{}}

Вместо знака решётки (#) с цифрой после него при компиляции макроса подставляется соответствующий параметр. В данном случае параметр был только один, и можно сказать, что его значение сохраняется в «переменной» #1.

Звёздочка (*) в конце макроса \newcommand налагает на передаваемый параметр команды \hm дополнительное условие: в нем не должно быть пустых строк и команды \par. В некоторых случаях это упрощает отладку кода.

Наличие второго необязательного параметра в макросах определения новых команд позволяет определить первый параметр создаваемой команды как параметр по умолчанию:

(thumbnail)
Рис. 2.
 \newcommand{\exmpl}[1][умолчанию]%
            {<<значение по #1>>}
 Сравните \exmpl{} и \exmpl[требованию].

Для определения нового окружения используется команда \newenvironment, например:

(thumbnail)
Рис. 3.
 \newenvironment{outlined}{\hrule\begin{center}}%
                  {\end{center}\smallskip\hrule}
 \begin{outlined}
   Выделенный текст.
 \end{outlined}

Формальное описание этой команды похоже на описание \newcommand:

 \newenvironment{«окружение»}[N][«зн. по ум.»]%
                 {«код, открывающий окружение»}%
                 {«код, закрывающий окружение»}

Точно так же, как и в случае \newcommand, созданному окружению можно передавать параметры. Подставлять параметры можно только в коде, открывающем окружение. Кроме создания нового окружения, можно также переопределять уже имеющиеся с помощью аналогичной команды \renewenvironment.

В разделе, посвящённом описанию презентационного класса beamer (LXF85), упоминалось ещё об одной возможности создавать новые именованные окружения с помощью команды \newtheorem:

(thumbnail)
Рис. 4.
 \newtheorem{Texmpl}{Пример}
 \begin{Texmpl}[Теорема Пифагора]\label{th:1}
   Пифагоровы штаны во все стороны равны.
 \end{Texmpl}
 \begin{Texmpl}\label{th:2}
   Мудрость ограничена, а глупость бесконечна.
 \end{Texmpl}
 Можем сослаться первую теорему:~\ref{th:1},
 а можно и на вторую:~\ref{th:2}

Команда \newtheorem имеет две формы:

 \newtheorem{«теорема»}[«существующая теорема»]{«заголовок»}
 \newtheorem{«теорема»}{«заголовок»}[«имя счётчика»]

Каждая из форм имеет по два соответствующих обязательных аргумента и по одному необязательному. В первом случае это имя уже существующей теоремы, с которой следует иметь совместную нумерацию. Во втором случае в качестве необязательного параметра передаётся имя уже существующего счётчика, на основе которого строится нумерация. О том, что такое счётчики и как их определять, речь пойдёт далее.

[править] Счётчики и другие переменные

«Другие переменные» уже обсуждались в разделе Определённые «размеры» и переменные «длины» (LXF89). Операции с этими переменными выполнялись с помощью команд \newlength, \setlength и \addtolength. Аналогично, в LaTeX представлена и целочисленная арифметика с использованием счётчиков в качестве переменных:

(thumbnail)
Рис. 5.
 \newcounter{MyCount}\setcounter{MyCount}{5}
 Значение MyCount равно \arabic{MyCount},
 или~\alph{MyCount}, или \Asbuk{MyCount}.\par
 \addtocounter{MyCount}{1550}
 \arabic{MyCount} эквивалентно \Roman{MyCount}.

Новый счётчик создаётся с помощью команды \newcounter. При создании он инициализируется нулём. Создание счётчика является глобальной операцией, то есть при компиляции информация о нём не исчезнет, даже если новый счётчик был определён внутри окружения. Для присвоения счётчику другого значения используется команда \setnewcounter, а для изменения на какое-то определённое число – \addtocounter.

В отличие от длин, основная роль которых – помнить размеры определённого бокса, счётчики используются для отображения какой-либо структурной информации. Поэтому особое внимание уделяется представлению значения счётчика в тексте. Чтобы просто отобразить численное значение счётчика с помощью арабских цифр, используется команда \arabic{счётчик}. Для римской числовой нотации необходимо воспользоваться командой \Roman и \roman – заглавные и строчные буквы соответственно. Счётчик может быть также представлен буквой алфавита: \alph – латинская строчная, \asbuk – кириллическая строчная и \Asbuk – кириллическая заглавная.

В стандартных классах уже определён набор счётчиков, в которых хранятся номера страницы (счётчик page), раздела (соответственно, счётчики part, chapter, section, subsection, subsubsection и т.д.), подстрочного примечания (счётчик footnote), плавающих окружений (счётчики figure и table) и формул (equation). При создании счётчика также автоматически создаётся команда с префиксом \the перед именем счётчика. Вызов такой команды выводит значение счётчика. При выводе номера раздела, плавающего объекта, уравнения и тому подобного используются именно такого рода команды, поэтому, переопределив \the-команду, можно немного изменить стиль, например, следующая команда предписывает в дальнейшем маркировать все страницы в римском стиле:

 \renewcommand{\thepage}{\Roman{page}}

На базе счётчиков можно организовывать иерархические структуры, то есть можно указывать зависимости:

(thumbnail)
Рис. 6.
 \newcounter{Main}\addtocounter{Main}{10}
 \newcounter{Dep}[Main]\addtocounter{Dep}{10}
 Было: \theMain.\theDep\par
 \stepcounter{Main}
 Стало: \theMain.\theDep

При создании нового счётчика можно создать связь с уже существующим, указав имя существующего счётчика в качестве необязательного параметра. В примере выше счётчик Dep зависит от счётчика Main. Эта связь проявляется в том, что при увеличении значения базового счётчика (Main) на единицу с помощью команды \stepcounter подчинённый счётчик (Dep) обнуляется. Обычно новый счётчик устанавливают в подчинение счётчикам разделов (section).

Команда \refstepcounter{счётчик} отличается от \stepcounter тем, что помимо обнуления всех зависимых счётчиков, \refstepcounter опреде- ляет значение, выводимое командой ссылки \ref, как текст, создаваемый \the-командой:

 % окружение "Задача"
 \newcounter{Problem}[section]
 \renewcommand{\theProblem}{\thesection.\arabic{Problem}}
 \newenvironment{Problem}[0]{%
 \par\refstepcounter{Problem}%
 \theProblem\,}%
 {\par}%

Здесь определено окружение Problem и одноимённый счётчик. Счётчик Problem зависит от счётчика раздела. Вывод счётчика \theProblem переопределён как номер раздела, за которым следует уже сам счётчик. Внутри окружения счётчик Problem увеличивается на единицу с помощью команды \refstepcounter{счётчик}. Результат использования нового окружения представлен в следующем примере:

(thumbnail)
Рис. 7.
 \begin{Problem}\label{ex:1}
   Задача раз
 \end{Problem}
 \begin{Problem}\label{ex:2}
   Задача два
  \end{Problem}
 Ссылки на раз~\ref{ex:1} и два~\ref{ex:2}.

При работе с переменными LaTeX также могут помочь следующие пакеты:

  • calc Макропакет из коллекции tools для арифметических вычислений, уже упоминавшийся в разделе calc (LXF89). Этот пакет переопределяет команды типа \newcounter так, что в них можно использовать арифметические выражения, хотя и с некоторыми ограничениями. Подробности в файле calc.pdf.
  • ifthen Макропакет, в котором определены команды условного перехода \ifthenelse и цикла \whiledo. Подробности в файле ifthen.pdf. Также

можно присмотреться к усовершенствованной версии этого пакетаxifthen.

  • fmtcount Представляет различные форматы (двоичный, восьмеричный, шестнадцатеричный и т.д.) отображения счётчиков (fmtcount.pdf).
  • multido Определяет оператор цикла \multido (multido.pdf).
  • tokenizer Позволяет разбивать текстовые списки на элементы (tokenizer.pdf).
  • totpages Даёт возможность узнать число страниц в документе и тому подобную информацию (totpages.pdf).
  • xkeyval Улучшенная версия пакета keyval, который позволяет передавать/принимать в качестве параметров пары значений «key=value» (xkeyval.pdf).

[править] Создаём свой пакет

Предположим, что вы уже владеете искусством программирования в среде LaTeX. Чтобы распространить свои наработки, следует организовать исходные тексты в удобном для дальнейшей поддержки, передаче и установке виде. Можно и не стараться, если вас не интересует конечный результат, но знать, как правильно устроен пакет, полезно и новичку, так как эффективное обучение программированию напрямую связано с изучением уже существующего кода.

В LaTeX-сообществе принято распространять свои пакеты и документацию к ним в виде автономных файлов с расширением dtx (DTX-файлы). Для автоматической установки пакетов используются инструкции, записанные в файлах с расширением ins (INS-файлы). Для более подробной информации следует обратиться к инструкции «How to Package Your LaTeX Package», созданной Скотом Пакиным [Scott Pakin]. Файл dtxtut.pdf, как обычно, можно найти в стандартной поставке LaTeX или на CTAN. Вместе с документацией идут файлы примеров [c]skeleton.dtx и [c]skeleton.ins.

За работу с DTX-файлами отвечает пакет doc и сопутствующая ему утилита DOCSTRIP (файл docstrip.pdf). Основная идея пакета doc состоит в совмещении кода с документацией, что облегчает поддержку и развитие пакета.

[править] Установочный INS-файл

Для извлечения кода и документации из DTX-пакета следует написать специальный установочный файл. Набор инструкций достаточно стереотипен:

 %% Стандартный копирайт по выбору (рекомендуется LPPL/GPL)
 %%
 %% Первый шаг - загрузка DOCSTRIP.
 \input docstrip.tex
 %% Подробный отчёт о каждом шаге хорош только когда пакет
 %% отлаживается.
 \keepsilent
 %% Директория, в которую устанавливается пакет. Имя
 %% директории является относительным по отношению к
 %% базовой директории $(TEXMF).
 \usedir{tex/latex/{«имя пакета»}}
 %% Определение преамбулы, которая вставляется во все
 %% сгенерированные файлы. Обычно это информация об авторе
 %% и пожелания пользователям.
 \preamble
  Текст преамбулы
 \endpreamble
 %% Извлечение файлов пакета из dtx. Основной шаг,
 %% который может повторяться несколько раз.
 \generate{\file{«извлекаемый файл»}{\from{«dtx-файл»}{метка}}}
 …
 …
 %% Информация для пользователя. Всегда что-то полезно сказать
 %% после установки.
 \obeyspaces
 \Msg{******************************************************
 **}
 \Msg{* Здорово, что Вы поставили этот пакет. *}
 \Msg{* Прочитайте документацию перед использованием! *}
 \Msg{******************************************************
 **}
 %% Метка конца установочного файла.
 \endbatchfile

[править] Пакетный DTX-файл

Пакетный DTX-файл содержит в себе и код с комментариями, и текст описания пакета. Структура DTX-файла позволяет получить печатную документацию после прогона через LaTeX. Код с комментариями тоже может стать частью документации. Это шаг по направлению к «грамотному программированию» [literate programming].

Наличие комментариев в коде заставляет повторять процедуру компиляции дважды. В первый раз отрабатывается LaTeX-код, а затем комментарии. Во втором случае знак % перед комментарием игнорируется, и текст комментария передаётся на вход LaTeX, если он (комментарий) не окружён командами \iffalse-\fi.

[править] Пролог

В начале следует, естественно, добавить информацию об авторе:

 %\iffalse meta-comment
 % Этот текст не обрабатывается LaTeX’ом. Слово meta-comment
 %добавлено просто для удобства чтения кода человеком и
 %означает, что этот текст предназначен именно для него (человека).
 %\fi

В ins-файле в команде \generate использовался параметр «метка». Он говорит DocStrip, что следует выбирать строки, которые следуют за комментарием и конструкцией <метка> или между тэгами <*метка> и </метка>. Далее идёт код заголовка пакета, соответствующего метке «метка»:

 % \iffalse
 %<метка> \NeedsTeXFormat{LaTeX2e}
 %<метка> \ProvidesPackage{«имя пакета»}
 %<метка> [<ГГГГ>/<ММ>/<ДД> v<версия> <краткое описание>]

Строчку «<ГГГГ>/<ММ>/<ДД> v<версия> <краткое описание>» нужно заменить на дату, версию и краткое описание, соответственно. Закончить пролог необходимо следующими словами, создающими основную документацию:

 %<*driver>
 \documentclass{ltxdoc}
 \usepackage{«имя пакета»}
 \begin{document}
 \DocInput{«dtx-файл»}
 \end{document}
 %</driver>
 % \fi

Это единственная часть, относящаяся к документации, которая не начинается со знака комментария (%).

В прологе можно указывать ещё некоторое количество инструкций, уточняющих формат создаваемой документации.

[править] Пользовательская документация

Прежде всего, следует учесть, что подавляющий объём описаний для пакетов LaTeX сделан на английском языке. Для этого есть довольно веские основания, связанные с размером англоязычной аудитории.

Написание документации для DTX-пакета ничем не отличается от написания обычного LaTeX-документа, за тем исключением, что не следует забывать о знаке комментария (%) в начале строки:

 % \title{Пакет \textsf{«имя пакета»}}
 % \author{«Ваше имя» \\ \texttt{«Ваш e-mail»}}
 % \maketitle
 % текст документации

К стандартным LaTeX-командам секционирования уровня paragraph добавляются \DescribeMacro{макрос} и \DescribeEnv{окружение}.

[править] Код с комментариями

Даже если допустить, что лучшая документация для программиста – это сам код, то для нормального человека описательный текст все равно будет предпочтительнее. Проблема совмещения кода и описания является основной причиной возникновения «грамотного программирования».

Код обычно начинается сразу же за пользовательской документацией:

 %\StopEventually{\PrintIndex}
 %% Описание окружения.
 %\begin{environment}{«имя окружения»}
 %% Аналогично, существует окружение macros, для описания
 %% новых команд.
 % \begin{macrocode}
 «Здесь идёт код, вида:»
 \newenvironment{«имя окружения»}{начало}{окончание}
 % \end{macrocode}
 %\end{environment}%\Finale
 \endinput

Команда \StopEventually{} отмечает начало кода и принимает в качестве параметра команду, которую следует выполнить в конце документации – например, распечатать алфавитный указатель \PrintIndex.

Любой код следует обрамлять с помощью окружения macrocode. Это позволит включить его в печатную документацию. Есть две особенности для этого окружения, которые следует учитывать:

  • Между % и \begin{macrocode} должно быть ровно четыре (4) пробела. Аналогичное правило действует и для \end{macrocode},
  • Внутри этого окружения не должно быть текста, начинающегося с %. Внутри окружений environment и macros может быть несколько вставок кода и текста.

[править] Пакетирование

Часто LaTeX-пакеты распространяются в виде одного DTX-файла. Существует способ включить установочный INS-файл в файл пакета:

 %<*batchfile>
 \begingroup
 
  «Содержание ins-файла»
 
 \endgroup
 %</batchfile>

Следует только убрать заключительную команду \endbatchfile, чтобы LaTeX мог скомпилировать остальное.

Всё. Для распространения свой пакет лучше всего поместить на CTAN. Для выгрузки следует обратиться к ресурсу http://www.ctan.org/upload. Всегда необходим краткий README с описанием. Собранная документация в виде PDF-файла также является хорошим тоном.

[править] Напутствие

Документируйте каждый шаг. Пишите как можно больше качественного текста, так как его мало не бывает. Живучесть программы определяется не только кодом, но и описанием. «Светлое будущее» за грамотным программированием.

LaTeX-цикл в Linux Format подошёл к концу. Честно говоря, я сам за это время узнал много нового для себя. Надеюсь, мне удалось поделиться этими знаниями с вами. В этой информации нет никакой чёрной магии – всё просто и логично, и эта информация полезна, так как позволяет автоматизировать одно из самых сложных ремёсел человеческой цивилизации – создание книг. Пишите тексты, большие и маленькие: они не пропадут.


[править] Внимание!

Политика создания названий команд в TeX-подобной среде такова, что для новых пакетов необходимо придумывать новые команды. Это сделано для обеспечения абсолютной совместимости сверху вниз. К сожалению, подобная политика в случае бездумного использования слов может привести к «захватыванию» подходящих сочетаний. Примером правильного именования служит пакет listings, где вместо, казалось бы, подходящего по названию окружения listing используется lstlisting.

Персональные инструменты
купить
подписаться
Яндекс.Метрика