Топаз является универсальным языком программирования со встроенной вёрсткой. Код, который делает одно и то же, выглядит одинаково, кто бы его ни писал.
let номера = подписи.map((текст) =>match (BigInt.parse(текст, 10)) {
case Some(число) => число.toInt()
case None() => None()
})
io.writeLine("{номера}")
Ожидаемый вывод
[Some(12), None, Some(14)]
map пишется после списка. BigInt.parse разбирает каждую строку, а toInt преобразует полученное число. На месте метки «обложка» остаётся None.
Для кого и для чего
Создан для таких команд
Команды, которые делают движок вёрстки книг
От рукописи к полосам
Движок принимает рукопись и решает, где закончатся строки и страницы. Разбиение абзацев и правила переноса для корейского, японского и китайского берутся из стандартной библиотеки. Один и тот же код разбиения строк работает в предпросмотре в браузере и в вёрстке для печати.
Команды, у которых правила зависят от издательства
Решения для каждой книги в файлах правил
С какой страницы начинать главу и сколько висячих строк допустимо, у каждого издательства и каждой книги свои решения. Они живут в файлах правил Лиспекса, а код разбиения строк общий для всех книг. Если у каждого клиента свой стиль учебника или отчёта, код приложения не меняется.
Функцию, которая разбирает входные данные, например проверяет JSON, пишут на Топазе и собирают в пакет для браузера. Существующее веб-приложение вызывает её из JavaScript. Так работают браузерные инструменты jeni.kr.
Модуль std.typeset в Топазе 6.0 разбивает абзацы на строки. Программа ниже разбивает корейское предложение на строки шириной в десять слогов хангыля. Если учитывать весь абзац, последнее слово не остаётся в строке одно.
for номерЗнака in (строка.start..<строка.trimmedEndExclusive) {
текст = текст + знаки[номерЗнака].text
}
}
текст
}
let предложение ="문단 전체를 보고 줄을 나누면 마지막 줄이 짧게 남지 않고 줄마다 길이가 고르게 됩니다."
let знаки = предложение.scalars().map(знак)
let итог =match (classifyBreaks(знаки, корейскиеПравила(знаки))) {
case Ok(места) =>breakParagraph(абзац(знаки, места))
case Err(ошибка) => Err(ошибка)
}
match (итог) {
case Ok(разбиения) => {
io.writeLine("С учётом всего абзаца\n{строкиИз(знаки, разбиения.optimized)}\n")
io.writeLine("Строка за строкой\n{строкиИз(знаки, разбиения.greedy)}")
}
case Err(ошибка) => io.writeLine("{ошибка}")
}
Ожидаемый вывод
С учётом всего абзаца
문단 전체를 보고
줄을 나누면 마지막
줄이 짧게 남지
않고 줄마다 길이가
고르게 됩니다.
Строка за строкой
문단 전체를 보고 줄을
나누면 마지막 줄이
짧게 남지 않고 줄마다
길이가 고르게
됩니다.
Разбиение абзаца
Вы получаете разбиение с учётом всего абзаца и жадное разбиение строка за строкой. Модель стоимости можно выбрать между Knuth-Plass и моделью с фиксированной точкой.
Правила переноса Юникода
Места возможного разрыва строки находятся по алгоритму Юникода 16.0 (UAX #14).
Правила для языков
С корейскими (KLReq), японскими (JLReq) или китайскими (CLReq) правилами открывающая скобка не остаётся в конце строки, а закрывающая скобка и точка не начинают строку. Японские правила следуют классам символов JLReq.
Ширина восточноазиатских символов
Свойство Юникода East Asian Width помогает решить, где разрывать строку у кавычек и скобок рядом с китайскими, японскими и корейскими символами.
Интервалы
При выключке задаётся, насколько можно растянуть или сжать пробелы между латинскими словами и насколько можно растянуть интервалы между символами CJK.
Единицы длины
Длины 12pt, 3mm, 1cm, 1in и 1em записываются прямо в коде и переводятся из одних единиц в другие.
ATLAS превращает рукопись в готовые к печати страницы книги. Ниже показаны страница, свёрстанная в ATLAS, и две функции проверки правил переноса, переписанные для Топаза 6.0. В ATLAS эти функции названы корейскими терминами вёрстки, здесь они переведены на русский.
Две функции проверки правил переноса ATLAS переписаны для Топаза 6.0 с русскими именами. Полный пример добавляет простые вспомогательные функции и входные данные для этих двух правил.
atlas-ru.tpz
import std.io
// Small sample policies for the two predicates below.
Для частых задач есть один способ записи. Кто бы ни писал код, человек или агент, он выглядит одинаково, поэтому при проверке достаточно следить за тем, что код делает.
Один способ записи
Преобразование числа в строку и операции с коллекциями записываются как методы значений. Для массива используйте map, для числа toString. Исходный код форматирует topaz fmt.
Если значение может отсутствовать, функция возвращает Option, если операция может завершиться сбоем, она возвращает Result, а очистку ресурсов задаёт defer. В конце абзаца правило переноса получает None вместо следующего символа, и это не ошибка.
Вывод на экран и чтение файлов используют импортируемые стандартные модули. По импортам при проверке кода сразу видно, где программа обменивается данными с внешним миром.
Задайте фиксированный набор случаев, например классы разрыва строки, перечислением, и компилятор проверит, что каждое сопоставление match обрабатывает все варианты. Если позже добавить вариант, сборка покажет каждое сопоставление, которое его ещё не обрабатывает.
Тип int представляет знаковое 64-разрядное целое число. При переполнении программа останавливается на этом месте и не продолжает работу с неверным значением. Если считать ширину строк и стоимость раскладки в целых числах, переполнение не останется в результате незамеченным.
Прямой запуск, нативные исполняемые файлы и пакеты для браузера следуют одним правилам языка. Поэтому предварительный просмотр на экране и вёрстка для печати разбивают строки в одних и тех же местах.
Расчёты вроде разбиения на строки выполняет код на Топазе. Решения, которые меняются от издательства к издательству и от книги к книге, например с какой страницы начинать главу или сколько висячих строк допустимо, записываются отдельно в правилах Лиспекса. Топаз 6.0 выполняет правила Лиспекса 2.0 через std.lispex с отдельными лимитами подготовки, преобразования значений и вычисления. Замените исходный код правила и подготовьте его заново, и та же рукопись получит другой стиль без изменений в коде приложения.
Правила не обращаются к файлам, системным часам и сети.
Правило останавливается там, где превышает лимит.
Одинаковые правило, вход и настройки каждый раз дают одно и то же решение.
Имена и типы проверяет и код Rust генерирует код, написанный на Топазе. Команда topaz check проверяет программу, а topaz build создаёт исполняемый файл.
Модуль std.typeset разбивает абзац на строки. Задайте ширину вроде 12pt или 3mm, правила разбиения строк для каждого языка и интервалы в выключенных строках.