Pull to refresh

Создание своих сложных стилей для LaTeX

Reading time6 min
Views17K

История вопроса


Если вы регулярно создаёте в ТеХ'е единообразные документы, то создание своего стиля может заметно ускорить работу.

Моими регулярными документами является создание листочков с задачами для школьников. Готовые они выглядят следующим образом: PNG или PDF (а также так, так или так)
Практически всё оформление здесь (а также отдельная табличка для результатов) создаётся автоматически.
(если это кому-то нужно, то могу выдать пакет с документацией и примерами использования)

Разными «трюками» при создании своего стиля я бы и хотел поделиться.
Если вы совсем не в теме про создание своих команд, то лучше всего почитать Львовского или чего-нибудь в этом духе.


Команды с русскими буквами (а также как использовать русский в формулах и как добавить русский в pdf)



Часто удобно создать команду, состоящую из русских букв. Чтобы, например, писать
Кривая называется \выд огибающей, если ...


Барьером для создания таких команд является то, что ТеХ по умолчанию считает русские буквы не вполне буквами (у них неправильный catcode (см. Кнута)).
Чтобы объяснить ТеХу своё желание, нужно выполнить либо большое, но понятное

\catcode156=11\catcode201=11\catcode212=11\catcode223=11\catcode234=11\catcode245=11
\catcode188=11\catcode202=11\catcode213=11\catcode224=11\catcode235=11\catcode246=11
\catcode192=11\catcode203=11\catcode214=11\catcode225=11\catcode236=11\catcode247=11
\catcode193=11\catcode204=11\catcode215=11\catcode226=11\catcode237=11\catcode248=11
\catcode194=11\catcode205=11\catcode216=11\catcode227=11\catcode238=11\catcode249=11
\catcode195=11\catcode206=11\catcode217=11\catcode228=11\catcode239=11\catcode250=11
\catcode196=11\catcode207=11\catcode218=11\catcode229=11\catcode240=11\catcode251=11
\catcode197=11\catcode208=11\catcode219=11\catcode230=11\catcode241=11\catcode252=11
\catcode198=11\catcode209=11\catcode220=11\catcode231=11\catcode242=11\catcode253=11
\catcode199=11\catcode210=11\catcode221=11\catcode232=11\catcode243=11\catcode254=11
\catcode200=11\catcode211=11\catcode222=11\catcode233=11\catcode244=11\catcode255=11

либо более компактное, но не вполне очевидное (взято из стиля russlh.sty)
\def\reserved@a#1#2{\@tempcnta#1\relax\@tempcntb#2\relax\reserved@b}
\def\reserved@b{\ifnum\@tempcnta>\@tempcntb\else\reserved@c\@tempcnta\advance\@tempcnta\@ne\expandafter\reserved@b\fi}
\def\reserved@c#1{\catcode#1=11\relax}
\reserved@a{192}{223} % А-Я
\reserved@a{224}{255} % а-я
\catcode156=11 % Ё
\catcode188=11 % ё


После этого проблемы с русскими буквами в командах исчезнут.

Русский язык и формулы

Если захочется использовать русские буквы в качестве русских букв в формулах, то спасёт пакет mathtext.

Русский язык и PDF

Если захочется получить нормальные русские буквы при поиске в готовых pdf, то поможет пакет cmap. Впрочем, есть ещё лучшее решение: можно проинклюдить файл glyphtounicode.tex с unicod-кодами значительной части символов, тогда в готовом pdf можно будет искать (и копи-пастить) греческие буквы и многие математические значки.

Сложные параметры у окружений и стилей (а также как ставить произвольный кегль и интерлиньяж)



Как сделать своё окружения или свой стиль так, чтобы в параметрах можно было указать:
[Par1=Value1, Par2=Value2, dump]
?

Это было бы очень удобно в многих случаях.

Ответ даёт пакет keyval.sty.

Что делать

Сначала мы подключаем стиль:
\usepackage{keyval}


Затем мы определяем то, как обрабатывать ключи:

\define@key
{Имя группы ключей}
{имя конкретного ключа}
[значение по умолчанию]  (если значение не передано, а также если его значение просто не нужно)
{как обрабатывать значение}


Теперь мы вызываем команду, которая распарсит текст, для каждой правильной переменной выполнит то, что было написано в соответствующем \define@key

\setkeys
{Имя группы ключей}
{параметры, которые нужно распарсить}


Пример для окружения


Итак, мы, например, хотим создать окружения, внутри которого промежутки между строками указываются явно, а также выбирается кегль шрифта. (Спасибо Яндекс.Рефератам за предоставленный текст)

Код:

\documentclass[12pt]{article}
\usepackage[textwidth=5cm]{geometry}
\usepackage[T2A]{fontenc}
\usepackage[cp1251]{inputenc}
\usepackage[russian]{babel}
\usepackage{keyval}
\sloppy


\makeatletter
\newlength{\wid} % переменная --- ширина блока
\newtoks{\fnt} % переменная --- кегль шрифта
\newlength{\skp} % переменная --- промежутки между строками

\define@key{key}{font}[12]{\fnt={#1}}
% определяем ключ font, значение пишем в переменную (если значение не передано, то 12)
\define@key{key}{skip}{\skp=#1}
\define@key{key}{width}{\wid=#1}

\newenvironment{test}[1]%
% определяем окружение с одним параметром
{\setkeys{key}{#1}%
% парсим параметры
\begin{minipage}{\wid}
% начинаем блок указанной ширины
\fontsize{\the\fnt}{\skp}\selectfont
% устанавливаем шрифт нужного кегля и интерлиньяжа
}%
{\par\end{minipage}}
% заканчиваем блок
\makeatother
% @ снова становится командным

\begin{document}

\begin{test}{font=6,skip=14pt,width=5cm}
Бесконечно малая величина отрицательна. Связное множество, следовательно, стремительно усиливает определитель системы линейных уравнений, что неудивительно. Интеграл Дирихле, конечно, привлекает возрастающий лист Мёбиуса, явно демонстрируя всю чушь вышесказанного. Достаточное условие сходимости монотонно.
\end{test}

\bigskip

\begin{test}{width=7cm,skip=13pt,font}
Бесконечно малая величина отрицательна. Связное множество, следовательно, стремительно усиливает определитель системы линейных уравнений, что неудивительно. Интеграл Дирихле, конечно, привлекает возрастающий лист Мёбиуса, явно демонстрируя всю чушь вышесказанного. Достаточное условие сходимости монотонно.
\end{test}


\end{document}

Результат:
image

(про \fontsize и \selectfont читаем в Кнуте или у Львовского)

Сложные параметры у стиля

Теперь более сложная задача, сделать так, чтобы такие параметры были у стиля.
Для решения задачи пришлось изучить, как устроен стиль geometry.sty.

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

Пример (а также как заставить команду mag работать правильно с полями документа)


test.sty


\ProvidesPackage{test.sty}
\RequirePackage[T2A]{fontenc}
\RequirePackage[cp1251]{inputenc}
\RequirePackage[russian]{babel}
\RequirePackage{keyval}

% Как и в прошлый раз, определяем как обрабатывать ключи
\define@key{key}{mag}{\mag#1}

%этот код, собственно, парсит входные параметры стиля
\let\@tempa\@empty%
\edef\@tempa{\@ptionlist{\@currname.\@currext}}%
\@for\CurrentOption:=\@classoptionslist\do{%
  \@ifundefined{KV@#2@\CurrentOption}{}{\edef\@tempa{\@tempa,\CurrentOption,}}}%
\edef\@tempa{\noexpand\setkeys{key}{\@tempa}}%
\@tempa%
\AtEndOfPackage{\let\@unprocessedoptions\relax}%

% А это для того, чтобы поля не поехали ни в dvi, ни в pdf.
% Дело в том, что dvi и pdf иногда используют свои переменные, 
% причём некоторые измеряются в масштабируемых единицах (без true), а некоторые --- наоборот. 
% Из-за этого всё ползёт.
\global\setlength\paperheight  {297truemm}%
\global\setlength\paperwidth   {210truemm}%
\global\setlength\pdfpageheight{297truemm}%
\global\setlength\pdfpagewidth {210truemm}%
\global\setlength\textheight   {260truemm}%
\global\setlength\textwidth    {180truemm}%
\global\setlength\hoffset      {-1truein}%
\global\setlength\voffset      {-1truein}%
\global\setlength\pdfhorigin   {1truein}%
\global\setlength\pdfvorigin   {1truein}%
\global\setlength\oddsidemargin{15truemm}%
\global\setlength\topmargin    {5truemm}%
\global\setlength\leftskip     {0truemm}%
\global\setlength\rightskip    {0truemm}%

test.tex


\documentclass[12pt]{article}
\usepackage[mag=2000]{test}

\begin{document}

Вуаля!

\end{document}

(команда mag, которая позволяет произвольно масштабировать документ очень хороша. Но её нужно вызывать как можно раньше. С ней возникает много глюков: например на 1cm или на 1in масштабирование влияет, а на 1truecm или 1truein — нет. Поэтому во всех полях нужно использовать true-единицы, а во всех остальных местах — обычные. Из-за этого пакет geometry с mag плохо работает. Кроме того, для размеров страниц (и сдвигов) в pdf и dvi используются разные величины (например, paperheight и pdfpageheight), что приводит к ещё большему числу проблем. Приведённый код их все учитывает)

Что ещё?



За 8 с лишним лет использования ТеХа и создания своего стиля у меня накопилось довольно много разных трюков, уловок и вообще нетривиальных моментов плохо освещённых в литературе.
Если будет интерес, то это также можно осветить.

Например:
  1. Создание portable сборок и настройка WinEdt (моя сборка на торрентах)
  2. Настройка WinEdt для прямого и обратного поиска сразу в PDF (про dvi можно забыть) (на хабре уже об этом немного писали
  3. Создание команд, которые «анализируют» структуру документа на лету — например, автоматическое создание сложных кондуитов, а также пишут какие-то данные в сторонние файлы на лету (например, у нас на лету создаётся специальный xml, который используется далее для электронного кондуита)
  4. Обработка и выполнение perl-, python-, metapost- или вообще любых кусков стороннего кода на лету
  5. Как следствие, неаккуратно скомпилировав чужой документ, вы можете, скажем, удалить какие-нибудь данные, запустить программу-вирус, и т.д. и т.п. (пример ;-)
  6. Создание и добавление рисунков, графиков и т.д. прямо в ТеХ, в metapost, IPE, GeoAlgebra и т.д. (про это уже тоже было раз, два, три, но тема необъятна.
Tags:
Hubs:
Total votes 37: ↑36 and ↓1+35
Comments10

Articles