-
Notifications
You must be signed in to change notification settings - Fork 1
Простые примеры по шагам
Базовыми элементами FineTeX'а являются блоки текста (абзацы), окружения и префиксы. Для начала рассмотрим их по отдельности.
Абзацы в FineTeX'е также, как и в LaTeX'е разделяются пустыми строками. Например:
Первый абзац.
Второй абзац.
И он продолжается на следующей строке.
А вот это уже третий абзац.
Отметим, что при трансляции в LaTeX разбиение на строчки не сохраняется. Так предыдущий пример при трансляции даёт:
Первый абзац.
Второй абзац. И он продолжается на следующей строке.
А вот это уже третий абзац.
Также, в отличие от LaTeX'а, FineTeX чувствителен к отступам. Если отступы части строк в абзаце отличаются от остальных, они образуют отельный блок. Так, например, следующий код
Начало
абзаца
продолжение
абзаца
конец
абзаца.
И ещё чуть-чуть
Даст при трансляции
Начало абзаца
продолжение абзаца
конец абзаца. И ещё чуть-чуть
Начало, продолжение и конец не объединились в одну строчку, так как они имели разные отступы.
А что если строчки окажутся слишком длинные?
Тогда они будут перенесены в произвольном месте между словами.
Но в целом, за это можно не переживать, так как LaTeX в большинстве случаев
не чувствителен к переносам строк.
Однако иногда всё же бывает нежелательным такое объединение и разделение строк.
В таком случае можно воспользоваться @Verb
окружениями (о них будет рассказано дальше).
Как вы наверняка знаете, в LaTeX'е встроенные формулы заключаются в доллары $
.
В FineTeX'е, чтобы не возникало путаницы, для этих целей выбраны обратные кавычки ```.
Например
Теорема пифагора: `a^2 + b^2 = c^2`
транслируется в
Теорема пифагора: $a^2 + b^2 = c^2$
Пока FineTeX почти ничем не отличается от LaTeX'а. Однако тут уже мы вплотную подошли к одной из самых мощных возможностей FineTeX'а --- команд с произвольными именами
В отличие, от LaTeX'а, где любая команда должна начинаться с \
и состоять из латинских букв,
в FineTeX'е название команды может быть любой последовательностью символов (не обязательно букв),
кроме знака процента %
, так как он открывает однострочный комментарий и обратной кавычки ```,
которая обрамляет встроенную формулу.
Введём, например, !=
для символа неравенства (\neq
), <=
и >=
для \leq
и \geq
соответственно.
FineTex-команды определяются в специальном окружении @Define
, которая должна идти в начале файла:
@Define
@MathCommands
!= = "\\neq"
<= = "\\leq"
>= = "\\geq"
Неравенства: `a <= b`, `c >= d`, `e != f`.
NB справа от знака =
в определении команды стоит строковый литерал.
В нём \
--- специальный символ, и поэтому, чтобы получить его как символ, нужно написать \\
.
Неравенства: $a \leq b$, $c \geq d$, $e \neq f$.
Да, их тоже можно использовать. Например:
@Define
@MathCommands
∀ = "\\forall"
∃ = "\\exists"
δ = "\\delta"
ϵ = "\\epsilon"
-> = "\\rightarrow"
=> = "\\Rightarrow"
Функция `f` стремится к `y` при `x -> x_0`, если
`∀ϵ > 0 ∃δ > 0 : ∀x (|x - x_0| < δ => |f(x) - y| < ϵ)`
после трансляции превращается в
Функция $f$ стремится к $y$ при $x \rightarrow x_0$, если $\forall\epsilon > 0 \exists\delta > 0 :
\forall x (|x - x_0| < \delta \Rightarrow |f(x) - y| < \epsilon)$
Как видите, формула получилась достаточно громоздкая. Если вы собираетесь потом использовать
сгенерированный .tex
файл отдельно, то это может быть нежелательным.
Но данная проблема легко решается: достаточно объявить обычные LaTeX'овские
команды и заменять Unicode-символы на них:
@Define
@MathCommands
∀ = "\\all"
∃ = "\\ex"
δ = "\\delta"
ϵ = "\\epsilon"
-> = "\\approc"
=> = "\\impl"
\newcommand{\all}{\forall}
\newcommand{\ex}{\exists}
\newcommand{\approc}{\rightarrow}
\newcommand{\impl}{\Rightarrow}
Функция `f` стремится к `y` при `x -> x_0`, если
`∀ϵ > 0 ∃δ > 0 : ∀x (|x - x_0| < δ => |f(x) - y| < ϵ)`
Посмотрим результат:
\newcommand{\all}{\forall} \newcommand{\ex}{\exists} \newcommand{\approc}{\rightarrow}
\newcommand{\impl}{\Rightarrow}
Функция $f$ стремится к $y$ при $x \approc x_0$, если
$\all\epsilon > 0 \ex\delta > 0 : \all x (|x - x_0| < \delta \impl |f(x) - y| < \epsilon)$
Вот так-то лучше. Только \newcommand
транслятор тоже решил объединить в одну строчку.
Это, как правило, не слишком удобно.
Также в LaTeX командах могут встретиться, скажем,
обратные кавычки и тогда всё будет совсем неприятно.
Для этих целей предусмотрены @Verb
окружения. Но о них чуть позже.
Возможно у вас возник вопрос, как же набирать все эти замечательные Unicode-символы. В большинстве современных сред разработки (да и во многих текстовых редакторах) для этого есть специальные расширения. Для VsCode, например, одно из таких расширений описано здесь
- Математические команды заменяются лишь в математическом режиме (в inline-формулах и математических окружениях, о них ниже).
- Команды заменяются одновременно, не рекурсивно.
- Предпочтение отдаётся более длинным командам.
Окружения в FineTeX'е представляют из себя следующую конструкцию:
в отдельной строке название окружения (всегда начинается с @
и может состоять
только из латинских букв и символов -
и '
) затем аргументы (если они есть)
далее с новой строки и с бОльшим, чем окружающий текст отступом находится то,
что попадёт внутрь окружения. Как только отступ становится меньше либо равен
отступу начала названия окружения (т. е. символа @
), окружение считается завершённым.
Так, например, в следующем коде:
@Simple
один
два
три
четыре
пять
всё, кроме "пять" попадёт внутрь окружения @Simple
.
Чтобы использовать окружения надо их объявить. Скажем, в нашем простом примере
@Define
@Environments
Simple =
Если дописать эти строки до кода выше мы получим:
один
два
три
четыре
пять
Как видите, никакого следа от окружения не осталось. Предположим, что мы хотим, чтобы в начале окружения добавлялась надпись "Привет!!!", а в конце "Пока :)". Для этого переделаем объявление окружения следующим образом:
@Define
@Environments
Simple = @Begin "Привет!!!" @End "Пока :)"
Посмотрим, что мы получили:
Привет!!!
один
два
три
четыре
Пока :)
пять
кроме ожидаемых надписей ещё появились отступы, выделяющие содержимое окружения.
Они добавляются автоматически всегда, если присутствует @Begin
и/или @End
.
Да, любую из этих опций можно использовать в отдельности.
А ещё есть специальная опция @TexBeginEnd "..."
,
которая равносильна @Begin "\\begin{...}"
и @End "\\end{...}"
,
удобная для задания стандартных LaTeX'овских окружений:
@Define
@Environments
Document = @TexBeginEnd "document"
Equation = @TexBeginEnd "equation"
@Document
Теорема Пифагора:
@Equation
a^2 + b^2 = c^2
\begin{document}
Теорема Пифагора:
\begin{equation}
a^2 + b^2 = c^2
\end{equation}
\end{document}
Вот это уже больше похоже на настоящий LaTeX!
Однако тут пока не всё гладко с @Equation
.
Если мы попробуем использовать в нём определённые в @MathCommands
FineTeX-команды, то ничего не получится: FineTeX пока
не знает, что в @Equation
должны быть математические формулы.
Так, если погрузить в @Equation
пример из с пределом функции
(естественно, скопировав определения @MathCommands
)
Функция `f` стремится к `y` при `x -> x_0`, если
@Equation
∀ϵ > 0 ∃δ > 0 : ∀x (|x - x_0| < δ => |f(x) - y| < ϵ)
то транслятор выдаст множество сообщений об ошибках вида:
...\eq-unicode-bug.ttex:17:3: Unexpected unicode symbol: '∀'
∀ϵ > 0 ∃δ > 0 : ∀x (|x - x_0| < δ => |f(x) - y| < ϵ)
^~^
Чтобы содержимое окружений equation
, align
и т. п. распознавалось,
как математическая формула и производилась соответствующая замена @MathCommands
необходимо добавить опцию @Math
в объявление окружения:
@Define
@Environments
Equation = @TexBeginEnd "equation" @Math
Тогда мы получим ожидаемое:
Функция $f$ стремится к $y$ при $x \rightarrow x_0$, если
\begin{equation}
\forall\epsilon > 0 \exists\delta > 0 : \forall x (|x - x_0| < \delta \Rightarrow |f(x) - y| <
\epsilon)
\end{equation}
Однако для данного примера намного более удобный и легковесный синтаксис дают префиксы, которые мы разберём в следующей главе.
Эти две опции говорят транслятору: не думай, что там внутри окружения,
просто перепиши всё как есть в .pdf
файл.
Однако с опцией @Verb
транслятор всё же добавляет отступы в начало строки, чтобы
сохранить "лесенку".
Это вполне допустимо везде, кроме окружений, которые чувствительны к пробелам.
Таким, например, является verbatim
.
Рассмотрим следующий пример:
@Define
@Environments
Tex = @Verb
Verbatim = @TexBeginEnd "verbatim" @Verb
Verbatim' = @TexBeginEnd "verbatim" @VerbIndent
Document = @TexBeginEnd "document"
@Tex
% Подключаем пакеты в окружении `@Tex`,
% чтобы транслятор не обрабатывал этот текст,
% не менял разделение на строчки и не пытался
% найти здесь какие-либо FineTeX команды
\documentclass[12pt,a4paper,oneside]{article}
\usepackage[utf8]{inputenc}
\usepackage[english,russian]{babel}
@Document
\texttt{Verbatim} с дополнительными отступами и пробелами.
В \texttt{.pdf} выглядит не очень красиво
@Verbatim
\begin{enumerate}
\item one
\item two
\end{enumerate}
А вот этот \texttt{verbatim} печатается в \texttt{.tex} документе без отступов,
выбиваясь из красивой лесенки
@Verbatim'
\begin{enumerate}
\item one
\item two
\end{enumerate}
но зато в \texttt{.pdf}-файле выглядит намного лучше!
После компиляции он превращается в:
% Подключаем пакеты в окружении `@Tex`,
% чтобы транслятор не обрабатывал этот текст,
% не менял разделение на строчки и не пытался
% найти здесь какие-либо FineTeX команды
\documentclass[12pt,a4paper,oneside]{article}
\usepackage[utf8]{inputenc}
\usepackage[english,russian]{babel}
\begin{document}
\texttt{Verbatim} с дополнительными отступами и пробелами. В \texttt{.pdf} выглядит не очень
красиво
\begin{verbatim}
\begin{enumerate}
\item one
\item two
\end{enumerate}
\end{verbatim}
А вот этот \texttt{verbatim} печатается в \texttt{.tex} документе без отступов, выбиваясь из
красивой лесенки
\begin{verbatim}
\begin{enumerate}
\item one
\item two
\end{enumerate}
\end{verbatim}
но зато в \texttt{.pdf}-файле выглядит намного лучше!
\end{document}
чтобы понять слова про отступы, давайте скомпилируем этот код в .pdf
Эта опция отключает проверку префиксов внутри окружения. Бывает полезна в математических окружениях, так как в них часто строки начинаются с небуквенных символов. Подробно описана в следующей главе.
Начнём с примера. Данный код (section
действительно удобно так определять,
а Frame
тут добавлен просто для примера команды с двумя аргументами)
@Define
@Environments
Section (name : String) = @Begin "\\section{$name}"
Frame (start : String) (stop : String) = @Begin "Начало: $start" @End "Конец: $stop"
@Section "Сбор урожая"
@Frame "пока у нас нет яблок" "Теперь у нас целых два яблока!!!"
Нашли первое яблоко!
Нашли второе яблоко!
Нашли третье яблоко, но сбор урожая уже закончился :(
транслируется в
\section{Сбор урожая}
Начало: пока у нас нет яблок
Нашли первое яблоко!
Нашли второе яблоко!
Конец: Теперь у нас целых два яблока!!!
Нашли третье яблоко, но сбор урожая уже закончился :(
Префиксы --- это более компактная форма окружений. Они не требуют отдельной строчки и длинного названия, их имя, как правило, состоит из нескольких небуквенных символов. Рассмотрим сразу пример:
@Define
@Environments
Document = @TexBeginEnd "document"
@Prefs
> = @TexBeginEnd "equation"
@Document
Теорема Пифагора:
> a^2 + b^2 = c^2
Этот код даёт абсолютно тот же результат, что и аналогичный с @Equation
выше.
Однако один символ >
гораздо меньше засоряет код, чем @Equation
на отдельной строке.
Приведём теперь более точное описание того, что такое префикс.
Первый символ в названии префикса должен быть из набора !#$%^*-+,./|\><[]~
(этот список символов, скорее всего, будет расширяться в следующих версиях),
далее может идти произвольных непробельных символов, кроме букв, цифр и %
.
Строка, в которой открывается префикс должна иметь больший отступ,
чем окружающие её строки.
Начинаться она должна с названия префикса, за которым должен следовать хотя бы 1 пробел
(либо конец строки).
Всё что идёт на этой строке и следующих строках с большим отступом, чем начало имени
префикса, попадает внутрь него.
Также, как и в окружениях для использования математических FineTeX-команд в префиксах
необходимо добавить опцию @Math
:
@Define
@Prefs
> = @TexBeginEnd "equation" @Math
После этого следующий код будет работать аналогично соответствующему с @Equation
выше
Функция `f` стремится к `y` при `x -> x_0`, если
> ∀ϵ > 0 ∃δ > 0 : ∀x (|x - x_0| < δ => |f(x) - y| < ϵ)
Наличие префиксов в языке, кроме всего прочего, накладывает ограничение на первую строку абзаца --- она не должна начинаться с допустимого имени префикса, за которым следует пробел или перенос строки. Например, следующий код:
~ зачем-то мы решили начать строку со знака ~
выдаст ошибку:
...\pref-par-error.ttex:1:1:
|
1 | ~ зачем-то мы решили начать строку со знака ~
| ^
Undefined prefix "~"
Однако внутри абзацев это допустимо:
Сейчас ошибки не будет:
~ зачем-то мы решили начать строку со знака ~
Так как транслятор знает, что если бы мы хотели тут префикс, сделали бы отступ:
Снова ошибка:
~ зачем-то мы решили начать строку со знака ~
Если всё же очень нужно начать абзац с недопустимой комбинации символов, можно поставить перед ними пустые фигурные скобки (пользуясь тем, что LaTeX их проигнорирует):
{}~ Ok, транслятор не замечает ~ за скобками
Такие ситуации часто возникают в математических окружениях при переносе формулы.
Причём, как правило, в подобных случаях и не предполагается использовать префиксы
внутри данных окружений. В таком случае можно воспользоваться опцией @NoPrefInside
:
@Define
@Environments
Equation = @TexBeginEnd "equation" @Math @NoPrefInside
@Equation
a + b + c
+ d + e = f
работает, в то время как без опции @NoPrefInside
выдаёт ошибку Undefined prefix "+"
.
Для префиксов тоже есть аналогичная опция. Так предыдущий пример можно переписать
с использованием >
:
@Define
@Environments
> = @TexBeginEnd "equation" @Math @NoPrefInside
> a + b + c
+ d + e = f
Ещё одно интересное свойство префиксов: они автоматически группируются. Например, следующий код
@Define
@Environments
Document = @TexBeginEnd "document"
@Prefs
> = @TexBeginEnd "equation"
@Document
Теорема Пифагора дважды:
> a^2 + b^2 = c^2
> c^2 = a^2 + b^2
после трансляции даёт
\begin{document}
Теорема Пифагора дважды:
\begin{equation}
a^2 + b^2 = c^2
c^2 = a^2 + b^2
\end{equation}
\end{document}
Как видим, два уравнения объединились в одно.
В данном случае, это вряд ли то, чего мы хотели
(эти два уравнения LaTeX потом напечатает в одну строчку,
так как он игнорирует переносы строк), но добавив разделитель (@Sep
)
и взяв align
вместо equation
в качестве итогового LaTeX-окружения получим из
@Define
@Environments
Document = @TexBeginEnd "document"
@Prefs
> = @TexBeginEnd "align" @Sep "\\\\"
@Document
Теорема Пифагора дважды:
> a^2 &+ b^2 = c^2
> c^2 &= a^2 + b^2
\documentclass{article}
\usepackage[english,russian]{babel}
\usepackage{amsmath}
\begin{document}
Теорема Пифагора дважды:
\begin{align}
a^2 &+ b^2 = c^2\\
c^2 &= a^2 + b^2
\end{align}
\end{document}
(символ '&' используется в LaTeX'е для выравнивания многострочных формул)
Немного больше точности: префиксы группируются в один блок, если они идут последовательно, между ними нет пустых строк (внутри префикса пустые строки могут быть), они одинакового типа (в смысле названия префиксов совпадают) и символы префиксов имеют одинаковый отступ.
Разделитель @Sep
вставляется после каждого префикса, кроме последнего,
значения опций @Begin
и @End
добавляются до и после всей группы префиксов.
Также можно указать опцию @Pref
--- соответствующая строка будет вставляться
в начало каждого префикса, в том числе последнего.
Такое поведение нужно, в например для списков.
Определим маркированный и нумерованный списки так:
@Define
@Prefs
- = @TexBeginEnd "itemize" @Pref "\\item"
# = @TexBeginEnd "enumerate" @Pref "\\item"
Рассмотрим следующий пример
Маркированный список:
- один
второй параграф в первом элементе
- два
- 2.1
- 2.2
- уже новый вложенный список,
так как есть пустая строка после предыдущего элемента
и какой-то комментарий после списков
- три
- 3.1
# Нумерованный раз
# два
- отделил данный элемент в отдельный список
Маркированный список:
\begin{itemize}
\item один
второй параграф в первом элементе
\item два
\begin{itemize}
\item 2.1
\item 2.2
\end{itemize}
\begin{itemize}
\item уже новый вложенный список, так как есть пустая строка после предыдущего элемента
\end{itemize}
и какой-то комментарий после списков
\item три
\begin{itemize}
\item 3.1
\end{itemize}
\end{itemize}
\begin{enumerate}
\item Нумерованный раз
\item два
\end{enumerate}
\begin{itemize}
\item отделил данный элемент в отдельный список
\end{itemize}
Иногда возникает желание вынести часть определений в отдельный файл и использовать их потом из разных документов.
Нет ничего проще! Достаточно скопировать окружение @Define
в новый файл, а в старом прописать @Import
перед возможным блоком @Define
.
Пути при импорте отсчитываются относительно текущего файла,
так что при таком подключении, как в примере, defs.ttex
и main.ttex
должны быть в одной папке.
defs.ttex
@Define
@MathCommands
∀ = "\\all"
∃ = "\\ex"
δ = "\\delta"
ϵ = "\\epsilon"
-> = "\\approc"
=> = "\\impl"
@Prefs
> = @TexBeginEnd "align" @Math @Sep "\\\\" @NoPrefInside
- = @TexBeginEnd "itemize" @Pref "\\item"
@Environments
Document = @TexBeginEnd "document"
Section (name : String) = @Begin "\\section{$name}"
Tex = @Verb
main.ttex
@Import "defs.ttex"
@Define
@MathCommands
ℕ = "\\N"
∞ = "\\infty"
∈ = "\\in"
,, = ",\\quad"
@Tex
\documentclass{article}
\usepackage[english,russian]{babel}
\usepackage{amsmath}
\usepackage{amssymb}
\newcommand{\N}{\mathbb{N}}
\newcommand{\all}{\forall}
\newcommand{\ex}{\exists}
\newcommand{\approc}{\rightarrow}
\newcommand{\impl}{\Rightarrow}
@Document
@Section "Предел функции"
Функция `f` стремится к `y` при `x -> x_0`, если
> ∀ϵ > 0 ∃δ > 0 : ∀x (|x - x_0| < δ => |f(x) - y| < ϵ)
Как известно, это равносильно тому, что для любой последовательности `\{ x_n \}_{n ∈ ℕ}`,
> x_n -> x_0,, n -> ∞ => f(x_n) -> y,, n -> ∞
Примеры:
> \frac{ sin x }{ x } &-> 1,, x -> 0
> (1 + x)^{1 / x} &-> e,, x -> 0
Сразу видны проблемы текущей версии FineTeX'а.
Так как из файла импортируются только объявления,
невозможно, например, подключить пакет amsmath
и приходится
это делать отдельно для каждого файла, где используется >
в качестве align
.
По тем же причинам нельзя определить сокращения \all
, \ex
и т. п.
Однако это будет исправлено в следующих версиях.
Посмотрим на сгенерированный .tex
файл:
\documentclass{article}
\usepackage[english,russian]{babel}
\usepackage{amsmath}
\usepackage{amssymb}
\newcommand{\N}{\mathbb{N}}
\newcommand{\all}{\forall}
\newcommand{\ex}{\exists}
\newcommand{\approc}{\rightarrow}
\newcommand{\impl}{\Rightarrow}
\begin{document}
\section{Предел функции}
Функция $f$ стремится к $y$ при $x \approc x_0$, если
\begin{align}
\all\epsilon > 0 \ex\delta > 0 : \all x (|x - x_0| < \delta \impl |f(x) - y| < \epsilon)
\end{align}
Как известно, это равносильно тому, что для любой последовательности $\{ x_n \}_{n \in \N}$,
\begin{align}
x_n \approc x_0, n \approc \infty \impl f(x_n) \approc y, n \approc \infty
\end{align}
Примеры:
\begin{align}
\frac{ sin x }{ x } &\approc 1, x \approc 0\\
(1 + x)^{1 / x} &\approc e,\quad x \approc 0
\end{align}
\end{document}