summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Allen <dan.j.allen@gmail.com>2017-07-09 19:12:14 -0600
committerGitHub <noreply@github.com>2017-07-09 19:12:14 -0600
commit8e80317dee56483e48a07451bff0cd14f0bfd59c (patch)
treec46c4c14367b574328abbed4c38cdb334caccf88
parentc4b4d10c218093b46a8efecaf4f7969864ae3461 (diff)
resolves #858 add support for formal xref text (PR #2220)
- store referenceable nodes under refs key in document catalog - when registering a ref, store entry in both refs table and deprecated ids table - update tests to use consolidated register method - add xreftext method to AbstractBlock, Section, and Inline to produce formatted text for xref - add API docs to the xreftext methods - format xref text according to xrefstyle attribute, if set (full, short, or basic) - move reftext? and reftext methods down to AbstractBlock and Inline; contextualize - apply reftext substitutions (specialchars, quotes, replacements) to value returned by reftext method - drop support for reftext document attribute - don't catalog inline anchor if reftext containing attribute reference resolves to empty string - use reftext method instead of text method for :ref in DocBook converter - add feature tests for explicit reftext - add feature tests for generated reftext using xrefstyle - introduce language attributes for chapter, section, and appendix reference signifier * name attributes chapter-refsig, section-refsig, and appendix-refsig, respectively - enable chapter-label attribute in translations file; map to chapter-refsig attribute to it - map appendix-refsig attribute to value of appendix-caption attribute in translations file - add placeholders in translations file for chapter-refsig where missing and section-refsig - handle refsig document attribute values consistently (only use if attribute is non-nil) - update link and xref tests to populate refs key in document catalog - encode double quote and strip XML tags in value of xreflabel attribute in DocBook converter - don't store return value of target in inline_anchor method of HTML converter
-rw-r--r--data/locale/attributes.adoc137
-rw-r--r--features/xref.feature600
-rw-r--r--lib/asciidoctor/abstract_block.rb60
-rw-r--r--lib/asciidoctor/abstract_node.rb10
-rw-r--r--lib/asciidoctor/attribute_list.rb2
-rw-r--r--lib/asciidoctor/converter/docbook5.rb16
-rw-r--r--lib/asciidoctor/converter/html5.rb23
-rw-r--r--lib/asciidoctor/document.rb16
-rw-r--r--lib/asciidoctor/inline.rb22
-rw-r--r--lib/asciidoctor/parser.rb57
-rw-r--r--lib/asciidoctor/section.rb35
-rw-r--r--lib/asciidoctor/substitutors.rb16
-rw-r--r--test/blocks_test.rb19
-rw-r--r--test/document_test.rb2
-rw-r--r--test/links_test.rb68
-rw-r--r--test/sections_test.rb20
-rw-r--r--test/substitutions_test.rb5
17 files changed, 981 insertions, 127 deletions
diff --git a/data/locale/attributes.adoc b/data/locale/attributes.adoc
index 029df599..09e8d045 100644
--- a/data/locale/attributes.adoc
+++ b/data/locale/attributes.adoc
@@ -2,14 +2,17 @@
// See http://asciidoctor.org/docs/user-manual/#customizing-labels to learn how to use it.
//
// NOTE: Please use a line comment in front of the listing-caption and preface-title entries.
-// These attributes are optional and not set by default.
+// These attributes should not be set by default.
//
// IMPORTANT: Do not add any blank lines.
//
// Arabic translation, courtesy of Aboullaite Mohammed <aboullaite.mohammed@gmail.com>
ifeval::["{lang}" == "ar"]
:appendix-caption: ملحق
+:appendix-refsig: {appendix-caption}
:caution-caption: تنبيه
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: مثال
:figure-caption: الشكل
:important-caption: مهم
@@ -18,6 +21,7 @@ ifeval::["{lang}" == "ar"]
:manname-title: اسم
:note-caption: ملاحظة
//:preface-title: تمهيد
+//:section-refsig: ???
:table-caption: جدول
:tip-caption: تلميح
:toc-title: فهرس
@@ -25,11 +29,13 @@ ifeval::["{lang}" == "ar"]
:version-label: نسخة
:warning-caption: تحذير
endif::[]
-//
// Bulgarian translation, courtesy of Ivan St. Ivanov <ivan.st.ivanov@gmail.com>
ifeval::["{lang}" == "bg"]
:appendix-caption: Приложение
+:appendix-refsig: {appendix-caption}
:caution-caption: Внимание
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: Пример
:figure-caption: Фигура
:important-caption: Важно
@@ -38,6 +44,7 @@ ifeval::["{lang}" == "bg"]
:manname-title: ИМЕ
:note-caption: Забележка
//:preface-title: Предговор
+//:section-refsig: ???
:table-caption: Таблица
:tip-caption: Подсказка
:toc-title: Съдържание
@@ -45,11 +52,13 @@ ifeval::["{lang}" == "bg"]
:version-label: Версия
:warning-caption: Внимание
endif::[]
-//
// Catalan translation, courtesy of Abel Salgado Romero <abelromero@gmail.com> and Alex Soto
ifeval::["{lang}" == "ca"]
:appendix-caption: Apendix
+:appendix-refsig: {appendix-caption}
:caution-caption: Atenció
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: Exemple
:figure-caption: Figura
:important-caption: Important
@@ -58,6 +67,7 @@ ifeval::["{lang}" == "ca"]
:manname-title: NOM
:note-caption: Nota
//:preface-title: Prefaci
+//:section-refsig: ???
:table-caption: Taula
:tip-caption: Suggeriment
:toc-title: Índex
@@ -65,11 +75,13 @@ ifeval::["{lang}" == "ca"]
:version-label: Versió
:warning-caption: Advertència
endif::[]
-//
// Danish translation, courtesy of Max Rydahl Andersen <manderse@redhat.com>
ifeval::["{lang}" == "da"]
:appendix-caption: Appendix
+:appendix-refsig: {appendix-caption}
:caution-caption: Forsigtig
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: Eksempel
:figure-caption: Figur
:important-caption: Vigtig
@@ -78,6 +90,7 @@ ifeval::["{lang}" == "da"]
:manname-title: NAVN
:note-caption: Notat
//:preface-title:
+//:section-refsig: ???
:table-caption: Tabel
:tip-caption: Tips
:toc-title: Indholdsfortegnelse
@@ -85,12 +98,13 @@ ifeval::["{lang}" == "da"]
:version-label: Version
:warning-caption: Advarsel
endif::[]
-//
// German translation, courtesy of Florian Wilhelm
ifeval::["{lang}" == "de"]
:appendix-caption: Anhang
+:appendix-refsig: {appendix-caption}
:caution-caption: Achtung
:chapter-label: Kapitel
+:chapter-refsig: {chapter-label}
:example-caption: Beispiel
:figure-caption: Abbildung
:important-caption: Wichtig
@@ -99,6 +113,7 @@ ifeval::["{lang}" == "de"]
:manname-title: BEZEICHNUNG
:note-caption: Anmerkung
//:preface-title: Vorwort
+//:section-refsig: ???
:table-caption: Tabelle
:tip-caption: Hinweis
:toc-title: Inhalt
@@ -106,11 +121,13 @@ ifeval::["{lang}" == "de"]
:version-label: Version
:warning-caption: Warnung
endif::[]
-//
// Spanish translation, courtesy of Eddú Meléndez <eddu.melendez@gmail.com>
ifeval::["{lang}" == "es"]
:appendix-caption: Apéndice
+:appendix-refsig: {appendix-caption}
:caution-caption: Precaución
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: Ejemplo
:figure-caption: Figura
:important-caption: Importante
@@ -119,6 +136,7 @@ ifeval::["{lang}" == "es"]
:manname-title: NOMBRE
:note-caption: Nota
//:preface-title: Prefacio
+//:section-refsig: ???
:table-caption: Tabla
:tip-caption: Sugerencia
:toc-title: Tabla de Contenido
@@ -126,11 +144,13 @@ ifeval::["{lang}" == "es"]
:version-label: Versión
:warning-caption: Aviso
endif::[]
-//
// Persian (Farsi) translation, courtesy of Shahryar Eivazzadeh <shahryareiv@gmail.com>
ifeval::["{lang}" == "fa"]
:appendix-caption: پیوست
+:appendix-refsig: {appendix-caption}
:caution-caption: گوشزد
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: نمونه
:figure-caption: نمودار
:important-caption: مهم
@@ -139,6 +159,7 @@ ifeval::["{lang}" == "fa"]
:manname-title: نام
:note-caption: یادداشت
//:preface-title: پیشگفتار
+//:section-refsig: ???
:table-caption: جدول
:tip-caption: نکته
:toc-title: فهرست مطالب
@@ -146,11 +167,13 @@ ifeval::["{lang}" == "fa"]
:version-label: نگارش
:warning-caption: هشدار
endif::[]
-//
// Finnish translation by Tero Hänninen
ifeval::["{lang}" == "fi"]
:appendix-caption: Liitteet
+:appendix-refsig: {appendix-caption}
:caution-caption: Huom
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: Esimerkki
:figure-caption: Kuvio
:important-caption: Tärkeää
@@ -159,6 +182,7 @@ ifeval::["{lang}" == "fi"]
:manname-title: NIMI
:note-caption: Huomio
//:preface-title: Esipuhe
+//:section-refsig: ???
:table-caption: Taulukko
:tip-caption: Vinkki
:toc-title: Sisällysluettelo
@@ -166,11 +190,13 @@ ifeval::["{lang}" == "fi"]
:version-label: Versio
:warning-caption: Varoitus
endif::[]
-//
// French translation, courtesy of Nicolas Comet <nicolas.comet@gmail.com>
ifeval::["{lang}" == "fr"]
:appendix-caption: Appendice
+:appendix-refsig: {appendix-caption}
:caution-caption: Avertissement
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: Exemple
:figure-caption: Figure
:important-caption: Important
@@ -179,6 +205,7 @@ ifeval::["{lang}" == "fr"]
:manname-title: NOM
:note-caption: Note
//:preface-title: Préface
+//:section-refsig: ???
:table-caption: Tableau
:tip-caption: Astuce
:toc-title: Table des matières
@@ -186,11 +213,13 @@ ifeval::["{lang}" == "fr"]
:version-label: Version
:warning-caption: Attention
endif::[]
-//
// Hungarian translation, courtesy of István Pató <istvan.pato@gmail.com>
ifeval::["{lang}" == "hu"]
:appendix-caption: függelék
+:appendix-refsig: {appendix-caption}
:caution-caption: Figyelmeztetés
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: Példa
:figure-caption: Ábra
:important-caption: Fontos
@@ -199,6 +228,7 @@ ifeval::["{lang}" == "hu"]
:manname-title: NÉV
:note-caption: Megjegyzés
//:preface-title: Előszó
+//:section-refsig: ???
:table-caption: Táblázat
:tip-caption: Tipp
:toc-title: Tartalomjegyzék
@@ -206,12 +236,13 @@ ifeval::["{lang}" == "hu"]
:version-label: Verzió
:warning-caption: Figyelem
endif::[]
-//
// Bahasa Indonesia, courtesy of Triyan W. Nugroho <triyan.wn@gmail.com>
ifeval::["{lang}" == "id"]
:appendix-caption: Lampiran
+:appendix-refsig: {appendix-caption}
:caution-caption: Perhatian
:chapter-label: Bab
+:chapter-refsig: {chapter-label}
:example-caption: Contoh
:figure-caption: Gambar
:important-caption: Penting
@@ -220,6 +251,7 @@ ifeval::["{lang}" == "id"]
:manname-title: NAMA
:note-caption: Catatan
//:preface-title:
+//:section-refsig: ???
:table-caption: Tabel
:tip-caption: Tips
:toc-title: Daftar Isi
@@ -227,12 +259,13 @@ ifeval::["{lang}" == "id"]
:version-label: Versi
:warning-caption: Peringatan
endif::[]
-//
// Italian translation, courtesy of Marco Ciampa <ciampix@libero.it>
ifeval::["{lang}" == "it"]
:appendix-caption: Appendice
+:appendix-refsig: {appendix-caption}
:caution-caption: Attenzione
:chapter-label: Capitolo
+:chapter-refsig: {chapter-label}
:example-caption: Esempio
:figure-caption: Figura
:important-caption: Importante
@@ -241,6 +274,7 @@ ifeval::["{lang}" == "it"]
:manname-title: NOME
:note-caption: Nota
//:preface-title: Prefazione
+//:section-refsig: ???
:table-caption: Tabella
:tip-caption: Suggerimento
:toc-title: Indice
@@ -248,11 +282,13 @@ ifeval::["{lang}" == "it"]
:version-label: Versione
:warning-caption: Attenzione
endif::[]
-//
// Japanese translation, courtesy of Takayuki Konishi <seannos.takayuki@gmail.com>
ifeval::["{lang}" == "ja"]
:appendix-caption: 付録
+:appendix-refsig: {appendix-caption}
:caution-caption: 注意
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: 例
:figure-caption: 図
:important-caption: 重要
@@ -261,6 +297,7 @@ ifeval::["{lang}" == "ja"]
:manname-title: 名前
:note-caption: 注記
//:preface-title: まえがき
+//:section-refsig: ???
:table-caption: 表
:tip-caption: ヒント
:toc-title: 目次
@@ -268,11 +305,13 @@ ifeval::["{lang}" == "ja"]
:version-label: バージョン
:warning-caption: 警告
endif::[]
-//
// Korean translation, courtesy of Sungsik Nam <jmyl@me.com>
ifeval::["{lang}" == "kr"]
:appendix-caption: 부록
+:appendix-refsig: {appendix-caption}
:caution-caption: 주의
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: 예시
:figure-caption: 그림
:important-caption: 중요
@@ -281,6 +320,7 @@ ifeval::["{lang}" == "kr"]
:manname-title: 이름
:note-caption: 노트
//:preface-title: 머리말
+//:section-refsig: ???
:table-caption: 표
:tip-caption: 힌트
:toc-title: 차례
@@ -288,11 +328,13 @@ ifeval::["{lang}" == "kr"]
:version-label: 버전
:warning-caption: 경고
endif::[]
-//
// Dutch translation, courtesy of Roel Van Steenberghe <roel.vansteenberghe@gmail.com>
ifeval::["{lang}" == "nl"]
:appendix-caption: Bijlage
+:appendix-refsig: {appendix-caption}
:caution-caption: Opgelet
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: Voorbeeld
:figure-caption: Figuur
:important-caption: Belangrijk
@@ -301,6 +343,7 @@ ifeval::["{lang}" == "nl"]
:manname-title: NAAM
:note-caption: Noot
//:preface-title: Inleiding
+//:section-refsig: ???
:table-caption: Tabel
:tip-caption: Tip
:toc-title: Ínhoudsopgave
@@ -308,12 +351,13 @@ ifeval::["{lang}" == "nl"]
:version-label: Versie
:warning-caption: Waarschuwing
endif::[]
-//
// Norwegian Bokmål, courtesy of Aslak Knutsen <aslak@4fs.no>, with updates from Karl Ove Hufthammer <karl@huftis.org>
ifeval::["{lang}" == "nb"]
:appendix-caption: Vedlegg
+:appendix-refsig: {appendix-caption}
:caution-caption: OBS
:chapter-label: Kapittel
+:chapter-refsig: {chapter-label}
:example-caption: Eksempel
:figure-caption: Figur
:important-caption: Viktig
@@ -322,6 +366,7 @@ ifeval::["{lang}" == "nb"]
:manname-title: NAVN
:note-caption: Merk
//:preface-title: Forord
+//:section-refsig: ???
:table-caption: Tabell
:tip-caption: Tips
:toc-title: Innhold
@@ -329,12 +374,13 @@ ifeval::["{lang}" == "nb"]
:version-label: Versjon
:warning-caption: Advarsel
endif::[]
-//
// Norwegian Nynorsk, courtesy of Karl Ove Hufthammer <karl@huftis.org>
ifeval::["{lang}" == "nn"]
:appendix-caption: Vedlegg
+:appendix-refsig: {appendix-caption}
:caution-caption: OBS
:chapter-label: Kapittel
+:chapter-refsig: {chapter-label}
:example-caption: Eksempel
:figure-caption: Figur
:important-caption: Viktig
@@ -343,6 +389,7 @@ ifeval::["{lang}" == "nn"]
:manname-title: NAMN
:note-caption: Merk
//:preface-title: Forord
+//:section-refsig: ???
:table-caption: Tabell
:tip-caption: Tips
:toc-title: Innhald
@@ -350,12 +397,13 @@ ifeval::["{lang}" == "nn"]
:version-label: Versjon
:warning-caption: Åtvaring
endif::[]
-//
// Polish translation, courtesy of Łukasz Dziedziul <l.dziedziul@gmail.com>
ifeval::["{lang}" == "pl"]
:appendix-caption: Dodatek
+:appendix-refsig: {appendix-caption}
:caution-caption: Uwaga
:chapter-label: Rozdział
+:chapter-refsig: {chapter-label}
:example-caption: Przykład
:figure-caption: Rysunek
:important-caption: Ważne
@@ -364,6 +412,7 @@ ifeval::["{lang}" == "pl"]
:manname-title: NAZWA
:note-caption: Notka
//:preface-title:
+//:section-refsig: ???
:table-caption: Tabela
:tip-caption: Sugestia
:toc-title: Spis treści
@@ -371,11 +420,13 @@ ifeval::["{lang}" == "pl"]
:version-label: Wersja
:warning-caption: Ostrzeżenie
endif::[]
-//
// Portuguese translation, courtesy of Roberto Cortez <radcortez@yahoo.com>
ifeval::["{lang}" == "pt"]
:appendix-caption: Apêndice
+:appendix-refsig: {appendix-caption}
:caution-caption: Atenção
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: Exemplo
:figure-caption: Figura
:important-caption: Importante
@@ -384,6 +435,7 @@ ifeval::["{lang}" == "pt"]
:manname-title: NOME
:note-caption: Nota
//:preface-title: Prefácio
+//:section-refsig: ???
:table-caption: Tabela
:tip-caption: Sugestão
:toc-title: Índice
@@ -391,11 +443,13 @@ ifeval::["{lang}" == "pt"]
:version-label: Versão
:warning-caption: Aviso
endif::[]
-//
// Brazilian Portuguese translation, courtesy of Rafael Pestano <rmpestano@gmail.com>
ifeval::["{lang}" == "pt_BR"]
:appendix-caption: Apêndice
+:appendix-refsig: {appendix-caption}
:caution-caption: Cuidado
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: Exemplo
:figure-caption: Figura
:important-caption: Importante
@@ -404,6 +458,7 @@ ifeval::["{lang}" == "pt_BR"]
:manname-title: NOME
:note-caption: Nota
//:preface-title: Prefácio
+//:section-refsig: ???
:table-caption: Tabela
:tip-caption: Dica
:toc-title: Índice
@@ -411,11 +466,13 @@ ifeval::["{lang}" == "pt_BR"]
:version-label: Versão
:warning-caption: Aviso
endif::[]
-//
// Romanian translation, courtesy of Vitalie Lazu <vitalie.lazu@gmail.com>
ifeval::["{lang}" == "ro"]
:appendix-caption: Apendix
+:appendix-refsig: {appendix-caption}
:caution-caption: Precauție
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: Exemplu
:figure-caption: Figură
:important-caption: Important
@@ -424,6 +481,7 @@ ifeval::["{lang}" == "ro"]
:manname-title: NUME
:note-caption: Notă
//:preface-title: Prefață
+//:section-refsig: ???
:table-caption: Tabela
:tip-caption: Sfat
:toc-title: Cuprins
@@ -431,11 +489,13 @@ ifeval::["{lang}" == "ro"]
:version-label: Versiunea
:warning-caption: Atenție
endif::[]
-//
// Russian translation, courtesy of Alexander Zobkov <alexander.zobkov@gmail.com>
ifeval::["{lang}" == "ru"]
:appendix-caption: Приложение
+:appendix-refsig: {appendix-caption}
:caution-caption: Внимание
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: Пример
:figure-caption: Рисунок
:important-caption: Важно
@@ -444,6 +504,7 @@ ifeval::["{lang}" == "ru"]
:manname-title: НАЗВАНИЕ
:note-caption: Примечание
//:preface-title: Предисловие
+//:section-refsig: ???
:table-caption: Таблица
:tip-caption: Подсказка
:toc-title: Содержание
@@ -451,12 +512,13 @@ ifeval::["{lang}" == "ru"]
:version-label: Версия
:warning-caption: Предупреждение
endif::[]
-//
// Serbian Cyrillic translation, courtesy of Bojan Stipic <bojan-7@live.com>
ifeval::["{lang}" == "sr"]
:appendix-caption: Додатак
+:appendix-refsig: {appendix-caption}
:caution-caption: Опрез
-//:chapter-label: Поглавље
+:chapter-label: Поглавље
+:chapter-refsig: {chapter-label}
:example-caption: Пример
:figure-caption: Слика
:important-caption: Важно
@@ -465,6 +527,7 @@ ifeval::["{lang}" == "sr"]
:manname-title: НАЗИВ
:note-caption: Белешка
//:preface-title: Предговор
+//:section-refsig: ???
:table-caption: Табела
:tip-caption: Савет
:toc-title: Садржај
@@ -472,12 +535,13 @@ ifeval::["{lang}" == "sr"]
:version-label: Верзија
:warning-caption: Упозорење
endif::[]
-//
// Serbian Latin translation, courtesy of Bojan Stipic <bojan-7@live.com>
ifeval::["{lang}" == "sr_Latn"]
:appendix-caption: Dodatak
+:appendix-refsig: {appendix-caption}
:caution-caption: Oprez
-//:chapter-label: Poglavlje
+:chapter-label: Poglavlje
+:chapter-refsig: {chapter-label}
:example-caption: Primer
:figure-caption: Slika
:important-caption: Važno
@@ -486,6 +550,7 @@ ifeval::["{lang}" == "sr_Latn"]
:manname-title: NAZIV
:note-caption: Beleška
//:preface-title: Predgovor
+//:section-refsig: ???
:table-caption: Tabela
:tip-caption: Savet
:toc-title: Sadržaj
@@ -493,11 +558,13 @@ ifeval::["{lang}" == "sr_Latn"]
:version-label: Verzija
:warning-caption: Upozorenje
endif::[]
-//
// Turkish translation, courtesy of Rahman Usta <rahman.usta.88@gmail.com>
ifeval::["{lang}" == "tr"]
:appendix-caption: Ek bölüm
+:appendix-refsig: {appendix-caption}
:caution-caption: Dikkat
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: Örnek
:figure-caption: Görsel
:important-caption: Önemli
@@ -506,6 +573,7 @@ ifeval::["{lang}" == "tr"]
:manname-title: İSİM
:note-caption: Not
//:preface-title: Ön söz
+//:section-refsig: ???
:table-caption: Tablo
:tip-caption: İpucu
:toc-title: İçindekiler
@@ -513,11 +581,13 @@ ifeval::["{lang}" == "tr"]
:version-label: Versiyon
:warning-caption: Uyarı
endif::[]
-//
// Ukrainian translation, courtesy of Kyrylo Yatsenko <hedrok@gmail.com>
ifeval::["{lang}" == "uk"]
:appendix-caption: Додаток
+:appendix-refsig: {appendix-caption}
:caution-caption: Обережно
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: Приклад
:figure-caption: Зображення
:important-caption: Важливо
@@ -526,6 +596,7 @@ ifeval::["{lang}" == "uk"]
:manname-title: НАЗВА
:note-caption: Зауваження
//:preface-title: Передмова
+//:section-refsig: ???
:table-caption: Таблиця
:tip-caption: Підказка
:toc-title: Зміст
@@ -533,11 +604,13 @@ ifeval::["{lang}" == "uk"]
:version-label: Версія
:warning-caption: Попередження
endif::[]
-//
// Simplified Chinese translation, courtesy of John Dong <dongwqs@gmail.com>
ifeval::["{lang}" == "zh_CN"]
:appendix-caption: 附录
+:appendix-refsig: {appendix-caption}
:caution-caption: 注意
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: 示例
:figure-caption: 图表
:important-caption: 重要
@@ -546,6 +619,7 @@ ifeval::["{lang}" == "zh_CN"]
:manname-title: 名称
:note-caption: 笔记
//:preface-title: 序言
+//:section-refsig: ???
:table-caption: 表格
:tip-caption: 提示
:toc-title: 目录
@@ -553,11 +627,13 @@ ifeval::["{lang}" == "zh_CN"]
:version-label: 版本
:warning-caption: 警告
endif::[]
-//
// Traditional Chinese translation, courtesy of John Dong <dongwqs@gmail.com>
ifeval::["{lang}" == "zh_TW"]
:appendix-caption: 附錄
+:appendix-refsig: {appendix-caption}
:caution-caption: 注意
+//:chapter-label: ???
+//:chapter-refsig: {chapter-label}
:example-caption: 示例
:figure-caption: 圖表
:important-caption: 重要
@@ -566,6 +642,7 @@ ifeval::["{lang}" == "zh_TW"]
:manname-title: 名稱
:note-caption: 筆記
//:preface-title: 序言
+//:section-refsig: ???
:table-caption: 表格
:tip-caption: 提示
:toc-title: 目錄
diff --git a/features/xref.feature b/features/xref.feature
index 9dc6cbcf..a6bb01bc 100644
--- a/features/xref.feature
+++ b/features/xref.feature
@@ -1,9 +1,567 @@
# language: en
Feature: Cross References
- In order to create links to other sections
+ In order to create cross references between sections and blocks in the current or neighboring document
As a writer
- I want to be able to use a cross reference macro
+ I want to be able to use the cross reference macro to compose these references
+ Scenario: Create a cross reference to a block that has explicit reftext
+ Given the AsciiDoc source
+ """
+ :xrefstyle: full
+
+ See <<param-type-t>> to learn how it works.
+
+ .Parameterized Type <T>
+ [[param-type-t,that "<T>" thing]]
+ ****
+ This sidebar describes what that <T> thing is all about.
+ ****
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#param-type-t' that "&lt;T&gt;" thing
+ |to learn how it works.
+ """
+ When it is converted to docbook
+ Then the result should match the XML structure
+ """
+ simpara
+ |See
+ xref<> linkend='param-type-t'/
+ |to learn how it works.
+ sidebar xml:id='param-type-t' xreflabel='that &quot;&lt;T&gt;&quot; thing'
+ title Parameterized Type &lt;T&gt;
+ simpara This sidebar describes what that &lt;T&gt; thing is all about.
+ """
+
+ Scenario: Create a cross reference to a block that has explicit reftext with formatting
+ Given the AsciiDoc source
+ """
+ :xrefstyle: full
+
+ There are cats, then there are the <<big-cats>>.
+
+ [[big-cats,*big* cats]]
+ == Big Cats
+
+ So ferocious.
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |There are cats, then there are the
+ a< href='#big-cats' <strong>big</strong> cats
+ |.
+ """
+ When it is converted to docbook
+ Then the result should match the XML structure
+ """
+ simpara
+ |There are cats, then there are the
+ xref< linkend='big-cats'/
+ |.
+ section xml:id='big-cats' xreflabel='big cats'
+ title Big Cats
+ simpara So ferocious.
+ """
+
+ Scenario: Create a full cross reference to a numbered section
+ Given the AsciiDoc source
+ """
+ :sectnums:
+ :xrefstyle: full
+
+ See <<sect-features>> to find a complete list of features.
+
+ == About
+
+ [#sect-features]
+ === Features
+
+ All the features are listed in this section.
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#sect-features' Section 1.1, &#8220;Features&#8221;
+ |to find a complete list of features.
+ """
+
+ Scenario: Create a short cross reference to a numbered section
+ Given the AsciiDoc source
+ """
+ :sectnums:
+ :xrefstyle: short
+
+ See <<sect-features>> to find a complete list of features.
+
+ [#sect-features]
+ == Features
+
+ All the features are listed in this section.
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#sect-features' Section 1
+ |to find a complete list of features.
+ """
+
+ Scenario: Create a basic cross reference to an unnumbered section
+ Given the AsciiDoc source
+ """
+ :xrefstyle: full
+
+ See <<sect-features>> to find a complete list of features.
+
+ [#sect-features]
+ == Features
+
+ All the features are listed in this section.
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#sect-features' Features
+ |to find a complete list of features.
+ """
+
+ Scenario: Create a basic cross reference to a numbered section when the section reference signifier is disabled
+ Given the AsciiDoc source
+ """
+ :sectnums:
+ :xrefstyle: full
+ :!section-refsig:
+
+ See <<sect-features>> to find a complete list of features.
+
+ [#sect-features]
+ == Features
+
+ All the features are listed in this section.
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#sect-features' 1, &#8220;Features&#8221;
+ |to find a complete list of features.
+ """
+
+ Scenario: Create a full cross reference to a numbered chapter
+ Given the AsciiDoc source
+ """
+ :doctype: book
+ :sectnums:
+ :xrefstyle: full
+
+ See <<chap-features>> to find a complete list of features.
+
+ [#chap-features]
+ == Features
+
+ All the features are listed in this chapter.
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#chap-features' Chapter 1, <em>Features</em>
+ |to find a complete list of features.
+ """
+
+ Scenario: Create a short cross reference to a numbered chapter
+ Given the AsciiDoc source
+ """
+ :doctype: book
+ :sectnums:
+ :xrefstyle: short
+
+ See <<chap-features>> to find a complete list of features.
+
+ [#chap-features]
+ == Features
+
+ All the features are listed in this chapter.
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#chap-features' Chapter 1
+ |to find a complete list of features.
+ """
+
+ Scenario: Create a basic cross reference to a numbered chapter
+ Given the AsciiDoc source
+ """
+ :doctype: book
+ :sectnums:
+ :xrefstyle: basic
+
+ See <<chap-features>> to find a complete list of features.
+
+ [#chap-features]
+ == Features
+
+ All the features are listed in this chapter.
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#chap-features' <em>Features</em>
+ |to find a complete list of features.
+ """
+
+ Scenario: Create a basic cross reference to an unnumbered chapter
+ Given the AsciiDoc source
+ """
+ :doctype: book
+ :xrefstyle: full
+
+ See <<chap-features>> to find a complete list of features.
+
+ [#chap-features]
+ == Features
+
+ All the features are listed in this chapter.
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#chap-features' <em>Features</em>
+ |to find a complete list of features.
+ """
+
+ Scenario: Create a cross reference to a chapter using a custom chapter reference signifier
+ Given the AsciiDoc source
+ """
+ :doctype: book
+ :sectnums:
+ :xrefstyle: full
+ :chapter-refsig: Ch
+
+ See <<chap-features>> to find a complete list of features.
+
+ [#chap-features]
+ == Features
+
+ All the features are listed in this chapter.
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#chap-features' Ch 1, <em>Features</em>
+ |to find a complete list of features.
+ """
+
+ Scenario: Create a full cross reference to a numbered appendix
+ Given the AsciiDoc source
+ """
+ :sectnums:
+ :xrefstyle: full
+
+ See <<app-features>> to find a complete list of features.
+
+ [appendix#app-features]
+ == Features
+
+ All the features are listed in this appendix.
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#app-features' Appendix A, <em>Features</em>
+ |to find a complete list of features.
+ """
+
+ Scenario: Create a short cross reference to a numbered appendix
+ Given the AsciiDoc source
+ """
+ :sectnums:
+ :xrefstyle: short
+
+ See <<app-features>> to find a complete list of features.
+
+ [appendix#app-features]
+ == Features
+
+ All the features are listed in this appendix.
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#app-features' Appendix A
+ |to find a complete list of features.
+ """
+
+ Scenario: Create a full cross reference to an appendix even when section numbering is disabled
+ Given the AsciiDoc source
+ """
+ :xrefstyle: full
+
+ See <<app-features>> to find a complete list of features.
+
+ [appendix#app-features]
+ == Features
+
+ All the features are listed in this appendix.
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#app-features' Appendix A, <em>Features</em>
+ |to find a complete list of features.
+ """
+
+ Scenario: Create a full cross reference to a numbered formal block
+ Given the AsciiDoc source
+ """
+ :xrefstyle: full
+
+ See <<tbl-features>> to find a table of features.
+
+ .Features
+ [#tbl-features%autowidth]
+ |===
+ |Text formatting |Formats text for display.
+ |===
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#tbl-features' Table 1, &#8220;Features&#8221;
+ |to find a table of features.
+ """
+
+ Scenario: Create a short cross reference to a numbered formal block
+ Given the AsciiDoc source
+ """
+ :xrefstyle: short
+
+ See <<tbl-features>> to find a table of features.
+
+ .Features
+ [#tbl-features%autowidth]
+ |===
+ |Text formatting |Formats text for display.
+ |===
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#tbl-features' Table 1
+ |to find a table of features.
+ """
+
+ Scenario: Create a basic cross reference to a numbered formal block when the caption prefix is disabled
+ Given the AsciiDoc source
+ """
+ :xrefstyle: full
+ :!table-caption:
+
+ See <<tbl-features>> to find a table of features.
+
+ .Features
+ [#tbl-features%autowidth]
+ |===
+ |Text formatting |Formats text for display.
+ |===
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#tbl-features' Features
+ |to find a table of features.
+ """
+
+ Scenario: Create a cross reference to a numbered formal block with a custom caption prefix
+ Given the AsciiDoc source
+ """
+ :xrefstyle: full
+ :table-caption: Tbl
+
+ See <<tbl-features>> to find a table of features.
+
+ .Features
+ [#tbl-features%autowidth]
+ |===
+ |Text formatting |Formats text for display.
+ |===
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#tbl-features' Tbl 1, &#8220;Features&#8221;
+ |to find a table of features.
+ """
+
+ Scenario: Create a full cross reference to a formal image block
+ Given the AsciiDoc source
+ """
+ :xrefstyle: full
+
+ Behold, <<tiger>>!
+
+ .The ferocious Ghostscript tiger
+ [#tiger]
+ image::tiger.svg[Ghostscript tiger]
+ """
+ When it is converted to html
+ Then the result should match the HTML structure
+ """
+ .paragraph: p
+ |Behold,
+ a< href='#tiger' Figure 1, &#8220;The ferocious Ghostscript tiger&#8221;
+ |!
+ #tiger.imageblock
+ .content: img src='tiger.svg' alt='Ghostscript tiger'
+ .title Figure 1. The ferocious Ghostscript tiger
+ """
+
+ Scenario: Create a short cross reference to a formal image block
+ Given the AsciiDoc source
+ """
+ :xrefstyle: short
+
+ Behold, <<tiger>>!
+
+ .The ferocious Ghostscript tiger
+ [#tiger]
+ image::tiger.svg[Ghostscript tiger]
+ """
+ When it is converted to html
+ Then the result should match the HTML structure
+ """
+ .paragraph: p
+ |Behold,
+ a< href='#tiger' Figure 1
+ |!
+ #tiger.imageblock
+ .content: img src='tiger.svg' alt='Ghostscript tiger'
+ .title Figure 1. The ferocious Ghostscript tiger
+ """
+
+ Scenario: Create a full cross reference to a block with an explicit caption
+ Given the AsciiDoc source
+ """
+ :xrefstyle: full
+
+ See <<diagram-1>> and <<diagram-2>>.
+
+ .Managing Orders
+ [#diagram-1,caption="Diagram {counter:diag-number}. "]
+ image::managing-orders.png[Managing Orders]
+
+ .Managing Inventory
+ [#diagram-2,caption="Diagram {counter:diag-number}. "]
+ image::managing-inventory.png[Managing Inventory]
+ """
+ When it is converted to html
+ Then the result should match the HTML structure
+ """
+ .paragraph: p
+ |See
+ a<> href='#diagram-1' Diagram 1, &#8220;Managing Orders&#8221;
+ |and
+ a< href='#diagram-2' Diagram 2, &#8220;Managing Inventory&#8221;
+ |.
+ #diagram-1.imageblock
+ .content: img src='managing-orders.png' alt='Managing Orders'
+ .title Diagram 1. Managing Orders
+ #diagram-2.imageblock
+ .content: img src='managing-inventory.png' alt='Managing Inventory'
+ .title Diagram 2. Managing Inventory
+ """
+
+ Scenario: Create a short cross reference to a block with an explicit caption
+ Given the AsciiDoc source
+ """
+ :xrefstyle: short
+
+ See <<diagram-1>> and <<diagram-2>>.
+
+ .Managing Orders
+ [#diagram-1,caption="Diagram {counter:diag-number}. "]
+ image::managing-orders.png[Managing Orders]
+
+ .Managing Inventory
+ [#diagram-2,caption="Diagram {counter:diag-number}. "]
+ image::managing-inventory.png[Managing Inventory]
+ """
+ When it is converted to html
+ Then the result should match the HTML structure
+ """
+ .paragraph: p
+ |See
+ a<> href='#diagram-1' Diagram 1
+ |and
+ a< href='#diagram-2' Diagram 2
+ |.
+ #diagram-1.imageblock
+ .content: img src='managing-orders.png' alt='Managing Orders'
+ .title Diagram 1. Managing Orders
+ #diagram-2.imageblock
+ .content: img src='managing-inventory.png' alt='Managing Inventory'
+ .title Diagram 2. Managing Inventory
+ """
+
+ Scenario: Create a basic cross reference to an unnumbered formal block
+ Given the AsciiDoc source
+ """
+ :xrefstyle: full
+
+ See <<data>> to find the data used in this report.
+
+ .Data
+ [#data]
+ ....
+ a
+ b
+ c
+ ....
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |See
+ a<> href='#data' Data
+ |to find the data used in this report.
+ """
+
+ Scenario: Use title as cross reference text to refer to a formal admonition block
+ Given the AsciiDoc source
+ """
+ :xrefstyle: full
+
+ Recall in <<essential-tip-1>>, we told you how to speed up this process.
+
+ .Essential tip #1
+ [#essential-tip-1]
+ TIP: You can speed up this process by pressing the turbo button.
+ """
+ When it is converted to html
+ Then the result should contain the HTML structure
+ """
+ |Recall in
+ a< href='#essential-tip-1' Essential tip #1
+ |, we told you how to speed up this process.
+ """
Scenario: Create a cross reference from an AsciiDoc cell to a section
Given the AsciiDoc source
@@ -27,15 +585,14 @@ Feature: Cross References
td.tableblock.halign-left.valign-top
div
.paragraph: p
- 'See
- a href='#_install' Install
+ |See
+ a< href='#_install' Install
.sect1
h2#_install Install
.sectionbody
.paragraph: p Instructions go here.
"""
-
Scenario: Create a cross reference using the target section title
Given the AsciiDoc source
"""
@@ -56,12 +613,11 @@ Feature: Cross References
.sect1
h2#_section_two Section Two
.sectionbody: .paragraph: p
- 'refer to
- a href='#_section_one' Section One
+ |refer to
+ a< href='#_section_one' Section One
"""
-
- Scenario: Create a cross reference using the target reftext
+ Scenario: Create a natural cross reference using the reftext of the target section
Given the AsciiDoc source
"""
[reftext="the first section"]
@@ -82,10 +638,21 @@ Feature: Cross References
.sect1
h2#_section_two Section Two
.sectionbody: .paragraph: p
- 'refer to
- a href='#_section_one' the first section
+ |refer to
+ a< href='#_section_one' the first section
+ """
+ When it is converted to docbook
+ Then the result should match the XML structure
+ """
+ section xml:id='_section_one' xreflabel='the first section'
+ title Section One
+ simpara content
+ section xml:id='_section_two'
+ title Section Two
+ simpara
+ |refer to
+ xref< linkend='_section_one'/
"""
-
Scenario: Create a cross reference using the formatted target title
Given the AsciiDoc source
@@ -103,14 +670,11 @@ Feature: Cross References
"""
.sect1
h2#_section_strong_one_strong
- 'Section
- strong One
+ |Section <strong>One</strong>
.sectionbody: .paragraph: p content
.sect1
h2#_section_two Section Two
.sectionbody: .paragraph: p
- 'refer to
- a href='#_section_strong_one_strong'
- 'Section
- strong One
+ |refer to
+ a< href='#_section_strong_one_strong' Section <strong>One</strong>
"""
diff --git a/lib/asciidoctor/abstract_block.rb b/lib/asciidoctor/abstract_block.rb
index 26d4f57d..610259d7 100644
--- a/lib/asciidoctor/abstract_block.rb
+++ b/lib/asciidoctor/abstract_block.rb
@@ -161,6 +161,60 @@ class AbstractBlock < AbstractNode
end
end
+ # Public: A convenience method that checks if the reftext attribute is defined.
+ def reftext?
+ @attributes.key? 'reftext'
+ end
+
+ # Public: A convenience method that returns the value of the reftext attribute with substitutions applied.
+ def reftext
+ (val = @attributes['reftext']) ? (apply_reftext_subs val) : nil
+ end
+
+ # Public: Generate cross reference text (xreftext) that can be used to refer
+ # to this block.
+ #
+ # Use the explicit reftext for this block, if specified, retrieved from the
+ # {#reftext} method. Otherwise, if this is a section or captioned block (a
+ # block with both a title and caption, excluding admonitions), generate the
+ # xreftext according to the value of the xrefstyle argument (e.g., full,
+ # short). This logic may leverage the {Substitutors#sub_quotes} method to
+ # apply formatting to the text. If this is not a captioned block, return the
+ # title, if present, or nil otherwise.
+ #
+ # xrefstyle - An optional String that specifies the style to use to format
+ # the xreftext ('full', 'short', or 'basic') (default: nil).
+ #
+ # Returns the generated [String] xreftext used to refer to this block or
+ # nothing if there isn't sufficient information to generate one.
+ def xreftext xrefstyle = nil
+ if (val = reftext) && !val.empty?
+ val
+ # NOTE xrefstyle only applies to blocks with a title and a caption or number
+ # FIXME admonition blocks misuse the caption property, so exclude for now
+ elsif xrefstyle && @title && @caption && (type = @context) != :admonition
+ case xrefstyle
+ when 'full'
+ quoted_title = sprintf sub_quotes(@document.compat_mode ? %q(``%s'') : '"`%s`"'), title
+ if @number && (prefix = @document.attributes[type == :image ? 'figure-caption' : %(#{type}-caption)])
+ %(#{prefix} #{@number}, #{quoted_title})
+ else
+ %(#{@caption.chomp '. '}, #{quoted_title})
+ end
+ when 'short'
+ if @number && (prefix = @document.attributes[type == :image ? 'figure-caption' : %(#{type}-caption)])
+ %(#{prefix} #{@number})
+ else
+ @caption.chomp '. '
+ end
+ else # 'basic'
+ title
+ end
+ else
+ title
+ end
+ end
+
# Public: Determine whether this Block contains block content
#
# Returns A Boolean indicating whether this Block has block content
@@ -379,10 +433,10 @@ class AbstractBlock < AbstractNode
@next_section_index = (section.index = @next_section_index) + 1
if (sectname = section.sectname) == 'appendix'
section.number = @document.counter 'appendix-number', 'A'
- if (caption = @document.attr 'appendix-caption').nil_or_empty?
- section.caption = %(#{section.number}. )
- else
+ if (caption = @document.attributes['appendix-caption'])
section.caption = %(#{caption} #{section.number}: )
+ else
+ section.caption = %(#{section.number}. )
end
# NOTE currently chapters in a book doctype are sequential even for multi-part books (see #979)
elsif sectname == 'chapter'
diff --git a/lib/asciidoctor/abstract_node.rb b/lib/asciidoctor/abstract_node.rb
index caebd3eb..dec3e479 100644
--- a/lib/asciidoctor/abstract_node.rb
+++ b/lib/asciidoctor/abstract_node.rb
@@ -249,16 +249,6 @@ class AbstractNode
end
end
- # Public: A convenience method that checks if the reftext attribute is specified
- def reftext?
- @attributes.key?('reftext') || @document.attributes.key?('reftext')
- end
-
- # Public: A convenience method that returns the value of the reftext attribute
- def reftext
- @attributes['reftext'] || @document.attributes['reftext']
- end
-
# Public: Construct a reference or data URI to an icon image for the
# specified icon name.
#
diff --git a/lib/asciidoctor/attribute_list.rb b/lib/asciidoctor/attribute_list.rb
index 465d7b17..5f772058 100644
--- a/lib/asciidoctor/attribute_list.rb
+++ b/lib/asciidoctor/attribute_list.rb
@@ -165,7 +165,7 @@ class AttributeList
else
if single_quoted_value && @block
case name
- when 'title'
+ when 'title', 'reftext'
@attributes[name] = value
else
@attributes[name] = @block.apply_subs value
diff --git a/lib/asciidoctor/converter/docbook5.rb b/lib/asciidoctor/converter/docbook5.rb
index 3d5ebd99..24cf17cf 100644
--- a/lib/asciidoctor/converter/docbook5.rb
+++ b/lib/asciidoctor/converter/docbook5.rb
@@ -508,7 +508,7 @@ module Asciidoctor
def inline_anchor node
case node.type
when :ref
- %(<anchor#{common_attributes node.target, nil, node.text || %([#{node.target}])}/>)
+ %(<anchor#{common_attributes node.target, nil, node.reftext || %([#{node.target}])}/>)
when :xref
if (path = node.attributes['path'])
# QUESTION should we use refid as fallback text instead? (like the html5 backend?)
@@ -661,10 +661,16 @@ module Asciidoctor
end
def common_attributes id, role = nil, reftext = nil
- res = id ? %( xml:id="#{id}") : ''
- res = %(#{res} role="#{role}") if role
- res = %(#{res} xreflabel="#{reftext}") if reftext
- res
+ attrs = id ? %( xml:id="#{id}") : ''
+ attrs = %(#{attrs} role="#{role}") if role
+ if reftext
+ if (reftext.include? '<') && ((reftext = reftext.gsub XmlSanitizeRx, '').include? ' ')
+ reftext = (reftext.squeeze ' ').strip
+ end
+ reftext = (reftext.gsub '"', '&quot;') if reftext.include? '"'
+ attrs = %(#{attrs} xreflabel="#{reftext}")
+ end
+ attrs
end
def doctype_declaration root_tag_name
diff --git a/lib/asciidoctor/converter/html5.rb b/lib/asciidoctor/converter/html5.rb
index a0fd632a..4fac077d 100644
--- a/lib/asciidoctor/converter/html5.rb
+++ b/lib/asciidoctor/converter/html5.rb
@@ -1025,27 +1025,28 @@ Your browser does not support the video tag.
end
def inline_anchor node
- target = node.target
case node.type
when :xref
- refid = node.attributes['refid'] || target
- # NOTE we lookup text in converter because DocBook doesn't need this logic
- text = node.text || node.document.catalog[:ids][refid] || %([#{refid}])
- # FIXME shouldn't target be refid? logic seems confused here
- %(<a href="#{target}">#{text}</a>)
+ unless (text = node.text)
+ if AbstractNode === (ref = node.document.catalog[:refs][refid = node.attributes['refid']])
+ text = ref.xreftext((@xrefstyle ||= node.document.attributes['xrefstyle'])) || %([#{refid}])
+ else
+ text = %([#{refid}])
+ end
+ end
+ %(<a href="#{node.target}">#{text}</a>)
when :ref
- %(<a id="#{target}"></a>)
+ %(<a id="#{node.target}"></a>)
when :link
- attrs = []
- attrs << %( id="#{node.id}") if node.id
+ attrs = node.id ? [%( id="#{node.id}")] : []
if (role = node.role)
attrs << %( class="#{role}")
end
attrs << %( title="#{node.attr 'title'}") if node.attr? 'title', nil, false
attrs << %( target="#{window = node.attr 'window'}"#{window == '_blank' || (node.option? 'noopener') ? ' rel="noopener"' : ''}) if node.attr? 'window', nil, false
- %(<a href="#{target}"#{attrs.join}>#{node.text}</a>)
+ %(<a href="#{node.target}"#{attrs.join}>#{node.text}</a>)
when :bibref
- %(<a id="#{target}"></a>#{node.text})
+ %(<a id="#{node.target}"></a>#{node.text})
else
warn %(asciidoctor: WARNING: unknown anchor type: #{node.type.inspect})
end
diff --git a/lib/asciidoctor/document.rb b/lib/asciidoctor/document.rb
index b322e370..97e2e081 100644
--- a/lib/asciidoctor/document.rb
+++ b/lib/asciidoctor/document.rb
@@ -206,6 +206,7 @@ class Document < AbstractBlock
@parent_document = nil
@catalog = {
:ids => {},
+ :refs => {},
:footnotes => [],
:links => [],
:images => [],
@@ -285,7 +286,6 @@ class Document < AbstractBlock
attrs['note-caption'] = 'Note'
attrs['tip-caption'] = 'Tip'
attrs['warning-caption'] = 'Warning'
- attrs['appendix-caption'] = 'Appendix'
attrs['example-caption'] = 'Example'
attrs['figure-caption'] = 'Figure'
#attrs['listing-caption'] = 'Listing'
@@ -293,6 +293,10 @@ class Document < AbstractBlock
attrs['toc-title'] = 'Table of Contents'
#attrs['preface-title'] = 'Preface'
attrs['manname-title'] = 'NAME'
+ attrs['section-refsig'] = 'Section'
+ #attrs['part-refsig'] = 'Part'
+ attrs['chapter-refsig'] = 'Chapter'
+ attrs['appendix-caption'] = attrs['appendix-refsig'] = 'Appendix'
attrs['untitled-label'] = 'Untitled'
attrs['version-label'] = 'Version'
attrs['last-update-label'] = 'Last updated'
@@ -557,9 +561,15 @@ class Document < AbstractBlock
def register type, value
case type
- when :ids
+ when :ids # deprecated
id, reftext = value
- @catalog[:ids][id] ||= (reftext || '[' + id + ']')
+ @catalog[:ids][id] ||= reftext || ('[' + id + ']')
+ when :refs
+ id, ref, reftext = value
+ unless (refs = @catalog[:refs]).key? id
+ refs[id] = ref
+ @catalog[:ids][id] = reftext || ('[' + id + ']')
+ end
when :footnotes, :indexterms
@catalog[type] << value
else
diff --git a/lib/asciidoctor/inline.rb b/lib/asciidoctor/inline.rb
index f2677e51..5b84d307 100644
--- a/lib/asciidoctor/inline.rb
+++ b/lib/asciidoctor/inline.rb
@@ -47,5 +47,27 @@ class Inline < AbstractNode
def alt
attr 'alt'
end
+
+ def reftext?
+ @text && (@type == :ref || @type == :bibref)
+ end
+
+ def reftext
+ (val = @text) ? (apply_reftext_subs val) : nil
+ end
+
+ # Public: Generate cross reference text (xreftext) that can be used to refer
+ # to this inline node.
+ #
+ # Use the explicit reftext for this inline node, if specified, retrieved by
+ # calling the reftext method. Otherwise, returns nil.
+ #
+ # xrefstyle - Not currently used (default: nil).
+ #
+ # Returns the [String] reftext to refer to this inline node or nothing if no
+ # reftext is defined.
+ def xreftext xrefstyle = nil
+ reftext
+ end
end
end
diff --git a/lib/asciidoctor/parser.rb b/lib/asciidoctor/parser.rb
index 8e1e0d39..b020ce0f 100644
--- a/lib/asciidoctor/parser.rb
+++ b/lib/asciidoctor/parser.rb
@@ -631,7 +631,7 @@ class Parser
block = next_item_list(reader, :ulist, parent)
if (style || (Section === parent && parent.sectname)) == 'bibliography'
attributes['style'] = 'bibliography' unless style
- block.items.each {|item| catalog_inline_biblio_anchor item.instance_variable_get(:@text), document }
+ block.items.each {|item| catalog_inline_biblio_anchor item.instance_variable_get(:@text), item, document }
end
break
@@ -726,8 +726,6 @@ class Parser
return
end
- catalog_inline_anchors lines * LF, document
-
# NOTE don't check indented here since it's extremely rare
#if text_only || indented
if text_only
@@ -768,6 +766,8 @@ class Parser
adjust_indentation! lines if indented && style == 'normal'
block = Block.new(parent, :paragraph, :content_model => :simple, :source => lines, :attributes => attributes)
end
+
+ catalog_inline_anchors lines * LF, block, document
end
break # forbid loop from executing more than once
@@ -904,16 +904,16 @@ class Parser
block.source_location = source_location if source_location
# FIXME title should have already been assigned
block.title = attributes.delete 'title' if attributes.key? 'title'
+ #unless attributes.key? 'reftext'
+ # attributes['reftext'] = document.attributes['reftext'] if document.attributes.key? 'reftext'
+ #end
# FIXME caption should have already been assigned
block.caption ||= attributes.delete 'caption'
# TODO eventually remove the style attribute from the attributes hash
#block.style = attributes.delete 'style'
block.style = attributes['style']
- # AsciiDoc Python always use [id] as the reftext in HTML output,
- # but I'd like to do better in Asciidoctor
if (block_id = (block.id ||= attributes['id']))
- # TODO sub reftext
- document.register(:ids, [block_id, (attributes['reftext'] || (block.title? ? block.title : nil))])
+ document.register :refs, [block_id, block, attributes['reftext'] || (block.title? ? block.title : nil)]
end
# FIXME remove the need for this update!
block.attributes.update(attributes) unless attributes.empty?
@@ -1192,36 +1192,42 @@ class Parser
found
end
- # Internal: Catalog any inline anchors found in the text, but don't process them
+ # Internal: Catalog any inline anchors found in the text (but don't convert)
#
# text - The String text in which to look for inline anchors
- # document - The current document in which the references are stored
+ # block - The block in which the references should be searched
+ # document - The current Document on which the references are stored
#
# Returns nothing
- def self.catalog_inline_anchors text, document
+ def self.catalog_inline_anchors text, block, document
text.scan(InlineAnchorScanRx) do
if (id = $1)
- reftext = $2
+ if (reftext = $2)
+ next if (reftext.include? '{') && (reftext = document.sub_attributes reftext).empty?
+ end
else
id = $3
- if (reftext = $4) && (reftext.include? ']')
- reftext = reftext.gsub '\]', ']'
+ if (reftext = $4)
+ reftext = reftext.gsub '\]', ']' if reftext.include? ']'
+ next if (reftext.include? '{') && (reftext = document.sub_attributes reftext).empty?
end
end
- document.register :ids, [id, reftext]
+ document.register :refs, [id, (Inline.new block, :anchor, reftext, :type => :ref, :target => id), reftext]
end if (text.include? '[[') || (text.include? 'or:')
nil
end
- # Internal: Catalog any bibliography inline anchors found in the text, but don't process them
+ # Internal: Catalog the bibliography inline anchor found in the start of the list item (but don't convert)
#
- # text - The String text in which to look for inline bibliography anchors
- # document - The current document in which the references are stored
+ # text - The String text in which to look for an inline bibliography anchor
+ # block - The ListItem block in which the reference should be searched
+ # document - The current document in which the reference is stored
#
# Returns nothing
- def self.catalog_inline_biblio_anchor text, document
+ def self.catalog_inline_biblio_anchor text, block, document
if InlineBiblioAnchorRx =~ text
- document.register :ids, [$1, %([#{$2 || $1}])]
+ # QUESTION should we sub attributes in reftext (like with regular anchors)?
+ document.register :refs, [(id = $1), (Inline.new block, :anchor, (reftext = %([#{$2 || id}])), :type => :bibref, :target => id), reftext]
end
nil
end
@@ -1562,6 +1568,8 @@ class Parser
attributes['reftext'] = sect_reftext
elsif attributes.key? 'reftext'
sect_reftext = attributes['reftext']
+ #elsif document.attributes.key? 'reftext'
+ # sect_reftext = attributes['reftext'] = document.attributes['reftext']
end
# parse style, id, and role attributes from first positional attribute if present
@@ -1602,8 +1610,7 @@ class Parser
# generate an ID if one was not embedded or specified as anchor above section title
if (id = section.id ||= (attributes['id'] ||
((document.attributes.key? 'sectids') ? (Section.generate_id section.title, document) : nil)))
- # TODO sub reftext
- document.register :ids, [id, sect_reftext || section.title]
+ document.register :refs, [id, section, sect_reftext || section.title]
end
section.update_attributes(attributes)
@@ -2013,11 +2020,11 @@ class Parser
if next_line.start_with? '['
if next_line.start_with? '[['
if (next_line.end_with? ']]') && BlockAnchorRx =~ next_line
+ # NOTE registration of id and reftext is deferred until block is processed
attributes['id'] = $1
- # AsciiDoc Python always uses [id] as the reftext in HTML output,
- # but I'd like to do better in Asciidoctor
- # registration is deferred until the block or section is processed
- attributes['reftext'] = $2 if $2
+ if (reftext = $2)
+ attributes['reftext'] = (reftext.include? '{') ? (document.sub_attributes reftext) : reftext
+ end
return true
end
elsif (next_line.end_with? ']') && BlockAttributeListRx =~ next_line
diff --git a/lib/asciidoctor/section.rb b/lib/asciidoctor/section.rb
index a37621f3..14854c6d 100644
--- a/lib/asciidoctor/section.rb
+++ b/lib/asciidoctor/section.rb
@@ -107,6 +107,41 @@ class Section < AbstractBlock
end
end
+ # (see AbstractBlock#xreftext)
+ def xreftext xrefstyle = nil
+ if (val = reftext) && !val.empty?
+ val
+ elsif xrefstyle
+ if @numbered
+ case xrefstyle
+ when 'full'
+ if (type = @sectname) == 'chapter' || type == 'appendix'
+ quoted_title = sprintf sub_quotes('_%s_'), title
+ else
+ quoted_title = sprintf sub_quotes(@document.compat_mode ? %q(``%s'') : '"`%s`"'), title
+ end
+ if (signifier = @document.attributes[%(#{type}-refsig)])
+ %(#{signifier} #{sectnum '.', ','} #{quoted_title})
+ else
+ %(#{sectnum '.', ','} #{quoted_title})
+ end
+ when 'short'
+ if (signifier = @document.attributes[%(#{@sectname}-refsig)])
+ %(#{signifier} #{sectnum '.', ''})
+ else
+ sectnum '.', ''
+ end
+ else # 'basic'
+ (type = @sectname) == 'chapter' || type == 'appendix' ? (sprintf sub_quotes('_%s_'), title) : title
+ end
+ else # apply basic styling
+ (type = @sectname) == 'chapter' || type == 'appendix' ? (sprintf sub_quotes('_%s_'), title) : title
+ end
+ else
+ title
+ end
+ end
+
# Public: Append a content block to this block's list of blocks.
#
# If the child block is a Section, assign an index to it.
diff --git a/lib/asciidoctor/substitutors.rb b/lib/asciidoctor/substitutors.rb
index f27c70f7..eb286d88 100644
--- a/lib/asciidoctor/substitutors.rb
+++ b/lib/asciidoctor/substitutors.rb
@@ -12,6 +12,7 @@ module Substitutors
(NORMAL_SUBS = [:specialcharacters, :quotes, :attributes, :replacements, :macros, :post_replacements]).freeze
(NONE_SUBS = []).freeze
(TITLE_SUBS = [:specialcharacters, :quotes, :replacements, :macros, :attributes, :post_replacements]).freeze
+ (REFTEXT_SUBS = [:specialcharacters, :quotes, :replacements]).freeze
(VERBATIM_SUBS = [:specialcharacters, :callouts]).freeze
SUB_GROUPS = {
@@ -153,6 +154,15 @@ module Substitutors
apply_subs title, TITLE_SUBS
end
+ # Public: Apply substitutions for reftext.
+ #
+ # text - The String to process
+ #
+ # Returns a String with all substitutions from the reftext substitution group applied
+ def apply_reftext_subs text
+ apply_subs text, REFTEXT_SUBS
+ end
+
# Public: Apply substitutions for header metadata and attribute assignments
#
# text - String containing the text process
@@ -972,8 +982,10 @@ module Substitutors
id, reftext = id.split ',', 2
reftext = reftext.lstrip if reftext
else
- id, reftext = m[2], m[3]
- reftext = reftext.gsub ESC_R_SB, R_SB if reftext && (reftext.include? R_SB)
+ id = m[2]
+ if (reftext = m[3]) && (reftext.include? R_SB)
+ reftext = reftext.gsub ESC_R_SB, R_SB
+ end
end
if (hash_idx = id.index '#')
diff --git a/test/blocks_test.rb b/test/blocks_test.rb
index 8a5b4e01..d4b78e92 100644
--- a/test/blocks_test.rb
+++ b/test/blocks_test.rb
@@ -3238,6 +3238,25 @@ $ apt-get install asciidoctor
assert_equal 'Debian, Ubuntu', reftext
end
+ test 'should substitute attribute references in reftext when registering block reference' do
+ input = <<-EOS
+:label-tiger: Tiger
+
+[[tiger-evolution,Evolution of the {label-tiger}]]
+****
+Information about the evolution of the tiger.
+****
+ EOS
+
+ doc = document_from_string input
+ reftext = doc.catalog[:ids]['tiger-evolution']
+ refute_nil reftext
+ assert_equal 'Evolution of the Tiger', reftext
+ ref = doc.catalog[:refs]['tiger-evolution']
+ refute_nil ref
+ assert_equal 'Evolution of the Tiger', ref.attributes['reftext']
+ end
+
test 'should use specified reftext when registering block reference' do
input = <<-EOS
[[debian]]
diff --git a/test/document_test.rb b/test/document_test.rb
index 76c22169..eaebf2be 100644
--- a/test/document_test.rb
+++ b/test/document_test.rb
@@ -1761,7 +1761,7 @@ content{blank}footnote:[commentary]
doc = document_from_string input
refute_nil doc.catalog
- assert_equal [:footnotes, :ids, :images, :includes, :indexterms, :links].to_set, doc.catalog.keys.to_set
+ assert_equal [:footnotes, :ids, :images, :includes, :indexterms, :links, :refs].to_set, doc.catalog.keys.to_set
assert_same doc.catalog, doc.references
assert_same doc.catalog[:footnotes], doc.references[:footnotes]
assert_same doc.catalog[:ids], doc.references[:ids]
diff --git a/test/links_test.rb b/test/links_test.rb
index 14671646..267b472f 100644
--- a/test/links_test.rb
+++ b/test/links_test.rb
@@ -238,11 +238,24 @@ context 'Links' do
doc = document_from_string %(Here you can read about tigers.#{anchor})
output = doc.render
assert_equal '[tigers]', doc.catalog[:ids]['tigers']
+ assert doc.catalog[:refs]['tigers'].is_a? Asciidoctor::Inline
+ assert_nil doc.catalog[:refs]['tigers'].text
assert_xpath '//a[@id = "tigers"]', output, 1
assert_xpath '//a[@id = "tigers"]/child::text()', output, 0
end
end
+ test 'escaped inline ref' do
+ variations = %w([[tigers]] anchor:tigers[])
+ variations.each do |anchor|
+ doc = document_from_string %(Here you can read about tigers.\\#{anchor})
+ output = doc.render
+ refute doc.catalog[:ids].key?('tigers')
+ refute doc.catalog[:refs].key?('tigers')
+ assert_xpath '//a[@id = "tigers"]', output, 0
+ end
+ end
+
test 'inline ref can start with colon' do
input = '[[:idname]] text'
output = render_embedded_string input
@@ -257,29 +270,48 @@ context 'Links' do
end
test 'inline ref with reftext' do
- variations = %w([[tigers,Tigers]] anchor:tigers[Tigers])
- variations.each do |anchor|
+ %w([[tigers,Tigers]] anchor:tigers[Tigers]).each do |anchor|
doc = document_from_string %(Here you can read about tigers.#{anchor})
output = doc.render
assert_equal 'Tigers', doc.catalog[:ids]['tigers']
+ assert doc.catalog[:refs]['tigers'].is_a? Asciidoctor::Inline
+ assert_equal 'Tigers', doc.catalog[:refs]['tigers'].text
assert_xpath '//a[@id = "tigers"]', output, 1
assert_xpath '//a[@id = "tigers"]/child::text()', output, 0
end
end
- test 'escaped inline ref' do
- variations = %w([[tigers]] anchor:tigers[])
- variations.each do |anchor|
- doc = document_from_string %(Here you can read about tigers.\\#{anchor})
- output = doc.render
- assert !doc.catalog[:ids].has_key?('tigers')
- assert_xpath '//a[@id = "tigers"]', output, 0
+ test 'should encode double quotes in reftext of anchor macro in DocBook output' do
+ input = 'anchor:uncola[the "un"-cola]'
+ result = render_inline_string input, :backend => :docbook
+ assert_equal '<anchor xml:id="uncola" xreflabel="the &quot;un&quot;-cola"/>', result
+ end
+
+ test 'should substitute attribute references in reftext when registering inline ref' do
+ %w([[tigers,{label-tigers}]] anchor:tigers[{label-tigers}]).each do |anchor|
+ doc = document_from_string %(Here you can read about tigers.#{anchor}), :attributes => { 'label-tigers' => 'Tigers' }
+ doc.render
+ assert doc.catalog[:refs]['tigers'].is_a? Asciidoctor::Inline
+ assert_equal 'Tigers', doc.catalog[:refs]['tigers'].text
+ assert_equal 'Tigers', doc.catalog[:ids]['tigers']
+ end
+ end
+
+ test 'inline ref with reftext converted to DocBook' do
+ %w([[tigers,<Tigers>]] anchor:tigers[<Tigers>]).each do |anchor|
+ doc = document_from_string %(Here you can read about tigers.#{anchor}), :backend => :docbook45
+ output = doc.convert :header_footer => false
+ assert doc.catalog[:refs]['tigers'].is_a? Asciidoctor::Inline
+ assert_equal '<Tigers>', doc.catalog[:refs]['tigers'].text
+ assert_equal '<Tigers>', doc.references[:ids]['tigers']
+ assert_includes output, '<anchor id="tigers" xreflabel="&lt;Tigers&gt;"/>'
end
end
test 'does not match bibliography anchor in prose when scanning for inline anchor' do
doc = document_from_string 'Use [[[label]]] to assign a label to a bibliography entry.'
refute doc.catalog[:ids].key?('label')
+ refute doc.catalog[:refs].key?('label')
end
test 'repeating inline anchor macro with empty reftext' do
@@ -300,6 +332,14 @@ context 'Links' do
assert_equal '<anchor xml:id="foo" xreflabel="[foo]"/>', result
end
+ test 'unescapes square bracket in reftext of anchor macro' do
+ input = 'see <<foo>>
+
+anchor:foo[b[a\]r]text'
+ result = render_embedded_string input
+ assert_includes result, 'see <a href="#foo">b[a]r</a>'
+ end
+
test 'unescapes square bracket in reftext of anchor macro in DocBook output' do
input = 'anchor:foo[b[a\]r]'
result = render_inline_string input, :backend => :docbook
@@ -308,13 +348,13 @@ context 'Links' do
test 'xref using angled bracket syntax' do
doc = document_from_string '<<tigers>>'
- doc.catalog[:ids]['tigers'] = '[tigers]'
+ doc.register :refs, ['tigers', (Asciidoctor::Inline.new doc, :anchor, '[tigers]', :type => :ref, :target => 'tigers'), '[tigers]']
assert_xpath '//a[@href="#tigers"][text() = "[tigers]"]', doc.render, 1
end
test 'xref using angled bracket syntax with explicit hash' do
doc = document_from_string '<<#tigers>>'
- doc.catalog[:ids]['tigers'] = 'Tigers'
+ doc.register :refs, ['tigers', (Asciidoctor::Inline.new doc, :anchor, 'Tigers', :type => :ref, :target => 'tigers'), 'Tigers']
assert_xpath '//a[@href="#tigers"][text() = "Tigers"]', doc.render, 1
end
@@ -455,13 +495,13 @@ A summary of the first lesson.
test 'xref using macro syntax' do
doc = document_from_string 'xref:tigers[]'
- doc.catalog[:ids]['tigers'] = '[tigers]'
+ doc.register :refs, ['tigers', (Asciidoctor::Inline.new doc, :anchor, '[tigers]', :type => :ref, :target => 'tigers'), '[tigers]']
assert_xpath '//a[@href="#tigers"][text() = "[tigers]"]', doc.render, 1
end
test 'xref using macro syntax with explicit hash' do
doc = document_from_string 'xref:#tigers[]'
- doc.catalog[:ids]['tigers'] = 'Tigers'
+ doc.register :refs, ['tigers', (Asciidoctor::Inline.new doc, :anchor, 'Tigers', :type => :ref, :target => 'tigers'), 'Tigers']
assert_xpath '//a[@href="#tigers"][text() = "Tigers"]', doc.render, 1
end
@@ -518,7 +558,7 @@ see <<foo>>'
test 'xref using invalid macro syntax does not create link' do
doc = document_from_string 'xref:tigers'
- doc.catalog[:ids]['tigers'] = '[tigers]'
+ doc.register :refs, ['tigers', (Asciidoctor::Inline.new doc, :anchor, 'Tigers', :type => :ref, :target => 'tigers'), 'Tigers']
assert_xpath '//a', doc.render, 0
end
diff --git a/test/sections_test.rb b/test/sections_test.rb
index 84304598..318456dc 100644
--- a/test/sections_test.rb
+++ b/test/sections_test.rb
@@ -190,6 +190,22 @@ content
assert_equal 'Install Procedure', reftext
end
+ test 'should substitute attributes when registering reftext for section' do
+ input = <<-EOS
+:platform-name: Linux
+
+[[install,install on {platform-name}]]
+== Install
+
+content
+ EOS
+
+ doc = document_from_string input
+ reftext = doc.catalog[:ids]['install']
+ refute_nil reftext
+ assert_equal 'install on Linux', reftext
+ end
+
test 'duplicate section id should not overwrite existing section id entry in references table' do
input = <<-EOS
[#install]
@@ -1367,10 +1383,10 @@ Details
assert_xpath '//h2[text()="App A: Attribute Options"]', output, 1
end
- test 'should only assign letter to appendix when numbered is enabled and appendix caption is empty' do
+ test 'should only assign letter to appendix when numbered is enabled and appendix caption is not set' do
input = <<-EOS
:numbered:
-:appendix-caption:
+:!appendix-caption:
[appendix]
== Attribute Options
diff --git a/test/substitutions_test.rb b/test/substitutions_test.rb
index d6362e9e..3f5e6a75 100644
--- a/test/substitutions_test.rb
+++ b/test/substitutions_test.rb
@@ -914,8 +914,9 @@ context 'Substitutions' do
test 'a footnote macro may contain an xref macro' do
# specialcharacters escaping is simulated
para = block_from_string('text footnote:[&lt;&lt;_install,install&gt;&gt;]')
- catalog = para.document.catalog
- catalog[:ids]['_install'] = 'Install'
+ doc = para.document
+ doc.register :refs, ['_install', (Asciidoctor::Inline.new doc, :anchor, 'Install', :type => :ref, :target => '_install'), 'Install']
+ catalog = doc.catalog
assert_equal %(text <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnote_1" title="View footnote.">1</a>]</sup>), para.sub_macros(para.source)
assert_equal 1, catalog[:footnotes].size
footnote1 = catalog[:footnotes][0]