Вака-разметка


Эта довольно длинная статья о том, как появилась «вака-разметка», и почему она такая, какая она сейчас есть. Если вы не знаете, что такое «вака-разметка» и, тем более, что такое «вики», вам стоит посетить сайт проекта WackoWiki и прочитать там пару статей документации, в особенности статью про вики-концепции.


Оглавление документа

1. О вака-разметке

Если коротко, то вака-разметка — это особый способ форматирования текста, который старается при минимуме спецсимволов и минимальном визуальном искажении «исходного текста» получать после программного преобразования красивый HTML.


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


Вака-разметка используется в вики-движке WackoWiki, в программном комплексе НПЖ, в других проектах различных разработчиков. Для того, чтобы внедрить вака-разметку в вашем проекте, вам достаточно скачать и инкорпорировать в ваш проект одну или две вещи:

  • вака-форматтер?, php-класс, превращающий разметку в HTML;
  • визуальный редактор? для вики-текстов. Это необязательное, но чрезвычайно удобное дополнение к форматтеру.

Исходный текст этой статьи написан в формате вака-разметки и доступен для просмотра.


2. Принципы, положенные в основу

Хотя вака-разметка изначально досталась нам в наследство от проекта WakkaWiki (ранее размещавшегося по адресу http://wakkawiki.de, но сейчас недоступного), в её основе были чёткие принципы, которые и определили её дальнейший успех.


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


Принципы были придуманы для того, чтобы достичь следующих целей:

  • снизить вероятность «случайного срабатывания» (т.е. когда обычный текст воспринимается как какая-то часть разметки);
  • добиться «интуитивной» и легко запоминаемой разметки;
  • защитить окружение форматированного текста от возможных опечаток автора.

2.1. Семантика должна передаваться через синтаксис

В основе любой вики-разметки лежит принцип WYTIWYG, поэтому каждое правило вака-разметки старается своим оформлением (синтаксисом) отражать смысл (семантику). Поскольку в вака-разметке всё оформление делается средствами простого текста — символами, которые можно набрать с клавиатуры, то мы старались подобрать такие комбинации, которые бы отражали смысл:

  • **жирный** — звёздочки для жирного текста, который выделяется из общей массы;
  • //курсив// — курсив оформляется скошенными же линиями;
  • --зачёркивание-- и __подчёркивание__ соответственно;
  • списки выглядят так же, как мы привыкли писать подобные списки в текстовых полях ввода.

Здесь мы сразу отошли от классической вики-разметки с её «всего 5 апострофов с каждой стороны».

2.2. Парные символы

Как вы заметили, все приведённые выше примеры вака-разметки содержат парные символы. Благодаря этому принципу текст «просто вставленный из какого-нибудь другого редактора» не требует специальной предобработки — маловероятно, что в нём встретятся таким образом «спаренные» символы.


В разметке есть случаи, когда используются тройные, четверные символы (и даже последовательности из 5–6 подряд идущих символов) — они используются для выделения заголовков разного уровня. Чем больше символов, тем «глубже» уровень заголовка.

2.3. Разметка соприкасается с внутренним текстом

Не исключено, что вы из тех людей, что всегда пишут тире как «два минуса» (вот так: --). Во всяком случае, авторы явно из числа этих людей. И более того, существует великое множество текстов, содержащих двойной минус как в качестве тире, так и в других качествах.


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


Т.е. --вот так-- будет работать, а если -- мы сделаем так-- — то текст не зачёркнётся.


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


2.4. Перевод строки — завершение некоторого фрагмента текста

В отличие от, скажем, разметки OpenWiki, перевод строки в «исходном тексте» вака-разметки воспринимается буквально — как перевод строки (два перевода начнут новый абзац). Таким образом, мы принимаем, что перевод строки — это завершение некоторого законченного фрагмента текста, например предложения или даже абзаца.


Некоторые правила вака-разметки: правила, изменяющие параметры шрифта у текста (это жирность, курсив, подчёркивание и другое) и заголовки — большинство этих правил работают только в масштабах фрагмента текста, ограниченного переводом строки. Использование этого принципа позволяет решить сразу три задачи:

  • снизить вероятность «случайного срабатывания»;
  • упростить восприятие разметки (ведь «начало» и «конец» выделения оказываются недалеко друг от друга);
  • свести роль «шрифтового оформления» к выделению малых фрагментов текста — что положительно сказывается на восприятии результата.

2.5. «Сломанная» разметка не должна ломать HTML вокруг текста

Вышеизложенные принципы позволяют добиться решения одной очень важной задачи — «защиты» HTML вокруг отформатированного текста от возможных ошибок форматирования. Благодаря правилу «прилипания» мы почти всегда можем определить какая часть разметки является «началом», а какая «концом», а также вставлять сразу оба HTML-тага (или не вставлять ни одного). Для тех правил вака-разметки, которые не имеют столь легко достижимой «парности» должны быть предприняты все усилия, чтобы добиться «герметичности» результата. И, как мы видим, это удалось.

2.6. Должен быть способ написать в точности то, что я хочу написать

Любую разметку нужно уметь «экранировать» — т.е. делать так, чтобы при разборе правила разметки игнорировались и фрагмент текста проходил через форматирование неизменным. Эта статья — пример того, когда подобное «экранирование» необходимо.

2.7. Минимум переключения раскладки клавиатуры

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


Суть принципа заключается в том, чтобы подбирать правила разметки таким образом, чтобы большинство из них (в особенности часто используемые правила) было можно набирать, оставаясь в русской раскладке. Одновременно с этим нужно не забывать и об аналогичной доступности для англоязычной аудитории.


Таким образом, исходный синтаксис ссылок [[WikiLink Textual description]] обрёл своего двойника ((ВикиСсылка Текст на ссылке)), которого можно использовать как на английской, так и на русской раскладке. Очень многие правила вики-разметки обладают этим ценным свойством.


3. Правила формирования разметки

Применяя эти принципы, мы развивали и совершенствовали изначальный набор правил, внимательно изучая разные вики-движки. Если бы я посмел хвастаться, я бы сказал, что итоговая вака-разметка вобрала в себя всё самое лучшее из разных правил разметки, оставшись стройной и простой. Хотя, чёрт возьми! В итоге нашей работы вака-разметка вобрала в себя всё самое лучшее из разных правил разметки, оставшись стройной и простой.


В этой главе бегло рассказывается о том, как мы пришли к наиболее ключевым правилам разметки.

3.1. «Однострочная разметка»

Однострочной разметкой стали все те правила, которые использовали символы, частоупотребляемые в «простых текстах», и которые касались какого-то «местного» оформления текста:

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

3.2. «Многострочная разметка»

Остальные правила разметки работают на больших фрагментах строк. Это разрешено главным образом потому, что их оформление часто применяют к большим фрагментам текста.

Это, например, зачёркивание.
Или
цитирование, которое захватывает весь абзац.

3.3. Экранирование разметки

Экранирование реализуется двумя способами:

  • экранирование блока с помощью «парных символов» "";
  • escaping (введение специального символа перед экранируемой последовательностью) с помощью символа ~ (тильда).

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


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

3.4. Ссылки и изображения

Вака-разметка, обнаружив в тексте URL, автоматически превращает его в ссылку. Если понятно, что URL указывает на «картинку» (например, заканчивается на .jpg или .gif) — в отформатированный текст вставляется изображение с помощью тага <img>. Это удобно, потому что позволяет, не особенно задумываясь, вставлять ссылки из буфера обмена, получая вполне качественный результат.


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

  • ((URL Текстовое описание))
  • [[URL Текстовое описание]] — то же, только менее удобно
  • ((Вики Ссылка C Пробелами == Текстовое описание)) — позволяет вставлять пробелы в «левую часть» вики-ссылки (так же работает и на квадратных скобках)

Концепция вики-ссылок? позволяет вставлять ссылки «внутри сайта» более просто и вака-разметка это тоже учитывает. Все ссылки, которые не являются «внутренними», сразу оформляются как «внешние», то же происходит и с email-адресами.


Подписи к картинкам расставляются очень похоже на подписи к ссылкам:

  • ((picture.jpg Подпись)) — способ задания title картинки
  • ((URL small_picture.jpg)) — способ поставить ссылку с картинки

3.5. Списковые структуры

Как наиболее естественно для человека писать списки, нумерованные и ненумерованные, а так же вложенные?

**Наверное, как-то так:**
  * элемент списка-1
  * элемент списка-2
  * Подсписок
    * элемент подсписка-1
    * элемент подсписка-2
  * продолжение списка
  
  1. Нумерованный список раз
  2. Второй элемент
    1. так же и с вложенным
    6. нумерация может и сбиться

Что хочется получить:

  • элемент списка-1
  • элемент списка-2
  • Подсписок
    • элемент подсписка-1
    • элемент подсписка-2
  • продолжение списка

  1. Нумерованный список раз 
  2. Второй элемент
    1. так же и с вложенным
    2. нумерация может и сбиться

Именно так и устроены правила разметки списков в вака-разметке. Пример хорошо иллюстрирует, почему все буллиты списка изначально сдвинуты вправо на пару символов — это позволяет избежать путаницы с полужирным текстом.


Отступ выбран равным в два символа исходя из принципа «парных символов», которые в обычных текстах почти не встречаются. Некоторые другие вики-форматы используют пять-шесть пробелов — можно представить себе, как будет выглядеть третий уровень вложенности в <textarea>!


Оригинальная разметка с c2.com использует символ табуляции, что представляется нам очень непродуманным: в большинстве интерфейсов Tab выполняет функции навигации, а в некоторых браузерах символ табуляции ввести в поле ввода вообще невозможно.


Нумерация в нумерованных списках проставляется автоматически, что позволяет спокойно удалять пункты, добавлять новые и переносить их в иерархии. Если вам нужен нумерованный список, начинающийся с тройки, начните его 1.#3 Вот так.

  1. Именно так.

3.6. Разметка таблиц

Таблицы — одно из самых больных мест любой разметки. Наилучшим решением оказался набор правил, разметка которого имитирует вертикальные линии сетки таблицы. Это легче, чем рисовать дефисами, плюсами и вертикальными линиями всю сетку, и одновременно даёт вполне читаемую в «исходном тексте» таблицу. Подробнее о разметке таблиц можно прочитать в синтаксисе вака-разметке?. Там же есть и примеры.


К сожалению, разметка таблиц — самый «уязвимый» фрагмент вака-разметки, позволяющий в некоторых случаях «нарушить» структуру внешнего окружения документа. Эта та небольшая цена, которую мы решили заплатить за наглядность синтаксиса и скорость его разбора.

4. Развитие разметки

Во-первых, выше рассмотрены далеко не все правила вака-разметки, а лишь самые основные. Если вам чего-то не хватает — посмотрите сперва более полную документацию?. Если же становится ясно, что существующих правил не хватает — разметку стоит расширять. Так появилось большинство правил нашей разметки.

4.1. Когда стоит изменять существующую разметку?

Никогда.


Именно так, если речь идёт не о введении новых правил, а о изменении существующих. Изменение поведения разметки, которое кажется полезным вам, может существенно помешать остальным людям, привыкшим работать с такой разметкой. Представьте, если бы на некоторых сайтах <b> стало работать как <a> и наоборот.


Конечно, если в рамках вашего конкретного проекта какое-то правило существенно мешает — тогда можно подумать о его замене. Заменяя/удаляя правило, задумайтесь о том, как это воспримут все те, кто привыкли к стандартной вака-разметке!

4.2. Когда стоит вводить новые сущности разметки?

Как можно реже.


У вака-разметки есть концепция «хайлайтеров» — подключаемых сущностей, которые добавлять легко и просто, не занимая «основное пространство разметки» — парные символы. О концепции хайлайтеров сказано чуть ниже.


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


Если вы хотите расширить вака-разметку, то лучше всего будет обратиться к авторам данного формата — может у них уже есть продуманная идея или они с радостью воспримут вашу. Координированные действия всегда оказываются эффективнее.

5. Сложные преобразования и сервис-функции

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


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

5.1. Концепция форматтеров-хайлайтеров (highlighters)

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


В теле вака-разметки использование хайлайтера выглядит так %%(html)<div class="test">testdiv</div>...%% — т.е. используется «парный символ» %% с указанием в круглых скобках, какой функции-хайлайтеру передать то, что внутри.


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


Как правило, этот синтаксис используется для разнообразной «расцветки» текста — для подсветки синтаксиса, оформления ICQ-логов и email, вставки каких-то произвольных блоков текста.


Эта концепция — способ легко расширить разметку, при этом:

  • не задействуя дополнительных «парных символов»;
  • не разбираясь в деталях работы вака-форматтера.

5.2. Концепция акшнов-действий (actions)

Actions — это концепция, позволяющая разработчику реализовать какую-то сложную функциональность (возможно, даже требующую диалога с пользователем), а пользователю — легко обеспечить в нужном месте документа доступ к этой функциональности.


В теле вака-разметки использование «действия» выглядит так {{RecentChanges for="kuso@npj"}} — используется «парный символ» {{ с указанием имени «действия» и дополнительных параметров.


Разработчик пишет эти функции точно так же, как он пишет и «хайлайтеры».


Именно через «действия» в WackoWiki и НПЖ реализована значительная часть функциональности по работе с документами (построение каталога, списков последних изменений/комментариев, поиск).


Эта концепция — способ «встроить» в документ какую-то сложную функциональность, при этом так же не влезая в детали работы вака-форматтера.

5.3. Interwiki — модификация разметки ссылок

Существует также способ расширить синтаксис разметки ссылок, введя в него дополнительные правила вида ((repository:address)) или ((repository:address Текст на ссылке)). Адрес в таком случае указывается как два фрагмента «хранилище» и «имя в этом хранилище». Например, для LiveJournal адреса будут выглядеть как-то так: ((lj:mendokusee)), а для ссылки на перевод английского слова можно будет писать ((lingvo:fascinating)).


Эта концепция (как и многое в нашей разметке) унаследована из вики, и изначально предназначалась для указания страниц на других вики-узлах. Как мы заметили, её очень удобно использовать и с другими, менее специфичными целями.


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


Вариант interwiki (ссылки через двоеточие) кажется нам более правильным хотя бы потому, что используется во множестве систем и является стандартом де-факто. Кроме того interwiki не вызывает конфликта с обычной разметкой [[Link Description]].

6. Технические детали

Эта статья — не то место, где вы сможете в деталях разобраться, как работает вака-форматтер?, однако, некоторые основные моменты стоит означить.


Во-первых, сам по себе форматтер построен на «регулярных выражениях» (а именно Perl Compatible Regular Expressions) и работает по принципу «рекурсивного разбора». Это означает, что он старается разбить текст на «самые крупные» фрагменты разметки, а потом использует себя же для разбора внутри них. Это, в свою очередь, значит, что нельзя вкладывать одинаковые правила разметки: например, вот так — **пример **вложенной** разметки** работать не будет. Но, согласитесь, это и не нужно.


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


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


Если вам интересны более глубокие аспекты функционирования форматтера — добро пожаловать в код форматтера?.

7. Вместо заключения

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


Если у вас возникли вопросы — не стесняйтесь задавать их в комментариях или лично авторам статьи.


С уважением, команда WackoWiki? и авторы статьи:

  • Кусо Мендокуси;
  • Роман Иванов.

8. Ссылки

  1. The WackoWiki Project
  2. Форматтер? для описываемой разметки
  3. Визуальный редактор? для описываемой разметки
  4. WakkaWiki — исторические корни WackoWiki (возможно, недоступно)
  5. OpenWiki — ещё одни исторические корни вака-разметки
  6. Описание вики-концепций?
  7. Синтаксис вака-разметки?
  8. Примеры классической разметки на c2.com
  9. Что такое ВикиИмя? — концепция вики-ссылок