asciidoctor 1.5.8 → 2.0.0.rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +162 -17
- data/LICENSE +1 -1
- data/README-de.adoc +12 -13
- data/README-fr.adoc +11 -12
- data/README-jp.adoc +11 -12
- data/README-zh_CN.adoc +12 -13
- data/README.adoc +6 -7
- data/asciidoctor.gemspec +19 -24
- data/bin/asciidoctor +5 -4
- data/data/reference/syntax.adoc +283 -0
- data/data/stylesheets/asciidoctor-default.css +56 -52
- data/data/stylesheets/coderay-asciidoctor.css +7 -9
- data/lib/asciidoctor.rb +171 -232
- data/lib/asciidoctor/abstract_block.rb +96 -105
- data/lib/asciidoctor/abstract_node.rb +118 -139
- data/lib/asciidoctor/attribute_list.rb +10 -14
- data/lib/asciidoctor/block.rb +20 -19
- data/lib/asciidoctor/callouts.rb +4 -2
- data/lib/asciidoctor/cli.rb +3 -2
- data/lib/asciidoctor/cli/invoker.rb +14 -21
- data/lib/asciidoctor/cli/options.rb +64 -54
- data/lib/asciidoctor/converter.rb +357 -185
- data/lib/asciidoctor/converter/composite.rb +40 -48
- data/lib/asciidoctor/converter/docbook5.rb +604 -640
- data/lib/asciidoctor/converter/html5.rb +949 -963
- data/lib/asciidoctor/converter/manpage.rb +569 -548
- data/lib/asciidoctor/converter/template.rb +231 -272
- data/lib/asciidoctor/core_ext.rb +5 -18
- data/lib/asciidoctor/core_ext/float/truncate.rb +19 -0
- data/lib/asciidoctor/core_ext/match_data/names.rb +7 -0
- data/lib/asciidoctor/core_ext/nil_or_empty.rb +1 -0
- data/lib/asciidoctor/core_ext/regexp/is_match.rb +4 -2
- data/lib/asciidoctor/document.rb +399 -377
- data/lib/asciidoctor/extensions.rb +72 -140
- data/lib/asciidoctor/helpers.rb +122 -83
- data/lib/asciidoctor/inline.rb +5 -1
- data/lib/asciidoctor/list.rb +13 -11
- data/lib/asciidoctor/logging.rb +17 -16
- data/lib/asciidoctor/parser.rb +390 -423
- data/lib/asciidoctor/path_resolver.rb +10 -5
- data/lib/asciidoctor/reader.rb +286 -263
- data/lib/asciidoctor/rouge_ext.rb +39 -0
- data/lib/asciidoctor/section.rb +9 -8
- data/lib/asciidoctor/stylesheets.rb +19 -37
- data/lib/asciidoctor/substitutors.rb +364 -509
- data/lib/asciidoctor/syntax_highlighter.rb +238 -0
- data/lib/asciidoctor/syntax_highlighter/coderay.rb +87 -0
- data/lib/asciidoctor/syntax_highlighter/highlightjs.rb +26 -0
- data/lib/asciidoctor/syntax_highlighter/html_pipeline.rb +10 -0
- data/lib/asciidoctor/syntax_highlighter/prettify.rb +27 -0
- data/lib/asciidoctor/syntax_highlighter/pygments.rb +149 -0
- data/lib/asciidoctor/syntax_highlighter/rouge.rb +129 -0
- data/lib/asciidoctor/table.rb +73 -66
- data/lib/asciidoctor/timings.rb +4 -2
- data/lib/asciidoctor/version.rb +2 -1
- data/lib/asciidoctor/writer.rb +30 -0
- data/man/asciidoctor.1 +19 -15
- data/man/asciidoctor.adoc +14 -12
- metadata +69 -216
- data/CONTRIBUTING.adoc +0 -185
- data/Gemfile +0 -60
- data/Rakefile +0 -129
- data/bin/asciidoctor-safe +0 -15
- data/features/open_block.feature +0 -92
- data/features/pass_block.feature +0 -66
- data/features/step_definitions.rb +0 -49
- data/features/text_formatting.feature +0 -57
- data/features/xref.feature +0 -1039
- data/lib/asciidoctor/converter/base.rb +0 -59
- data/lib/asciidoctor/converter/docbook45.rb +0 -93
- data/lib/asciidoctor/converter/factory.rb +0 -226
- data/lib/asciidoctor/core_ext/1.8.7/base64/strict_encode64.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/concurrent/hash.rb +0 -5
- data/lib/asciidoctor/core_ext/1.8.7/hash/key.rb +0 -4
- data/lib/asciidoctor/core_ext/1.8.7/io/binread.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/io/write.rb +0 -5
- data/lib/asciidoctor/core_ext/1.8.7/string/chr.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/string/limit_bytesize.rb +0 -29
- data/lib/asciidoctor/core_ext/1.8.7/symbol/empty.rb +0 -6
- data/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb +0 -6
- data/lib/asciidoctor/core_ext/string/limit_bytesize.rb +0 -10
- data/test/api_test.rb +0 -1240
- data/test/attribute_list_test.rb +0 -242
- data/test/attributes_test.rb +0 -1623
- data/test/blocks_test.rb +0 -3870
- data/test/converter_test.rb +0 -470
- data/test/document_test.rb +0 -1853
- data/test/extensions_test.rb +0 -1560
- data/test/fixtures/asciidoc_index.txt +0 -521
- data/test/fixtures/basic-docinfo-footer.html +0 -6
- data/test/fixtures/basic-docinfo-footer.xml +0 -8
- data/test/fixtures/basic-docinfo.html +0 -1
- data/test/fixtures/basic-docinfo.xml +0 -4
- data/test/fixtures/basic.asciidoc +0 -5
- data/test/fixtures/chapter-a.adoc +0 -3
- data/test/fixtures/child-include.adoc +0 -5
- data/test/fixtures/circle.svg +0 -9
- data/test/fixtures/custom-backends/erb/html5/block_paragraph.html.erb +0 -6
- data/test/fixtures/custom-backends/haml/docbook45/block_paragraph.xml.haml +0 -6
- data/test/fixtures/custom-backends/haml/html5-tweaks/block_paragraph.html.haml +0 -1
- data/test/fixtures/custom-backends/haml/html5/block_paragraph.html.haml +0 -3
- data/test/fixtures/custom-backends/haml/html5/block_sidebar.html.haml +0 -5
- data/test/fixtures/custom-backends/slim/docbook45/block_paragraph.xml.slim +0 -6
- data/test/fixtures/custom-backends/slim/html5/block_paragraph.html.slim +0 -3
- data/test/fixtures/custom-backends/slim/html5/block_sidebar.html.slim +0 -5
- data/test/fixtures/custom-docinfodir/basic-docinfo.html +0 -1
- data/test/fixtures/custom-docinfodir/docinfo.html +0 -1
- data/test/fixtures/docinfo-footer.html +0 -1
- data/test/fixtures/docinfo-footer.xml +0 -9
- data/test/fixtures/docinfo.html +0 -1
- data/test/fixtures/docinfo.xml +0 -3
- data/test/fixtures/doctime-localtime.adoc +0 -2
- data/test/fixtures/dot.gif +0 -0
- data/test/fixtures/encoding.asciidoc +0 -13
- data/test/fixtures/file-with-missing-include.adoc +0 -1
- data/test/fixtures/grandchild-include.adoc +0 -3
- data/test/fixtures/hello-asciidoctor.pdf +0 -69
- data/test/fixtures/include-file.asciidoc +0 -24
- data/test/fixtures/include-file.jsx +0 -8
- data/test/fixtures/include-file.ml +0 -3
- data/test/fixtures/include-file.xml +0 -5
- data/test/fixtures/lists.adoc +0 -96
- data/test/fixtures/master.adoc +0 -5
- data/test/fixtures/mismatched-end-tag.adoc +0 -7
- data/test/fixtures/other-chapters.adoc +0 -11
- data/test/fixtures/outer-include.adoc +0 -5
- data/test/fixtures/parent-include-restricted.adoc +0 -5
- data/test/fixtures/parent-include.adoc +0 -5
- data/test/fixtures/sample.asciidoc +0 -30
- data/test/fixtures/section-a.adoc +0 -4
- data/test/fixtures/stylesheets/custom.css +0 -3
- data/test/fixtures/subdir/index.adoc +0 -3
- data/test/fixtures/subdir/inner-include.adoc +0 -3
- data/test/fixtures/subdir/middle-include.adoc +0 -5
- data/test/fixtures/subs-docinfo.html +0 -2
- data/test/fixtures/subs.adoc +0 -6
- data/test/fixtures/tagged-class-enclosed.rb +0 -25
- data/test/fixtures/tagged-class.rb +0 -23
- data/test/fixtures/tip.gif +0 -0
- data/test/fixtures/unclosed-tag.adoc +0 -3
- data/test/fixtures/unexpected-end-tag.adoc +0 -4
- data/test/invoker_test.rb +0 -745
- data/test/links_test.rb +0 -855
- data/test/lists_test.rb +0 -5151
- data/test/logger_test.rb +0 -211
- data/test/manpage_test.rb +0 -660
- data/test/options_test.rb +0 -262
- data/test/paragraphs_test.rb +0 -562
- data/test/parser_test.rb +0 -742
- data/test/paths_test.rb +0 -395
- data/test/preamble_test.rb +0 -173
- data/test/reader_test.rb +0 -2161
- data/test/sections_test.rb +0 -3575
- data/test/substitutions_test.rb +0 -2066
- data/test/tables_test.rb +0 -2036
- data/test/test_helper.rb +0 -447
- data/test/text_test.rb +0 -309
@@ -1,132 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Asciidoctor
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
#
|
30
|
-
# str - the String to convert
|
31
|
-
# opts - an Hash of options to control processing (default: {})
|
32
|
-
# * :whitespace an enum that indicates how to handle whitespace; supported options are:
|
33
|
-
# :preserve - preserve spaces (only expanding tabs); :normalize - normalize whitespace
|
34
|
-
# (remove spaces around newlines); :collapse - collapse adjacent whitespace to a single
|
35
|
-
# space (default: :collapse)
|
36
|
-
# * :append_newline a Boolean that indicates whether to append an endline to the result (default: false)
|
37
|
-
def manify str, opts = {}
|
38
|
-
case opts.fetch :whitespace, :collapse
|
39
|
-
when :preserve
|
40
|
-
str = str.gsub TAB, ET
|
41
|
-
when :normalize
|
42
|
-
str = str.gsub WrappedIndentRx, LF
|
43
|
-
else
|
44
|
-
str = str.tr_s WHITESPACE, ' '
|
45
|
-
end
|
46
|
-
str = str.
|
47
|
-
gsub(LiteralBackslashRx, '\&(rs'). # literal backslash (not a troff escape sequence)
|
48
|
-
gsub(LeadingPeriodRx, '\\\&.'). # leading . is used in troff for macro call or other formatting; replace with \&.
|
49
|
-
# drop orphaned \c escape lines, unescape troff macro, quote adjacent character, isolate macro line
|
50
|
-
gsub(EscapedMacroRx) { (rest = $3.lstrip).empty? ? %(.#$1"#$2") : %(.#$1"#$2"#{LF}#{rest}) }.
|
51
|
-
gsub('-', '\-').
|
52
|
-
gsub('<', '<').
|
53
|
-
gsub('>', '>').
|
54
|
-
gsub(' ', '\~'). # non-breaking space
|
55
|
-
gsub('©', '\(co'). # copyright sign
|
56
|
-
gsub('®', '\(rg'). # registered sign
|
57
|
-
gsub('™', '\(tm'). # trademark sign
|
58
|
-
gsub(' ', ' '). # thin space
|
59
|
-
gsub('–', '\(en'). # en dash
|
60
|
-
gsub(EmDashCharRefRx, '\(em'). # em dash
|
61
|
-
gsub('‘', '\(oq'). # left single quotation mark
|
62
|
-
gsub('’', '\(cq'). # right single quotation mark
|
63
|
-
gsub('“', '\(lq'). # left double quotation mark
|
64
|
-
gsub('”', '\(rq'). # right double quotation mark
|
65
|
-
gsub(EllipsisCharRefRx, '...'). # horizontal ellipsis
|
66
|
-
gsub('←', '\(<-'). # leftwards arrow
|
67
|
-
gsub('→', '\(->'). # rightwards arrow
|
68
|
-
gsub('⇐', '\(lA'). # leftwards double arrow
|
69
|
-
gsub('⇒', '\(rA'). # rightwards double arrow
|
70
|
-
gsub('​', '\:'). # zero width space
|
71
|
-
gsub('&','&'). # literal ampersand (NOTE must take place after any other replacement that includes &)
|
72
|
-
gsub('\'', '\(aq'). # apostrophe-quote
|
73
|
-
gsub(MockBoundaryRx, ''). # mock boundary
|
74
|
-
gsub(ESC_BS, '\\'). # unescape troff backslash (NOTE update if more escapes are added)
|
75
|
-
gsub(ESC_FS, '.'). # unescape full stop in troff commands (NOTE must take place after gsub(LeadingPeriodRx))
|
76
|
-
rstrip # strip trailing space
|
77
|
-
opts[:append_newline] ? %(#{str}#{LF}) : str
|
78
|
-
end
|
79
|
-
|
80
|
-
def skip_with_warning node, name = nil
|
81
|
-
logger.warn %(converter missing for #{name || node.node_name} node in manpage backend)
|
82
|
-
nil
|
83
|
-
end
|
3
|
+
# A built-in {Converter} implementation that generates the man page (troff) format.
|
4
|
+
#
|
5
|
+
# The output follows the groff man page definition while also trying to be
|
6
|
+
# consistent with the output produced by the a2x tool from AsciiDoc Python.
|
7
|
+
#
|
8
|
+
# See http://www.gnu.org/software/groff/manual/html_node/Man-usage.html#Man-usage
|
9
|
+
class Converter::ManPageConverter < Converter::Base
|
10
|
+
register_for 'manpage'
|
11
|
+
|
12
|
+
WHITESPACE = %(#{LF}#{TAB} )
|
13
|
+
ET = ' ' * 8
|
14
|
+
ESC = ?\u001b # troff leader marker
|
15
|
+
ESC_BS = %(#{ESC}\\) # escaped backslash (indicates troff formatting sequence)
|
16
|
+
ESC_FS = %(#{ESC}.) # escaped full stop (indicates troff macro)
|
17
|
+
|
18
|
+
LiteralBackslashRx = /(?:\A|[^#{ESC}])\\/
|
19
|
+
LeadingPeriodRx = /^\./
|
20
|
+
EscapedMacroRx = /^(?:#{ESC}\\c\n)?#{ESC}\.((?:URL|MTO) ".*?" ".*?" )( |[^\s]*)(.*?)(?: *#{ESC}\\c)?$/
|
21
|
+
MockBoundaryRx = /<\/?BOUNDARY>/
|
22
|
+
EmDashCharRefRx = /—(?:​)?/
|
23
|
+
EllipsisCharRefRx = /…(?:​)?/
|
24
|
+
WrappedIndentRx = /#{CG_BLANK}*#{LF}#{CG_BLANK}*/
|
25
|
+
|
26
|
+
def initialize backend, opts = {}
|
27
|
+
@backend = backend
|
28
|
+
init_backend_traits basebackend: 'manpage', filetype: 'man', outfilesuffix: '.man', supports_templates: true
|
29
|
+
end
|
84
30
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
31
|
+
def document node
|
32
|
+
unless node.attr? 'mantitle'
|
33
|
+
raise 'asciidoctor: ERROR: doctype must be set to manpage when using manpage backend'
|
34
|
+
end
|
35
|
+
mantitle = node.attr 'mantitle'
|
36
|
+
manvolnum = node.attr 'manvolnum', '1'
|
37
|
+
manname = node.attr 'manname', mantitle
|
38
|
+
manmanual = node.attr 'manmanual'
|
39
|
+
mansource = node.attr 'mansource'
|
40
|
+
docdate = (node.attr? 'reproducible') ? nil : (node.attr 'docdate')
|
41
|
+
# NOTE the first line enables the table (tbl) preprocessor, necessary for non-Linux systems
|
42
|
+
result = [%('\\" t
|
97
43
|
.\\" Title: #{mantitle}
|
98
44
|
.\\" Author: #{(node.attr? 'authors') ? (node.attr 'authors') : '[see the "AUTHOR(S)" section]'}
|
99
45
|
.\\" Generator: Asciidoctor #{node.attr 'asciidoctor-version'})]
|
100
|
-
|
101
|
-
|
46
|
+
result << %(.\\" Date: #{docdate}) if docdate
|
47
|
+
result << %(.\\" Manual: #{manmanual ? (manmanual.tr_s WHITESPACE, ' ') : '\ \&'}
|
102
48
|
.\\" Source: #{mansource ? (mansource.tr_s WHITESPACE, ' ') : '\ \&'}
|
103
49
|
.\\" Language: English
|
104
50
|
.\\")
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
51
|
+
# TODO add document-level setting to disable capitalization of manname
|
52
|
+
result << %(.TH "#{_manify manname.upcase}" "#{manvolnum}" "#{docdate}" "#{mansource ? (_manify mansource) : '\ \&'}" "#{manmanual ? (_manify manmanual) : '\ \&'}")
|
53
|
+
# define portability settings
|
54
|
+
# see http://bugs.debian.org/507673
|
55
|
+
# see http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
|
56
|
+
result << '.ie \n(.g .ds Aq \(aq'
|
57
|
+
result << '.el .ds Aq \''
|
58
|
+
# set sentence_space_size to 0 to prevent extra space between sentences separated by a newline
|
59
|
+
# the alternative is to add \& at the end of the line
|
60
|
+
result << '.ss \n[.ss] 0'
|
61
|
+
# disable hyphenation
|
62
|
+
result << '.nh'
|
63
|
+
# disable justification (adjust text to left margin only)
|
64
|
+
result << '.ad l'
|
65
|
+
# define URL macro for portability
|
66
|
+
# see http://web.archive.org/web/20060102165607/http://people.debian.org/~branden/talks/wtfm/wtfm.pdf
|
67
|
+
#
|
68
|
+
# Usage
|
69
|
+
#
|
70
|
+
# .URL "http://www.debian.org" "Debian" "."
|
71
|
+
#
|
72
|
+
# * First argument: the URL
|
73
|
+
# * Second argument: text to be hyperlinked
|
74
|
+
# * Third (optional) argument: text that needs to immediately trail the hyperlink without intervening whitespace
|
75
|
+
result << '.de URL
|
130
76
|
\\fI\\\\$2\\fP <\\\\$1>\\\\$3
|
131
77
|
..
|
132
78
|
.als MTO URL
|
@@ -138,192 +84,208 @@ module Asciidoctor
|
|
138
84
|
. am MTO
|
139
85
|
. ad l
|
140
86
|
. .'
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
#{mannames.map {|n|
|
149
|
-
end
|
87
|
+
result << %(. LINKSTYLE #{node.attr 'man-linkstyle', 'blue R < >'})
|
88
|
+
result << '.\}'
|
89
|
+
|
90
|
+
unless node.noheader
|
91
|
+
if node.attr? 'manpurpose'
|
92
|
+
mannames = node.attr 'mannames', [manname]
|
93
|
+
result << %(.SH "#{(node.attr 'manname-title', 'NAME').upcase}"
|
94
|
+
#{mannames.map {|n| _manify n }.join ', '} \\- #{_manify node.attr('manpurpose'), whitespace: :normalize})
|
150
95
|
end
|
96
|
+
end
|
151
97
|
|
152
|
-
|
98
|
+
result << node.content
|
153
99
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
100
|
+
# QUESTION should NOTES come after AUTHOR(S)?
|
101
|
+
if node.footnotes? && !(node.attr? 'nofootnotes')
|
102
|
+
result << '.SH "NOTES"'
|
103
|
+
result.concat(node.footnotes.map {|fn| %(#{fn.index}. #{fn.text}) })
|
104
|
+
end
|
159
105
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
106
|
+
unless (authors = node.authors).empty?
|
107
|
+
if authors.size > 1
|
108
|
+
result << '.SH "AUTHORS"'
|
109
|
+
authors.each do |author|
|
110
|
+
result << %(.sp
|
165
111
|
#{author.name})
|
166
|
-
|
167
|
-
|
168
|
-
|
112
|
+
end
|
113
|
+
else
|
114
|
+
result << %(.SH "AUTHOR"
|
169
115
|
.sp
|
170
116
|
#{authors[0].name})
|
171
|
-
end
|
172
117
|
end
|
173
|
-
|
174
|
-
result.join LF
|
175
118
|
end
|
176
119
|
|
177
|
-
|
178
|
-
|
179
|
-
result = [node.content]
|
180
|
-
|
181
|
-
if node.footnotes? && !(node.attr? 'nofootnotes')
|
182
|
-
result << '.SH "NOTES"'
|
183
|
-
result.concat(node.footnotes.map {|fn| %(#{fn.index}. #{fn.text}) })
|
184
|
-
end
|
120
|
+
result.join LF
|
121
|
+
end
|
185
122
|
|
186
|
-
|
123
|
+
# NOTE embedded doesn't really make sense in the manpage backend
|
124
|
+
def embedded node
|
125
|
+
result = [node.content]
|
187
126
|
|
188
|
-
|
127
|
+
if node.footnotes? && !(node.attr? 'nofootnotes')
|
128
|
+
result << '.SH "NOTES"'
|
129
|
+
result.concat(node.footnotes.map {|fn| %(#{fn.index}. #{fn.text}) })
|
189
130
|
end
|
190
131
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
132
|
+
# QUESTION should we add an AUTHOR(S) section?
|
133
|
+
|
134
|
+
result.join LF
|
135
|
+
end
|
136
|
+
|
137
|
+
def section node
|
138
|
+
result = []
|
139
|
+
if node.level > 1
|
140
|
+
macro = 'SS'
|
141
|
+
# QUESTION why captioned title? why not when level == 1?
|
142
|
+
stitle = node.captioned_title
|
143
|
+
else
|
144
|
+
macro = 'SH'
|
145
|
+
stitle = node.title.upcase
|
146
|
+
end
|
147
|
+
result << %(.#{macro} "#{_manify stitle}"
|
202
148
|
#{node.content})
|
203
|
-
|
204
|
-
|
149
|
+
result.join LF
|
150
|
+
end
|
205
151
|
|
206
|
-
|
207
|
-
|
208
|
-
|
152
|
+
def admonition node
|
153
|
+
result = []
|
154
|
+
result << %(.if n .sp
|
209
155
|
.RS 4
|
210
156
|
.it 1 an-trap
|
211
157
|
.nr an-no-space-flag 1
|
212
158
|
.nr an-break-flag 1
|
213
159
|
.br
|
214
160
|
.ps +1
|
215
|
-
.B #{node.attr 'textlabel'}#{node.title? ? "\\fP: #{
|
161
|
+
.B #{node.attr 'textlabel'}#{node.title? ? "\\fP: #{_manify node.title}" : ''}
|
216
162
|
.ps -1
|
217
163
|
.br
|
218
|
-
#{
|
164
|
+
#{_enclose_content node}
|
219
165
|
.sp .5v
|
220
166
|
.RE)
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
alias audio skip_with_warning
|
167
|
+
result.join LF
|
168
|
+
end
|
225
169
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
.B #{
|
170
|
+
def colist node
|
171
|
+
result = []
|
172
|
+
result << %(.sp
|
173
|
+
.B #{_manify node.title}
|
230
174
|
.br) if node.title?
|
231
|
-
|
175
|
+
result << '.TS
|
232
176
|
tab(:);
|
233
177
|
r lw(\n(.lu*75u/100u).'
|
234
178
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
end
|
242
|
-
result << '.TE'
|
243
|
-
result.join LF
|
179
|
+
num = 0
|
180
|
+
node.items.each do |item|
|
181
|
+
result << %(\\fB(#{num += 1})\\fP\\h'-2n':T{)
|
182
|
+
result << (_manify item.text, whitespace: :normalize)
|
183
|
+
result << item.content if item.blocks?
|
184
|
+
result << 'T}'
|
244
185
|
end
|
186
|
+
result << '.TE'
|
187
|
+
result.join LF
|
188
|
+
end
|
245
189
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
.B #{
|
190
|
+
# TODO implement horizontal (if it makes sense)
|
191
|
+
def dlist node
|
192
|
+
result = []
|
193
|
+
result << %(.sp
|
194
|
+
.B #{_manify node.title}
|
251
195
|
.br) if node.title?
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
#{counter}. #{
|
196
|
+
counter = 0
|
197
|
+
node.items.each do |terms, dd|
|
198
|
+
counter += 1
|
199
|
+
case node.style
|
200
|
+
when 'qanda'
|
201
|
+
result << %(.sp
|
202
|
+
#{counter}. #{_manify terms.map {|dt| dt.text }.join ' '}
|
259
203
|
.RS 4)
|
260
|
-
|
261
|
-
|
262
|
-
#{
|
204
|
+
else
|
205
|
+
result << %(.sp
|
206
|
+
#{_manify terms.map {|dt| dt.text }.join(', '), whitespace: :normalize}
|
263
207
|
.RS 4)
|
264
|
-
end
|
265
|
-
if dd
|
266
|
-
result << (manify dd.text, :whitespace => :normalize) if dd.text?
|
267
|
-
result << dd.content if dd.blocks?
|
268
|
-
end
|
269
|
-
result << '.RE'
|
270
208
|
end
|
271
|
-
|
209
|
+
if dd
|
210
|
+
result << (_manify dd.text, whitespace: :normalize) if dd.text?
|
211
|
+
result << dd.content if dd.blocks?
|
212
|
+
end
|
213
|
+
result << '.RE'
|
272
214
|
end
|
215
|
+
result.join LF
|
216
|
+
end
|
273
217
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
.B #{
|
278
|
-
.br)
|
279
|
-
|
280
|
-
#{
|
218
|
+
def example node
|
219
|
+
result = []
|
220
|
+
result << (node.title? ? %(.sp
|
221
|
+
.B #{_manify node.captioned_title}
|
222
|
+
.br) : '.sp')
|
223
|
+
result << %(.RS 4
|
224
|
+
#{_enclose_content node}
|
281
225
|
.RE)
|
282
|
-
|
283
|
-
|
226
|
+
result.join LF
|
227
|
+
end
|
284
228
|
|
285
|
-
|
286
|
-
|
287
|
-
|
229
|
+
def floating_title node
|
230
|
+
%(.SS "#{_manify node.title}")
|
231
|
+
end
|
288
232
|
|
289
|
-
|
233
|
+
def image node
|
234
|
+
result = []
|
235
|
+
result << (node.title? ? %(.sp
|
236
|
+
.B #{_manify node.captioned_title}
|
237
|
+
.br) : '.sp')
|
238
|
+
result << %([#{node.alt}])
|
239
|
+
result.join LF
|
240
|
+
end
|
290
241
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
.B #{
|
242
|
+
def listing node
|
243
|
+
result = []
|
244
|
+
result << %(.sp
|
245
|
+
.B #{_manify node.captioned_title}
|
295
246
|
.br) if node.title?
|
296
|
-
|
247
|
+
result << %(.sp
|
297
248
|
.if n .RS 4
|
298
249
|
.nf
|
299
|
-
#{
|
250
|
+
#{_manify node.content, whitespace: :preserve}
|
300
251
|
.fi
|
301
252
|
.if n .RE)
|
302
|
-
|
303
|
-
|
253
|
+
result.join LF
|
254
|
+
end
|
304
255
|
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
.B #{
|
256
|
+
def literal node
|
257
|
+
result = []
|
258
|
+
result << %(.sp
|
259
|
+
.B #{_manify node.title}
|
309
260
|
.br) if node.title?
|
310
|
-
|
261
|
+
result << %(.sp
|
311
262
|
.if n .RS 4
|
312
263
|
.nf
|
313
|
-
#{
|
264
|
+
#{_manify node.content, whitespace: :preserve}
|
314
265
|
.fi
|
315
266
|
.if n .RE)
|
316
|
-
|
317
|
-
|
267
|
+
result.join LF
|
268
|
+
end
|
318
269
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
.B #{
|
270
|
+
def sidebar node
|
271
|
+
result = []
|
272
|
+
result << (node.title? ? %(.sp
|
273
|
+
.B #{_manify node.title}
|
274
|
+
.br) : '.sp')
|
275
|
+
result << %(.RS 4
|
276
|
+
#{_enclose_content node}
|
277
|
+
.RE)
|
278
|
+
result.join LF
|
279
|
+
end
|
280
|
+
|
281
|
+
def olist node
|
282
|
+
result = []
|
283
|
+
result << %(.sp
|
284
|
+
.B #{_manify node.title}
|
323
285
|
.br) if node.title?
|
324
286
|
|
325
|
-
|
326
|
-
|
287
|
+
node.items.each_with_index do |item, idx|
|
288
|
+
result << %(.sp
|
327
289
|
.RS 4
|
328
290
|
.ie n \\{\\
|
329
291
|
\\h'-04' #{idx + 1}.\\h'+01'\\c
|
@@ -332,226 +294,223 @@ r lw(\n(.lu*75u/100u).'
|
|
332
294
|
. sp -1
|
333
295
|
. IP " #{idx + 1}." 4.2
|
334
296
|
.\\}
|
335
|
-
#{
|
336
|
-
|
337
|
-
|
338
|
-
end
|
339
|
-
result.join LF
|
297
|
+
#{_manify item.text, whitespace: :normalize})
|
298
|
+
result << item.content if item.blocks?
|
299
|
+
result << '.RE'
|
340
300
|
end
|
301
|
+
result.join LF
|
302
|
+
end
|
341
303
|
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
end
|
304
|
+
def open node
|
305
|
+
case node.style
|
306
|
+
when 'abstract', 'partintro'
|
307
|
+
_enclose_content node
|
308
|
+
else
|
309
|
+
node.content
|
349
310
|
end
|
311
|
+
end
|
350
312
|
|
351
|
-
|
352
|
-
|
313
|
+
# TODO use Page Control https://www.gnu.org/software/groff/manual/html_node/Page-Control.html#Page-Control
|
314
|
+
alias page_break _skip
|
353
315
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
.B #{
|
316
|
+
def paragraph node
|
317
|
+
if node.title?
|
318
|
+
%(.sp
|
319
|
+
.B #{_manify node.title}
|
358
320
|
.br
|
359
|
-
#{
|
360
|
-
|
361
|
-
|
362
|
-
#{
|
363
|
-
end
|
321
|
+
#{_manify node.content, whitespace: :normalize})
|
322
|
+
else
|
323
|
+
%(.sp
|
324
|
+
#{_manify node.content, whitespace: :normalize})
|
364
325
|
end
|
326
|
+
end
|
365
327
|
|
366
|
-
|
328
|
+
alias pass _content_only
|
329
|
+
alias preamble _content_only
|
367
330
|
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
331
|
+
def quote node
|
332
|
+
result = []
|
333
|
+
if node.title?
|
334
|
+
result << %(.sp
|
372
335
|
.RS 3
|
373
|
-
.B #{
|
336
|
+
.B #{_manify node.title}
|
374
337
|
.br
|
375
338
|
.RE)
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
339
|
+
end
|
340
|
+
attribution_line = (node.attr? 'citetitle') ? %(#{node.attr 'citetitle'} ) : nil
|
341
|
+
attribution_line = (node.attr? 'attribution') ? %[#{attribution_line}\\(em #{node.attr 'attribution'}] : nil
|
342
|
+
result << %(.RS 3
|
380
343
|
.ll -.6i
|
381
|
-
#{
|
344
|
+
#{_enclose_content node}
|
382
345
|
.br
|
383
346
|
.RE
|
384
347
|
.ll)
|
385
|
-
|
386
|
-
|
348
|
+
if attribution_line
|
349
|
+
result << %(.RS 5
|
387
350
|
.ll -.10i
|
388
351
|
#{attribution_line}
|
389
352
|
.RE
|
390
353
|
.ll)
|
391
|
-
end
|
392
|
-
result.join LF
|
393
354
|
end
|
355
|
+
result.join LF
|
356
|
+
end
|
394
357
|
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
.
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
%(#{title_element}#{equation})
|
408
|
-
end
|
358
|
+
def stem node
|
359
|
+
result = []
|
360
|
+
result << (node.title? ? %(.sp
|
361
|
+
.B #{_manify node.title}
|
362
|
+
.br) : '.sp')
|
363
|
+
open, close = BLOCK_MATH_DELIMITERS[node.style.to_sym]
|
364
|
+
if ((equation = node.content).start_with? open) && (equation.end_with? close)
|
365
|
+
equation = equation.slice open.length, equation.length - open.length - close.length
|
366
|
+
end
|
367
|
+
result << %(#{_manify equation, whitespace: :preserve} (#{node.style}))
|
368
|
+
result.join LF
|
369
|
+
end
|
409
370
|
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
371
|
+
# FIXME: The reason this method is so complicated is because we are not
|
372
|
+
# receiving empty(marked) cells when there are colspans or rowspans. This
|
373
|
+
# method has to create a map of all cells and in the case of rowspans
|
374
|
+
# create empty cells as placeholders of the span.
|
375
|
+
# To fix this, asciidoctor needs to provide an API to tell the user if a
|
376
|
+
# given cell is being used as a colspan or rowspan.
|
377
|
+
def table node
|
378
|
+
result = []
|
379
|
+
if node.title?
|
380
|
+
result << %(.sp
|
420
381
|
.it 1 an-trap
|
421
382
|
.nr an-no-space-flag 1
|
422
383
|
.nr an-break-flag 1
|
423
384
|
.br
|
424
|
-
.B #{
|
385
|
+
.B #{_manify node.captioned_title}
|
425
386
|
)
|
426
|
-
|
427
|
-
|
387
|
+
end
|
388
|
+
result << '.TS
|
428
389
|
allbox tab(:);'
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
390
|
+
row_header = []
|
391
|
+
row_text = []
|
392
|
+
row_index = 0
|
393
|
+
node.rows.to_h.each do |tsec, rows|
|
394
|
+
rows.each do |row|
|
395
|
+
row_header[row_index] ||= []
|
396
|
+
row_text[row_index] ||= []
|
397
|
+
# result << LF
|
398
|
+
# l left-adjusted
|
399
|
+
# r right-adjusted
|
400
|
+
# c centered-adjusted
|
401
|
+
# n numerical align
|
402
|
+
# a alphabetic align
|
403
|
+
# s spanned
|
404
|
+
# ^ vertically spanned
|
405
|
+
remaining_cells = row.size
|
406
|
+
row.each_with_index do |cell, cell_index|
|
407
|
+
remaining_cells -= 1
|
408
|
+
row_header[row_index][cell_index] ||= []
|
409
|
+
# Add an empty cell if this is a rowspan cell
|
410
|
+
if row_header[row_index][cell_index] == ['^t']
|
411
|
+
row_text[row_index] << %(T{#{LF}.sp#{LF}T}:)
|
412
|
+
end
|
413
|
+
row_text[row_index] << %(T{#{LF}.sp#{LF})
|
414
|
+
cell_halign = (cell.attr 'halign', 'left').chr
|
415
|
+
if tsec == :head
|
416
|
+
if row_header[row_index].empty? || row_header[row_index][cell_index].empty?
|
417
|
+
row_header[row_index][cell_index] << %(#{cell_halign}tB)
|
418
|
+
else
|
419
|
+
row_header[row_index][cell_index + 1] ||= []
|
420
|
+
row_header[row_index][cell_index + 1] << %(#{cell_halign}tB)
|
451
421
|
end
|
452
|
-
row_text[row_index] << %(
|
453
|
-
|
454
|
-
if
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
elsif tsec == :foot
|
422
|
+
row_text[row_index] << %(#{_manify cell.text, whitespace: :normalize}#{LF})
|
423
|
+
elsif tsec == :body
|
424
|
+
if row_header[row_index].empty? || row_header[row_index][cell_index].empty?
|
425
|
+
row_header[row_index][cell_index] << %(#{cell_halign}t)
|
426
|
+
else
|
427
|
+
row_header[row_index][cell_index + 1] ||= []
|
428
|
+
row_header[row_index][cell_index + 1] << %(#{cell_halign}t)
|
429
|
+
end
|
430
|
+
case cell.style
|
431
|
+
when :asciidoc
|
432
|
+
cell_content = cell.content
|
433
|
+
when :literal
|
434
|
+
cell_content = %(.nf#{LF}#{_manify cell.text, whitespace: :preserve}#{LF}.fi)
|
435
|
+
else
|
436
|
+
cell_content = _manify cell.content.join, whitespace: :normalize
|
437
|
+
end
|
438
|
+
row_text[row_index] << %(#{cell_content}#{LF})
|
439
|
+
elsif tsec == :foot
|
440
|
+
if row_header[row_index].empty? || row_header[row_index][cell_index].empty?
|
441
|
+
row_header[row_index][cell_index] << %(#{cell_halign}tB)
|
442
|
+
else
|
443
|
+
row_header[row_index][cell_index + 1] ||= []
|
444
|
+
row_header[row_index][cell_index + 1] << %(#{cell_halign}tB)
|
445
|
+
end
|
446
|
+
row_text[row_index] << %(#{_manify cell.text, whitespace: :normalize}#{LF})
|
447
|
+
end
|
448
|
+
if cell.colspan && cell.colspan > 1
|
449
|
+
(cell.colspan - 1).times do |i|
|
481
450
|
if row_header[row_index].empty? || row_header[row_index][cell_index].empty?
|
482
|
-
row_header[row_index][cell_index] <<
|
451
|
+
row_header[row_index][cell_index + i] << 'st'
|
483
452
|
else
|
484
|
-
row_header[row_index][cell_index + 1] ||= []
|
485
|
-
row_header[row_index][cell_index + 1] <<
|
486
|
-
end
|
487
|
-
row_text[row_index] << %(#{manify cell.text, :whitespace => :normalize}#{LF})
|
488
|
-
end
|
489
|
-
if cell.colspan && cell.colspan > 1
|
490
|
-
(cell.colspan - 1).times do |i|
|
491
|
-
if row_header[row_index].empty? || row_header[row_index][cell_index].empty?
|
492
|
-
row_header[row_index][cell_index + i] << 'st'
|
493
|
-
else
|
494
|
-
row_header[row_index][cell_index + 1 + i] ||= []
|
495
|
-
row_header[row_index][cell_index + 1 + i] << 'st'
|
496
|
-
end
|
453
|
+
row_header[row_index][cell_index + 1 + i] ||= []
|
454
|
+
row_header[row_index][cell_index + 1 + i] << 'st'
|
497
455
|
end
|
498
456
|
end
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
457
|
+
end
|
458
|
+
if cell.rowspan && cell.rowspan > 1
|
459
|
+
(cell.rowspan - 1).times do |i|
|
460
|
+
row_header[row_index + 1 + i] ||= []
|
461
|
+
if row_header[row_index + 1 + i].empty? || row_header[row_index + 1 + i][cell_index].empty?
|
462
|
+
row_header[row_index + 1 + i][cell_index] ||= []
|
463
|
+
row_header[row_index + 1 + i][cell_index] << '^t'
|
464
|
+
else
|
465
|
+
row_header[row_index + 1 + i][cell_index + 1] ||= []
|
466
|
+
row_header[row_index + 1 + i][cell_index + 1] << '^t'
|
509
467
|
end
|
510
468
|
end
|
511
|
-
if remaining_cells >= 1
|
512
|
-
row_text[row_index] << 'T}:'
|
513
|
-
else
|
514
|
-
row_text[row_index] << %(T}#{LF})
|
515
|
-
end
|
516
469
|
end
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
470
|
+
if remaining_cells >= 1
|
471
|
+
row_text[row_index] << 'T}:'
|
472
|
+
else
|
473
|
+
row_text[row_index] << %(T}#{LF})
|
474
|
+
end
|
475
|
+
end
|
476
|
+
row_index += 1
|
477
|
+
end unless rows.empty?
|
478
|
+
end
|
479
|
+
|
480
|
+
#row_header.each do |row|
|
481
|
+
# result << LF
|
482
|
+
# row.each_with_index do |cell, i|
|
483
|
+
# result << (cell.join ' ')
|
484
|
+
# result << ' ' if row.size > i + 1
|
485
|
+
# end
|
486
|
+
#end
|
487
|
+
# FIXME temporary fix to get basic table to display
|
488
|
+
result << LF
|
489
|
+
result << ('lt ' * row_header[0].size).chop
|
490
|
+
|
491
|
+
result << %(.#{LF})
|
492
|
+
row_text.each do |row|
|
493
|
+
result << row.join
|
494
|
+
end
|
495
|
+
result << %(.TE#{LF}.sp)
|
496
|
+
result.join
|
497
|
+
end
|
539
498
|
|
540
|
-
|
541
|
-
|
499
|
+
def thematic_break node
|
500
|
+
'.sp
|
542
501
|
.ce
|
543
502
|
\l\'\n(.lu*25u/100u\(ap\''
|
544
|
-
|
503
|
+
end
|
545
504
|
|
546
|
-
|
505
|
+
alias toc _skip
|
547
506
|
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
.B #{
|
507
|
+
def ulist node
|
508
|
+
result = []
|
509
|
+
result << %(.sp
|
510
|
+
.B #{_manify node.title}
|
552
511
|
.br) if node.title?
|
553
|
-
|
554
|
-
|
512
|
+
node.items.map do |item|
|
513
|
+
result << %[.sp
|
555
514
|
.RS 4
|
556
515
|
.ie n \\{\\
|
557
516
|
\\h'-04'\\(bu\\h'+03'\\c
|
@@ -560,159 +519,221 @@ allbox tab(:);'
|
|
560
519
|
. sp -1
|
561
520
|
. IP \\(bu 2.3
|
562
521
|
.\\}
|
563
|
-
#{
|
564
|
-
|
565
|
-
|
566
|
-
}
|
567
|
-
result.join LF
|
522
|
+
#{_manify item.text, whitespace: :normalize}]
|
523
|
+
result << item.content if item.blocks?
|
524
|
+
result << '.RE'
|
568
525
|
end
|
526
|
+
result.join LF
|
527
|
+
end
|
569
528
|
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
.
|
576
|
-
.
|
577
|
-
|
578
|
-
|
579
|
-
attribution_line = (node.attr? 'attribution') ? %[#{attribution_line}\\(em #{node.attr 'attribution'}] : nil
|
580
|
-
result << %(.sp
|
529
|
+
# FIXME git uses [verse] for the synopsis; detect this special case
|
530
|
+
def verse node
|
531
|
+
result = []
|
532
|
+
result << (node.title? ? %(.sp
|
533
|
+
.B #{_manify node.title}
|
534
|
+
.br) : '.sp')
|
535
|
+
attribution_line = (node.attr? 'citetitle') ? %(#{node.attr 'citetitle'} ) : nil
|
536
|
+
attribution_line = (node.attr? 'attribution') ? %[#{attribution_line}\\(em #{node.attr 'attribution'}] : nil
|
537
|
+
result << %(.sp
|
581
538
|
.nf
|
582
|
-
#{
|
539
|
+
#{_manify node.content, whitespace: :preserve}
|
583
540
|
.fi
|
584
541
|
.br)
|
585
|
-
|
586
|
-
|
542
|
+
if attribution_line
|
543
|
+
result << %(.in +.5i
|
587
544
|
.ll -.5i
|
588
545
|
#{attribution_line}
|
589
546
|
.in
|
590
547
|
.ll)
|
591
|
-
end
|
592
|
-
result.join LF
|
593
548
|
end
|
549
|
+
result.join LF
|
550
|
+
end
|
594
551
|
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
.B #{
|
601
|
-
.br)
|
602
|
-
|
603
|
-
|
604
|
-
|
552
|
+
def video node
|
553
|
+
start_param = (node.attr? 'start') ? %(&start=#{node.attr 'start'}) : ''
|
554
|
+
end_param = (node.attr? 'end') ? %(&end=#{node.attr 'end'}) : ''
|
555
|
+
result = []
|
556
|
+
result << (node.title? ? %(.sp
|
557
|
+
.B #{_manify node.title}
|
558
|
+
.br) : '.sp')
|
559
|
+
result << %(<#{node.media_uri(node.attr 'target')}#{start_param}#{end_param}> (video))
|
560
|
+
result.join LF
|
561
|
+
end
|
605
562
|
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
563
|
+
def inline_anchor node
|
564
|
+
target = node.target
|
565
|
+
case node.type
|
566
|
+
when :link
|
567
|
+
if target.start_with? 'mailto:'
|
568
|
+
macro = 'MTO'
|
569
|
+
target = target.slice 7, target.length
|
570
|
+
else
|
571
|
+
macro = 'URL'
|
572
|
+
end
|
573
|
+
if (text = node.text) == target
|
574
|
+
text = ''
|
575
|
+
else
|
576
|
+
text = text.gsub '"', %[#{ESC_BS}(dq]
|
577
|
+
end
|
578
|
+
target = target.sub '@', %[#{ESC_BS}(at] if macro == 'MTO'
|
579
|
+
%(#{ESC_BS}c#{LF}#{ESC_FS}#{macro} "#{target}" "#{text}" )
|
580
|
+
when :xref
|
581
|
+
unless (text = node.text)
|
582
|
+
refid = node.attributes['refid']
|
583
|
+
if AbstractNode === (ref = (@refs ||= node.document.catalog[:refs])[refid])
|
584
|
+
text = (ref.xreftext node.attr('xrefstyle', nil, true)) || %([#{refid}])
|
618
585
|
else
|
619
|
-
text =
|
586
|
+
text = %([#{refid}])
|
620
587
|
end
|
621
|
-
target = target.sub '@', %[#{ESC_BS}(at] if macro == 'MTO'
|
622
|
-
%(#{ESC_BS}c#{LF}#{ESC_FS}#{macro} "#{target}" "#{text}" )
|
623
|
-
when :xref
|
624
|
-
refid = (node.attr 'refid') || target
|
625
|
-
node.text || (node.document.catalog[:ids][refid] || %([#{refid}]))
|
626
|
-
when :ref, :bibref
|
627
|
-
# These are anchor points, which shouldn't be visible
|
628
|
-
''
|
629
|
-
else
|
630
|
-
logger.warn %(unknown anchor type: #{node.type.inspect})
|
631
|
-
nil
|
632
588
|
end
|
589
|
+
text
|
590
|
+
when :ref, :bibref
|
591
|
+
# These are anchor points, which shouldn't be visible
|
592
|
+
''
|
593
|
+
else
|
594
|
+
logger.warn %(unknown anchor type: #{node.type.inspect})
|
595
|
+
nil
|
633
596
|
end
|
597
|
+
end
|
634
598
|
|
635
|
-
|
636
|
-
|
637
|
-
|
599
|
+
def inline_break node
|
600
|
+
%(#{node.text}#{LF}#{ESC_FS}br)
|
601
|
+
end
|
638
602
|
|
639
|
-
|
640
|
-
|
641
|
-
|
603
|
+
def inline_button node
|
604
|
+
%(#{ESC_BS}fB[#{ESC_BS}0#{node.text}#{ESC_BS}0]#{ESC_BS}fP)
|
605
|
+
end
|
642
606
|
|
643
|
-
|
644
|
-
|
645
|
-
|
607
|
+
def inline_callout node
|
608
|
+
%(#{ESC_BS}fB(#{node.text})#{ESC_BS}fP)
|
609
|
+
end
|
646
610
|
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
end
|
611
|
+
# TODO supposedly groff has footnotes, but we're in search of an example
|
612
|
+
def inline_footnote node
|
613
|
+
if (index = node.attr 'index')
|
614
|
+
%([#{index}])
|
615
|
+
elsif node.type == :xref
|
616
|
+
%([#{node.text}])
|
654
617
|
end
|
618
|
+
end
|
655
619
|
|
656
|
-
|
657
|
-
|
658
|
-
|
620
|
+
def inline_image node
|
621
|
+
(node.attr? 'link') ? %([#{node.alt}] <#{node.attr 'link'}>) : %([#{node.alt}])
|
622
|
+
end
|
623
|
+
|
624
|
+
def inline_indexterm node
|
625
|
+
node.type == :visible ? node.text : ''
|
626
|
+
end
|
659
627
|
|
660
|
-
|
661
|
-
|
628
|
+
def inline_kbd node
|
629
|
+
if (keys = node.attr 'keys').size == 1
|
630
|
+
keys[0]
|
631
|
+
else
|
632
|
+
keys.join %(#{ESC_BS}0+#{ESC_BS}0)
|
662
633
|
end
|
634
|
+
end
|
663
635
|
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
636
|
+
def inline_menu node
|
637
|
+
caret = %[#{ESC_BS}0#{ESC_BS}(fc#{ESC_BS}0]
|
638
|
+
menu = node.attr 'menu'
|
639
|
+
if !(submenus = node.attr 'submenus').empty?
|
640
|
+
submenu_path = submenus.map {|item| %(#{ESC_BS}fI#{item}#{ESC_BS}fP) }.join caret
|
641
|
+
%(#{ESC_BS}fI#{menu}#{ESC_BS}fP#{caret}#{submenu_path}#{caret}#{ESC_BS}fI#{node.attr 'menuitem'}#{ESC_BS}fP)
|
642
|
+
elsif (menuitem = node.attr 'menuitem')
|
643
|
+
%(#{ESC_BS}fI#{menu}#{caret}#{menuitem}#{ESC_BS}fP)
|
644
|
+
else
|
645
|
+
%(#{ESC_BS}fI#{menu}#{ESC_BS}fP)
|
670
646
|
end
|
647
|
+
end
|
671
648
|
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
649
|
+
# NOTE use fake <BOUNDARY> element to prevent creating artificial word boundaries
|
650
|
+
def inline_quoted node
|
651
|
+
case node.type
|
652
|
+
when :emphasis
|
653
|
+
%(#{ESC_BS}fI<BOUNDARY>#{node.text}</BOUNDARY>#{ESC_BS}fP)
|
654
|
+
when :strong
|
655
|
+
%(#{ESC_BS}fB<BOUNDARY>#{node.text}</BOUNDARY>#{ESC_BS}fP)
|
656
|
+
when :monospaced
|
657
|
+
%[#{ESC_BS}f(CR<BOUNDARY>#{node.text}</BOUNDARY>#{ESC_BS}fP]
|
658
|
+
when :single
|
659
|
+
%[#{ESC_BS}(oq<BOUNDARY>#{node.text}</BOUNDARY>#{ESC_BS}(cq]
|
660
|
+
when :double
|
661
|
+
%[#{ESC_BS}(lq<BOUNDARY>#{node.text}</BOUNDARY>#{ESC_BS}(rq]
|
662
|
+
else
|
663
|
+
node.text
|
683
664
|
end
|
665
|
+
end
|
684
666
|
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
%(#{
|
692
|
-
when :monospaced
|
693
|
-
%[#{ESC_BS}f(CR<BOUNDARY>#{node.text}</BOUNDARY>#{ESC_BS}fP]
|
694
|
-
when :single
|
695
|
-
%[#{ESC_BS}(oq<BOUNDARY>#{node.text}</BOUNDARY>#{ESC_BS}(cq]
|
696
|
-
when :double
|
697
|
-
%[#{ESC_BS}(lq<BOUNDARY>#{node.text}</BOUNDARY>#{ESC_BS}(rq]
|
698
|
-
else
|
699
|
-
node.text
|
667
|
+
def self.write_alternate_pages mannames, manvolnum, target
|
668
|
+
if mannames && mannames.size > 1
|
669
|
+
mannames.shift
|
670
|
+
manvolext = %(.#{manvolnum})
|
671
|
+
dir, basename = ::File.split target
|
672
|
+
mannames.each do |manname|
|
673
|
+
::File.write ::File.join(dir, %(#{manname}#{manvolext})), %(.so #{basename}), mode: FILE_WRITE_MODE
|
700
674
|
end
|
701
675
|
end
|
676
|
+
end
|
702
677
|
|
703
|
-
|
704
|
-
node.content_model == :compound ? node.content : %(.sp#{LF}#{manify node.content, :whitespace => :normalize})
|
705
|
-
end
|
678
|
+
private
|
706
679
|
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
680
|
+
# Converts HTML entity references back to their original form, escapes
|
681
|
+
# special man characters and strips trailing whitespace.
|
682
|
+
#
|
683
|
+
# It's crucial that text only ever pass through _manify once.
|
684
|
+
#
|
685
|
+
# str - the String to convert
|
686
|
+
# opts - an Hash of options to control processing (default: {})
|
687
|
+
# * :whitespace an enum that indicates how to handle whitespace; supported options are:
|
688
|
+
# :preserve - preserve spaces (only expanding tabs); :normalize - normalize whitespace
|
689
|
+
# (remove spaces around newlines); :collapse - collapse adjacent whitespace to a single
|
690
|
+
# space (default: :collapse)
|
691
|
+
# * :append_newline a Boolean that indicates whether to append a newline to the result (default: false)
|
692
|
+
def _manify str, opts = {}
|
693
|
+
case opts.fetch :whitespace, :collapse
|
694
|
+
when :preserve
|
695
|
+
str = str.gsub TAB, ET
|
696
|
+
when :normalize
|
697
|
+
str = str.gsub WrappedIndentRx, LF
|
698
|
+
else
|
699
|
+
str = str.tr_s WHITESPACE, ' '
|
700
|
+
end
|
701
|
+
str = str.
|
702
|
+
gsub(LiteralBackslashRx, '\&(rs'). # literal backslash (not a troff escape sequence)
|
703
|
+
gsub(LeadingPeriodRx, '\\\&.'). # leading . is used in troff for macro call or other formatting; replace with \&.
|
704
|
+
# drop orphaned \c escape lines, unescape troff macro, quote adjacent character, isolate macro line
|
705
|
+
gsub(EscapedMacroRx) { (rest = $3.lstrip).empty? ? %(.#$1"#$2") : %(.#$1"#$2"#{LF}#{rest}) }.
|
706
|
+
gsub('-', '\-').
|
707
|
+
gsub('<', '<').
|
708
|
+
gsub('>', '>').
|
709
|
+
gsub(' ', '\~'). # non-breaking space
|
710
|
+
gsub('©', '\(co'). # copyright sign
|
711
|
+
gsub('®', '\(rg'). # registered sign
|
712
|
+
gsub('™', '\(tm'). # trademark sign
|
713
|
+
gsub(' ', ' '). # thin space
|
714
|
+
gsub('–', '\(en'). # en dash
|
715
|
+
gsub(EmDashCharRefRx, '\(em'). # em dash
|
716
|
+
gsub('‘', '\(oq'). # left single quotation mark
|
717
|
+
gsub('’', '\(cq'). # right single quotation mark
|
718
|
+
gsub('“', '\(lq'). # left double quotation mark
|
719
|
+
gsub('”', '\(rq'). # right double quotation mark
|
720
|
+
gsub(EllipsisCharRefRx, '...'). # horizontal ellipsis
|
721
|
+
gsub('←', '\(<-'). # leftwards arrow
|
722
|
+
gsub('→', '\(->'). # rightwards arrow
|
723
|
+
gsub('⇐', '\(lA'). # leftwards double arrow
|
724
|
+
gsub('⇒', '\(rA'). # rightwards double arrow
|
725
|
+
gsub('​', '\:'). # zero width space
|
726
|
+
gsub('&','&'). # literal ampersand (NOTE must take place after any other replacement that includes &)
|
727
|
+
gsub('\'', '\(aq'). # apostrophe-quote
|
728
|
+
gsub(MockBoundaryRx, ''). # mock boundary
|
729
|
+
gsub(ESC_BS, '\\'). # unescape troff backslash (NOTE update if more escapes are added)
|
730
|
+
gsub(ESC_FS, '.'). # unescape full stop in troff commands (NOTE must take place after gsub(LeadingPeriodRx))
|
731
|
+
rstrip # strip trailing space
|
732
|
+
opts[:append_newline] ? %(#{str}#{LF}) : str
|
717
733
|
end
|
734
|
+
|
735
|
+
def _enclose_content node
|
736
|
+
node.content_model == :compound ? node.content : %(.sp#{LF}#{_manify node.content, whitespace: :normalize})
|
737
|
+
end
|
738
|
+
end
|
718
739
|
end
|