Skip to content

Простые примеры по шагам

Lev135 edited this page Jun 6, 2022 · 12 revisions

Базовыми элементами FineTeX'а являются блоки текста (абзацы), окружения и префиксы. Для начала рассмотрим их по отдельности.

Абзацы

Простые абзацы

Абзацы в FineTeX'е также, как и в LaTeX'е разделяются пустыми строками. Например:

Первый абзац.

Второй абзац.
И он продолжается на следующей строке.

А вот это уже третий абзац.

Отметим, что при трансляции в LaTeX разбиение на строчки не сохраняется. Так предыдущий пример при трансляции даёт:

Первый абзац.

Второй абзац. И он продолжается на следующей строке.

А вот это уже третий абзац.

Также, в отличие от LaTeX'а, FineTeX чувствителен к отступам. Если отступы части строк в абзаце отличаются от остальных, они образуют отельный блок. Так, например, следующий код

Начало
абзаца
  продолжение
  абзаца
конец
абзаца.
И ещё чуть-чуть

Даст при трансляции

Начало абзаца
продолжение абзаца
конец абзаца. И ещё чуть-чуть

Начало, продолжение и конец не объединились в одну строчку, так как они имели разные отступы.

А что если строчки окажутся слишком длинные? Тогда они будут перенесены в произвольном месте между словами. Но в целом, за это можно не переживать, так как LaTeX в большинстве случаев не чувствителен к переносам строк. Однако иногда всё же бывает нежелательным такое объединение и разделение строк. В таком случае можно воспользоваться @Verb окружениями (о них будет рассказано дальше).

Встроенные (inline) формулы

Как вы наверняка знаете, в LaTeX'е встроенные формулы заключаются в доллары $. В FineTeX'е, чтобы не возникало путаницы, для этих целей выбраны обратные кавычки ```. Например

Теорема пифагора: `a^2 + b^2 = c^2`

транслируется в

Теорема пифагора: $a^2 + b^2 = c^2$

Пока FineTeX почти ничем не отличается от LaTeX'а. Однако тут уже мы вплотную подошли к одной из самых мощных возможностей FineTeX'а --- команд с произвольными именами

Команды (@MathCommands)

Простые команды

В отличие, от 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$.

Unicode-символы в командах

Да, их тоже можно использовать. Например:

@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-формулах и математических окружениях, о них ниже).
  • Команды заменяются одновременно, не рекурсивно.
  • Предпочтение отдаётся более длинным командам.

Окружения (@Environments)

Простейшие примеры @Begin, @End и @TexBeginEnd

Окружения в 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| < ϵ)
  ^~^

Опция @Math

Чтобы содержимое окружений 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}

Однако для данного примера намного более удобный и легковесный синтаксис дают префиксы, которые мы разберём в следующей главе.

Опции @Verb @VerbIndent

Эти две опции говорят транслятору: не думай, что там внутри окружения, просто перепиши всё как есть в .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 verb-compiled

Опция @NoPrefInside

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

Окружения с параметрами

Начнём с примера. Данный код (section действительно удобно так определять, а Frame тут добавлен просто для примера команды с двумя аргументами)

@Define
  @Environments
    Section (name : String) = @Begin "\\section{$name}"
    Frame (start : String) (stop : String) = @Begin "Начало: $start" @End "Конец: $stop"

@Section "Сбор урожая"
  @Frame "пока у нас нет яблок" "Теперь у нас целых два яблока!!!"
    Нашли первое яблоко!

    Нашли второе яблоко!
  Нашли третье яблоко, но сбор урожая уже закончился :(

транслируется в

\section{Сбор урожая}
  Начало: пока у нас нет яблок
    Нашли первое яблоко!

    Нашли второе яблоко!
  Конец: Теперь у нас целых два яблока!!!
  Нашли третье яблоко, но сбор урожая уже закончился :(

Префиксы (@Prefs)

Простые префиксы и опция @Math

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

@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| < ϵ)

Ограничения на первые строки абзацев и опция @NoPrefInside

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

~ зачем-то мы решили начать строку со знака ~

выдаст ошибку:

...\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

Группировка префиксов, опции @Begin, @End, @BeginEnd, @Pref и @Sep

Ещё одно интересное свойство префиксов: они автоматически группируются. Например, следующий код

@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}

Импорты (@Import)

Иногда возникает желание вынести часть определений в отдельный файл и использовать их потом из разных документов. Нет ничего проще! Достаточно скопировать окружение @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}