diff options
| author | Dan Allen <dan.j.allen@gmail.com> | 2017-07-09 19:12:14 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-07-09 19:12:14 -0600 |
| commit | 8e80317dee56483e48a07451bff0cd14f0bfd59c (patch) | |
| tree | c46c4c14367b574328abbed4c38cdb334caccf88 | |
| parent | c4b4d10c218093b46a8efecaf4f7969864ae3461 (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.adoc | 137 | ||||
| -rw-r--r-- | features/xref.feature | 600 | ||||
| -rw-r--r-- | lib/asciidoctor/abstract_block.rb | 60 | ||||
| -rw-r--r-- | lib/asciidoctor/abstract_node.rb | 10 | ||||
| -rw-r--r-- | lib/asciidoctor/attribute_list.rb | 2 | ||||
| -rw-r--r-- | lib/asciidoctor/converter/docbook5.rb | 16 | ||||
| -rw-r--r-- | lib/asciidoctor/converter/html5.rb | 23 | ||||
| -rw-r--r-- | lib/asciidoctor/document.rb | 16 | ||||
| -rw-r--r-- | lib/asciidoctor/inline.rb | 22 | ||||
| -rw-r--r-- | lib/asciidoctor/parser.rb | 57 | ||||
| -rw-r--r-- | lib/asciidoctor/section.rb | 35 | ||||
| -rw-r--r-- | lib/asciidoctor/substitutors.rb | 16 | ||||
| -rw-r--r-- | test/blocks_test.rb | 19 | ||||
| -rw-r--r-- | test/document_test.rb | 2 | ||||
| -rw-r--r-- | test/links_test.rb | 68 | ||||
| -rw-r--r-- | test/sections_test.rb | 20 | ||||
| -rw-r--r-- | test/substitutions_test.rb | 5 |
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 "<T>" 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 "<T>" thing' + title Parameterized Type <T> + simpara This sidebar describes what that <T> 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, “Features” + |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, “Features” + |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, “Features” + |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, “Features” + |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, “The ferocious Ghostscript tiger” + |! + #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, “Managing Orders” + |and + a< href='#diagram-2' Diagram 2, “Managing Inventory” + |. + #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 '"', '"') 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 "un"-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="<Tigers>"/>' 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:[<<_install,install>>]') - 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] |
