asciidoctor 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of asciidoctor might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/Gemfile +1 -1
- data/LICENSE +2 -2
- data/README.adoc +461 -0
- data/asciidoctor.gemspec +27 -16
- data/compat/asciidoc.conf +139 -0
- data/lib/asciidoctor.rb +212 -69
- data/lib/asciidoctor/abstract_block.rb +41 -0
- data/lib/asciidoctor/abstract_node.rb +128 -81
- data/lib/asciidoctor/attribute_list.rb +5 -2
- data/lib/asciidoctor/backends/base_template.rb +16 -4
- data/lib/asciidoctor/backends/docbook45.rb +112 -42
- data/lib/asciidoctor/backends/html5.rb +206 -90
- data/lib/asciidoctor/block.rb +5 -5
- data/lib/asciidoctor/cli/invoker.rb +38 -34
- data/lib/asciidoctor/cli/options.rb +3 -3
- data/lib/asciidoctor/document.rb +115 -13
- data/lib/asciidoctor/helpers.rb +16 -0
- data/lib/asciidoctor/lexer.rb +486 -359
- data/lib/asciidoctor/path_resolver.rb +360 -0
- data/lib/asciidoctor/reader.rb +122 -23
- data/lib/asciidoctor/renderer.rb +1 -33
- data/lib/asciidoctor/section.rb +1 -1
- data/lib/asciidoctor/substituters.rb +103 -19
- data/lib/asciidoctor/version.rb +1 -1
- data/man/asciidoctor.1 +6 -6
- data/man/asciidoctor.ad +5 -3
- data/stylesheets/asciidoctor.css +274 -0
- data/test/attributes_test.rb +133 -10
- data/test/blocks_test.rb +302 -17
- data/test/document_test.rb +269 -6
- data/test/fixtures/basic-docinfo.html +1 -0
- data/test/fixtures/basic-docinfo.xml +4 -0
- data/test/fixtures/basic.asciidoc +4 -0
- data/test/fixtures/docinfo.html +1 -0
- data/test/fixtures/docinfo.xml +2 -0
- data/test/fixtures/include-file.asciidoc +22 -1
- data/test/fixtures/stylesheets/custom.css +3 -0
- data/test/invoker_test.rb +38 -6
- data/test/lexer_test.rb +64 -21
- data/test/links_test.rb +4 -0
- data/test/lists_test.rb +251 -12
- data/test/paragraphs_test.rb +225 -30
- data/test/paths_test.rb +174 -0
- data/test/reader_test.rb +89 -2
- data/test/sections_test.rb +518 -16
- data/test/substitutions_test.rb +121 -10
- data/test/tables_test.rb +53 -13
- data/test/test_helper.rb +2 -2
- data/test/text_test.rb +5 -5
- metadata +46 -50
- data/README.asciidoc +0 -296
- data/lib/asciidoctor/errors.rb +0 -5
data/asciidoctor.gemspec
CHANGED
@@ -6,39 +6,41 @@
|
|
6
6
|
## http://docs.rubygems.org/read/chapter/20
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.specification_version = 2 if s.respond_to? :specification_version=
|
9
|
-
s.required_rubygems_version = Gem::Requirement.new(
|
10
|
-
s.rubygems_version = '1.
|
9
|
+
s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
|
10
|
+
s.rubygems_version = '1.8.5'
|
11
11
|
|
12
|
-
##
|
13
|
-
##
|
14
|
-
## the sub! line in the Rakefile
|
12
|
+
## This group of properties is updated automatically by the Rake build when
|
13
|
+
## cutting a new release (see the validate task)
|
15
14
|
s.name = 'asciidoctor'
|
16
|
-
s.version = '0.1.
|
17
|
-
s.date = '2013-
|
15
|
+
s.version = '0.1.2'
|
16
|
+
s.date = '2013-04-25'
|
18
17
|
s.rubyforge_project = 'asciidoctor'
|
19
18
|
|
20
19
|
## Make sure your summary is short. The description may be as long
|
21
20
|
## as you like.
|
22
|
-
s.summary =
|
23
|
-
s.description =
|
21
|
+
s.summary = 'A native Ruby AsciiDoc syntax processor and publishing toolchain'
|
22
|
+
s.description = <<-EOS
|
23
|
+
An open source text processor and publishing toolchain, written entirely in Ruby, for converting AsciiDoc markup into HTML 5, DocBook 4.5 and other formats.
|
24
|
+
EOS
|
25
|
+
s.license = 'MIT'
|
24
26
|
|
25
27
|
## List the primary authors. If there are a bunch of authors, it's probably
|
26
28
|
## better to set the email to an email list or something. If you don't have
|
27
29
|
## a custom homepage, consider using your GitHub URL or the like.
|
28
|
-
s.authors = [
|
29
|
-
s.email = 'rew@erebor.com'
|
30
|
-
s.homepage = 'http://
|
30
|
+
s.authors = ['Ryan Waldron', 'Dan Allen', 'Jeremy McAnally', 'Jason Porter']
|
31
|
+
s.email = ['rew@erebor.com', 'dan.j.allen@gmail.com']
|
32
|
+
s.homepage = 'http://asciidoctor.org'
|
31
33
|
|
32
34
|
## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
|
33
35
|
## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
|
34
36
|
s.require_paths = %w[lib]
|
35
37
|
|
36
38
|
## If your gem includes any executables, list them here.
|
37
|
-
s.executables = [
|
39
|
+
s.executables = ['asciidoctor', 'asciidoctor-safe']
|
38
40
|
|
39
41
|
## Specify any RDoc options here. You'll want to add your README and
|
40
42
|
## LICENSE files to the extra_rdoc_files list.
|
41
|
-
s.rdoc_options = [
|
43
|
+
s.rdoc_options = ['--charset=UTF-8']
|
42
44
|
s.extra_rdoc_files = %w[LICENSE]
|
43
45
|
|
44
46
|
## List your runtime dependencies here. Runtime dependencies are those
|
@@ -63,11 +65,12 @@ Gem::Specification.new do |s|
|
|
63
65
|
s.files = %w[
|
64
66
|
Gemfile
|
65
67
|
LICENSE
|
66
|
-
README.
|
68
|
+
README.adoc
|
67
69
|
Rakefile
|
68
70
|
asciidoctor.gemspec
|
69
71
|
bin/asciidoctor
|
70
72
|
bin/asciidoctor-safe
|
73
|
+
compat/asciidoc.conf
|
71
74
|
lib/asciidoctor.rb
|
72
75
|
lib/asciidoctor/abstract_block.rb
|
73
76
|
lib/asciidoctor/abstract_node.rb
|
@@ -81,11 +84,11 @@ Gem::Specification.new do |s|
|
|
81
84
|
lib/asciidoctor/cli/options.rb
|
82
85
|
lib/asciidoctor/debug.rb
|
83
86
|
lib/asciidoctor/document.rb
|
84
|
-
lib/asciidoctor/errors.rb
|
85
87
|
lib/asciidoctor/helpers.rb
|
86
88
|
lib/asciidoctor/inline.rb
|
87
89
|
lib/asciidoctor/lexer.rb
|
88
90
|
lib/asciidoctor/list_item.rb
|
91
|
+
lib/asciidoctor/path_resolver.rb
|
89
92
|
lib/asciidoctor/reader.rb
|
90
93
|
lib/asciidoctor/renderer.rb
|
91
94
|
lib/asciidoctor/section.rb
|
@@ -94,17 +97,24 @@ Gem::Specification.new do |s|
|
|
94
97
|
lib/asciidoctor/version.rb
|
95
98
|
man/asciidoctor.1
|
96
99
|
man/asciidoctor.ad
|
100
|
+
stylesheets/asciidoctor.css
|
97
101
|
test/attributes_test.rb
|
98
102
|
test/blocks_test.rb
|
99
103
|
test/document_test.rb
|
100
104
|
test/fixtures/asciidoc.txt
|
101
105
|
test/fixtures/asciidoc_index.txt
|
102
106
|
test/fixtures/ascshort.txt
|
107
|
+
test/fixtures/basic-docinfo.html
|
108
|
+
test/fixtures/basic-docinfo.xml
|
109
|
+
test/fixtures/basic.asciidoc
|
110
|
+
test/fixtures/docinfo.html
|
111
|
+
test/fixtures/docinfo.xml
|
103
112
|
test/fixtures/dot.gif
|
104
113
|
test/fixtures/encoding.asciidoc
|
105
114
|
test/fixtures/include-file.asciidoc
|
106
115
|
test/fixtures/list_elements.asciidoc
|
107
116
|
test/fixtures/sample.asciidoc
|
117
|
+
test/fixtures/stylesheets/custom.css
|
108
118
|
test/fixtures/tip.gif
|
109
119
|
test/invoker_test.rb
|
110
120
|
test/lexer_test.rb
|
@@ -112,6 +122,7 @@ Gem::Specification.new do |s|
|
|
112
122
|
test/lists_test.rb
|
113
123
|
test/options_test.rb
|
114
124
|
test/paragraphs_test.rb
|
125
|
+
test/paths_test.rb
|
115
126
|
test/preamble_test.rb
|
116
127
|
test/reader_test.rb
|
117
128
|
test/renderer_test.rb
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# This file is an AsciiDoc configuration file that makes
|
2
|
+
# AsciiDoc conform with Asciidoctor's fixes and customizations.
|
3
|
+
#
|
4
|
+
# Place this file in the same directory as your AsciiDoc document and the
|
5
|
+
# AsciiDoc processor (asciidoc) will automatically use it.
|
6
|
+
|
7
|
+
[miscellaneous]
|
8
|
+
newline=\n
|
9
|
+
|
10
|
+
[attributes]
|
11
|
+
# make html5 the default html backend
|
12
|
+
backend-alias-html=html5
|
13
|
+
linkcss=
|
14
|
+
apostrophe='
|
15
|
+
asterisk=*
|
16
|
+
caret=^
|
17
|
+
backtick=`
|
18
|
+
# plus introduced in AsciiDoc 8.6.9
|
19
|
+
plus=+
|
20
|
+
space=" "
|
21
|
+
tilde=~
|
22
|
+
|
23
|
+
# enables fenced code blocks
|
24
|
+
# I haven't sorted out yet how to do syntax highlighting
|
25
|
+
[blockdef-fenced-code]
|
26
|
+
delimiter=^```\w*$
|
27
|
+
template::[blockdef-listing]
|
28
|
+
|
29
|
+
# enables literal block to be used as code block
|
30
|
+
[blockdef-literal]
|
31
|
+
template::[source-filter-style]
|
32
|
+
|
33
|
+
ifdef::basebackend-html[]
|
34
|
+
|
35
|
+
[literal-inlinemacro]
|
36
|
+
<code>{passtext}</code>
|
37
|
+
|
38
|
+
[tags]
|
39
|
+
monospaced=<code{1? class="{1}"}>|</code>
|
40
|
+
|
41
|
+
[monospacedwords]
|
42
|
+
<code>{words}</code>
|
43
|
+
|
44
|
+
[tabletags-monospaced]
|
45
|
+
paragraph=<p class="tableblock"><code>|</code></p>
|
46
|
+
|
47
|
+
# support for document title in embedded documents
|
48
|
+
ifeval::[not config.header_footer]
|
49
|
+
[preamble]
|
50
|
+
<h1>{title={doctitle}}</h1>{set:title-rendered:}
|
51
|
+
<div id="preamble">
|
52
|
+
<div class="sectionbody">
|
53
|
+
|
|
54
|
+
</div>
|
55
|
+
</div>
|
56
|
+
|
57
|
+
[sect1]
|
58
|
+
{title-rendered%}<h1>{doctitle}</h1>
|
59
|
+
<div class="sect1{style? {style}}{role? {role}}">
|
60
|
+
<h2{id? id="{id}"}>{numbered?{sectnum} }{title}</h2>
|
61
|
+
<div class="sectionbody">
|
62
|
+
|
|
63
|
+
</div>
|
64
|
+
</div>
|
65
|
+
endif::[]
|
66
|
+
|
67
|
+
# override to add the admonition name to the class attribute of the outer element
|
68
|
+
[admonitionblock]
|
69
|
+
<div class="admonitionblock {name}{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
|
70
|
+
<table><tr>
|
71
|
+
<td class="icon">
|
72
|
+
{data-uri%}{icons#}<img src="{icon={iconsdir}/{name}.png}" alt="{caption}">
|
73
|
+
{data-uri#}{icons#}<img alt="{caption}" src="data:image/png;base64,
|
74
|
+
{data-uri#}{icons#}{sys:"{python}" -u -c "import base64,sys; base64.encode(sys.stdin,sys.stdout)" < "{eval:os.path.join(r"{indir={outdir}}",r"{icon={iconsdir}/{name}.png}")}"}">
|
75
|
+
{icons%}<div class="title">{caption}</div>
|
76
|
+
</td>
|
77
|
+
<td class="content">
|
78
|
+
<div class="title">{title}</div>
|
79
|
+
|
|
80
|
+
</td>
|
81
|
+
</tr></table>
|
82
|
+
</div>
|
83
|
+
|
84
|
+
# a common template for emitting the attribute for a quote or verse block
|
85
|
+
# don't output attribution div if attribution or citetitle are both empty
|
86
|
+
[attribution]
|
87
|
+
{attribution,citetitle#}<div class="attribution">
|
88
|
+
<cite>{citetitle}</cite>{attribution?<br>}
|
89
|
+
— {attribution}
|
90
|
+
{attribution,citetitle#}</div>
|
91
|
+
|
92
|
+
# override to use blockquote element for content and cite element for cite title
|
93
|
+
[quoteblock]
|
94
|
+
<div class="quoteblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
|
95
|
+
<div class="title">{title}</div>
|
96
|
+
<blockquote>
|
97
|
+
|
|
98
|
+
</blockquote>
|
99
|
+
template::[attribution]
|
100
|
+
</div>
|
101
|
+
|
102
|
+
# override to use cite element for cite title
|
103
|
+
[verseblock]
|
104
|
+
<div class="verseblock{role? {role}}{unbreakable-option? unbreakable}"{id? id="{id}"}>
|
105
|
+
<div class="title">{title}</div>
|
106
|
+
<pre class="content">
|
107
|
+
|
|
108
|
+
</pre>
|
109
|
+
template::[attribution]
|
110
|
+
</div>
|
111
|
+
|
112
|
+
endif::basebackend-html[]
|
113
|
+
|
114
|
+
# Override docinfo to support subtitle
|
115
|
+
ifdef::basebackend-docbook[]
|
116
|
+
|
117
|
+
[docinfo]
|
118
|
+
ifndef::notitle[]
|
119
|
+
{set2:subtitle_offset:{eval:'{doctitle}'.rfind(': ')}}
|
120
|
+
{eval:{subtitle_offset} != -1} <title>{eval:'{doctitle}'[0:{subtitle_offset}]}</title>
|
121
|
+
{eval:{subtitle_offset} != -1} <subtitle>{eval:'{doctitle}'[{subtitle_offset} + 2:]}</subtitle>
|
122
|
+
{eval:{subtitle_offset} < 0} <title>{doctitle}</title>
|
123
|
+
endif::notitle[]
|
124
|
+
<date>{revdate}</date>
|
125
|
+
# To ensure valid articleinfo/bookinfo when there is no AsciiDoc header.
|
126
|
+
{doctitle%}{revdate%}<date>{docdate}</date>
|
127
|
+
{authored#}<author>
|
128
|
+
<firstname>{firstname}</firstname>
|
129
|
+
<othername>{middlename}</othername>
|
130
|
+
<surname>{lastname}</surname>
|
131
|
+
<email>{email}</email>
|
132
|
+
{authored#}</author>
|
133
|
+
<authorinitials>{authorinitials}</authorinitials>
|
134
|
+
<revhistory><revision>{revnumber?<revnumber>{revnumber}</revnumber>}<date>{revdate}</date>{authorinitials?<authorinitials>{authorinitials}</authorinitials>}{revremark?<revremark>{revremark}</revremark>}</revision></revhistory>
|
135
|
+
{docinfo1,docinfo2#}{include:{docdir}/docinfo.xml}
|
136
|
+
{docinfo,docinfo2#}{include:{docdir}/{docname}-docinfo.xml}
|
137
|
+
<orgname>{orgname}</orgname>
|
138
|
+
|
139
|
+
endif::basebackend-docbook[]
|
data/lib/asciidoctor.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
require 'rubygems'
|
1
|
+
require 'rubygems' unless RUBY_VERSION >= '1.9'
|
2
2
|
require 'strscan'
|
3
|
+
require 'set'
|
3
4
|
|
4
5
|
$:.unshift(File.dirname(__FILE__))
|
5
6
|
#$:.unshift(File.join(File.dirname(__FILE__), '..', 'vendor'))
|
@@ -87,6 +88,9 @@ module Asciidoctor
|
|
87
88
|
|
88
89
|
end
|
89
90
|
|
91
|
+
# The root path of the Asciidoctor gem
|
92
|
+
ROOT_PATH = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
93
|
+
|
90
94
|
# The default document type
|
91
95
|
# Can influence markup generated by render templates
|
92
96
|
DEFAULT_DOCTYPE = 'article'
|
@@ -94,6 +98,12 @@ module Asciidoctor
|
|
94
98
|
# The backend determines the format of the rendered output, default to html5
|
95
99
|
DEFAULT_BACKEND = 'html5'
|
96
100
|
|
101
|
+
DEFAULT_STYLESHEET_PATH = File.join(ROOT_PATH, 'stylesheets', 'asciidoctor.css')
|
102
|
+
|
103
|
+
DEFAULT_STYLESHEET_KEYS = ['', 'DEFAULT'].to_set
|
104
|
+
|
105
|
+
DEFAULT_STYLESHEET_NAME = File.basename(DEFAULT_STYLESHEET_PATH)
|
106
|
+
|
97
107
|
# Pointers to the preferred version for a given backend.
|
98
108
|
BACKEND_ALIASES = {
|
99
109
|
'html' => 'html5',
|
@@ -113,19 +123,35 @@ module Asciidoctor
|
|
113
123
|
'markdown' => '.md'
|
114
124
|
}
|
115
125
|
|
126
|
+
SECTION_LEVELS = {
|
127
|
+
'=' => 0,
|
128
|
+
'-' => 1,
|
129
|
+
'~' => 2,
|
130
|
+
'^' => 3,
|
131
|
+
'+' => 4
|
132
|
+
}
|
133
|
+
|
134
|
+
ADMONITION_STYLES = ['NOTE', 'TIP', 'IMPORTANT', 'WARNING', 'CAUTION'].to_set
|
135
|
+
|
136
|
+
# NOTE: AsciiDoc doesn't support pass style for paragraph
|
137
|
+
PARAGRAPH_STYLES = ['comment', 'example', 'literal', 'listing', 'normal', 'pass', 'quote', 'sidebar', 'source', 'verse'].to_set
|
138
|
+
|
139
|
+
VERBATIM_STYLES = ['literal', 'listing', 'source', 'verse'].to_set
|
140
|
+
|
116
141
|
DELIMITED_BLOCKS = {
|
117
|
-
'
|
118
|
-
'
|
119
|
-
'
|
120
|
-
'
|
121
|
-
'
|
122
|
-
'
|
123
|
-
'
|
124
|
-
'
|
125
|
-
'
|
126
|
-
'
|
127
|
-
'
|
128
|
-
'
|
142
|
+
# NOTE: AsciiDoc doesn't support pass style for open block
|
143
|
+
'--' => [:open, ['comment', 'example', 'literal', 'listing', 'pass', 'quote', 'sidebar', 'source', 'verse', 'admonition'].to_set],
|
144
|
+
'----' => [:listing, ['literal', 'source'].to_set],
|
145
|
+
'....' => [:literal, ['listing', 'source'].to_set],
|
146
|
+
'====' => [:example, ['admonition'].to_set],
|
147
|
+
'****' => [:sidebar, Set.new],
|
148
|
+
'____' => [:quote, ['verse'].to_set],
|
149
|
+
'++++' => [:pass, Set.new],
|
150
|
+
'|===' => [:table, Set.new],
|
151
|
+
'!===' => [:table, Set.new],
|
152
|
+
'////' => [:comment, Set.new],
|
153
|
+
'```' => [:fenced_code, Set.new],
|
154
|
+
'~~~' => [:fenced_code, Set.new]
|
129
155
|
}
|
130
156
|
|
131
157
|
BREAK_LINES = {
|
@@ -156,6 +182,27 @@ module Asciidoctor
|
|
156
182
|
|
157
183
|
LINE_FEED_ENTITY = ' ' # or 

|
158
184
|
|
185
|
+
# Flags to control compliance with the behavior of AsciiDoc
|
186
|
+
COMPLIANCE = {
|
187
|
+
# AsciiDoc terminates paragraphs adjacent to
|
188
|
+
# block content (delimiter or block attribute list)
|
189
|
+
# Compliance value: true
|
190
|
+
# TODO what about literal paragraph?
|
191
|
+
:block_terminates_paragraph => true,
|
192
|
+
|
193
|
+
# AsciiDoc does not treat paragraphs labeled with a
|
194
|
+
# verbatim style (literal, listing, source, verse)
|
195
|
+
# as verbatim; override this behavior
|
196
|
+
# Compliance value: false
|
197
|
+
:strict_verbatim_paragraphs => true,
|
198
|
+
|
199
|
+
# AsciiDoc allows start and end delimiters around
|
200
|
+
# a block to be different lengths
|
201
|
+
# this option requires that they be the same
|
202
|
+
# Compliance value: false
|
203
|
+
:congruent_block_delimiters => true
|
204
|
+
}
|
205
|
+
|
159
206
|
# The following pattern, which appears frequently, captures the contents between square brackets,
|
160
207
|
# ignoring escaped closing brackets (closing brackets prefixed with a backslash '\' character)
|
161
208
|
#
|
@@ -164,8 +211,11 @@ module Asciidoctor
|
|
164
211
|
# Matches:
|
165
212
|
# [enclosed text here] or [enclosed [text\] here]
|
166
213
|
REGEXP = {
|
214
|
+
# NOTE: this is a inline admonition note
|
215
|
+
:admonition_inline => /^(#{ADMONITION_STYLES.to_a * '|'}):\s/,
|
216
|
+
|
167
217
|
# [[Foo]]
|
168
|
-
:anchor => /^\[\[([^\[\]]+)\]\]$/,
|
218
|
+
:anchor => /^\[\[([^\s\[\]]+)\]\]$/,
|
169
219
|
|
170
220
|
# Foowhatevs [[Bar]]
|
171
221
|
:anchor_embedded => /^(.*?)\s*\[\[([^\[\]]+)\]\]$/,
|
@@ -178,6 +228,14 @@ module Asciidoctor
|
|
178
228
|
# NOTE position the most common blocks towards the front of the pattern
|
179
229
|
:any_blk => %r{^(?:--|(?:-|\.|=|\*|_|\+|/){4,}|[\|!]={3,}|(?:`|~){3,}.*)$},
|
180
230
|
|
231
|
+
# detect a list item of any sort
|
232
|
+
# [[:graph:]] is a non-blank character
|
233
|
+
:any_list => /^(?:
|
234
|
+
<?\d+>[[:blank:]]+[[:graph:]]|
|
235
|
+
[[:blank:]]*(?:(?:-|\*|\.){1,5}|\d+\.|[A-Za-z]\.|[IVXivx]+\))[[:blank:]]+[[:graph:]]|
|
236
|
+
[[:blank:]]*.*?(?::{2,4}|;;)(?:[[:blank:]]+[[:graph:]]|$)
|
237
|
+
)/x,
|
238
|
+
|
181
239
|
# :foo: bar
|
182
240
|
# :Author: Dan
|
183
241
|
# :numbered!:
|
@@ -204,10 +262,10 @@ module Asciidoctor
|
|
204
262
|
# [NOTE, caption="Good to know"]
|
205
263
|
# Can be defined by an attribute
|
206
264
|
# [{lead}]
|
207
|
-
:blk_attr_list => /^\[([\w\{].*)\]$/,
|
265
|
+
:blk_attr_list => /^\[(|[[:blank:]]*[\w\{,"'].*)\]$/,
|
208
266
|
|
209
267
|
# block attribute list or block id (bulk query)
|
210
|
-
:attr_line => /^\[([\w\{].*|\[[^\[\]]
|
268
|
+
:attr_line => /^\[(|[[:blank:]]*[\w\{,"'].*|\[[^\[\]]*\])\]$/,
|
211
269
|
|
212
270
|
# attribute reference
|
213
271
|
# {foo}
|
@@ -216,7 +274,7 @@ module Asciidoctor
|
|
216
274
|
|
217
275
|
# The author info line the appears immediately following the document title
|
218
276
|
# John Doe <john@anonymous.com>
|
219
|
-
:author_info =>
|
277
|
+
:author_info => /^(\w[\w\-'.]*)(?: +(\w[\w\-'.]*))?(?: +(\w[\w\-'.]*))?(?: +<([^>]+)>)?$/,
|
220
278
|
|
221
279
|
# [[[Foo]]] (anywhere inline)
|
222
280
|
:biblio_macro => /\\?\[\[\[([\w:][\w:.-]*?)\]\]\]/,
|
@@ -229,7 +287,7 @@ module Asciidoctor
|
|
229
287
|
:callout_scan => /\\?<(\d+)>/,
|
230
288
|
|
231
289
|
# <1> Foo
|
232
|
-
:colist => /^<?(\d+)>
|
290
|
+
:colist => /^<?(\d+)>[[:blank:]]+(.*)/,
|
233
291
|
|
234
292
|
# ////
|
235
293
|
# comment block
|
@@ -242,7 +300,15 @@ module Asciidoctor
|
|
242
300
|
# one,two
|
243
301
|
# one, two
|
244
302
|
# one , two
|
245
|
-
:csv_delimiter => /[[:
|
303
|
+
:csv_delimiter => /[[:blank:]]*,[[:blank:]]*/,
|
304
|
+
|
305
|
+
# one;two
|
306
|
+
# one; two
|
307
|
+
# one ; two
|
308
|
+
:semicolon_delim => /[[:blank:]]*;[[:blank:]]*/,
|
309
|
+
|
310
|
+
# one,two;three;four
|
311
|
+
:scsv_csv_delim => /[[:blank:]]*[,;][[:blank:]]*/,
|
246
312
|
|
247
313
|
# 29
|
248
314
|
:digits => /^\d+$/,
|
@@ -255,13 +321,14 @@ module Asciidoctor
|
|
255
321
|
# That which precedes 'bar' (see also, <<bar>>)
|
256
322
|
# The term may be an attribute reference
|
257
323
|
# {term_foo}:: {def_foo}
|
258
|
-
|
324
|
+
# REVIEW leading space has already been stripped, so may not need in regex
|
325
|
+
:dlist => /^[[:blank:]]*(.*?)(:{2,4}|;;)(?:[[:blank:]]+(.*))?$/,
|
259
326
|
:dlist_siblings => {
|
260
327
|
# (?:.*?[^:])? - a non-capturing group which grabs longest sequence of characters that doesn't end w/ colon
|
261
|
-
'::' =>
|
262
|
-
':::' =>
|
263
|
-
'::::' =>
|
264
|
-
';;' =>
|
328
|
+
'::' => /^[[:blank:]]*((?:.*[^:])?)(::)(?:[[:blank:]]+(.*))?$/,
|
329
|
+
':::' => /^[[:blank:]]*((?:.*[^:])?)(:::)(?:[[:blank:]]+(.*))?$/,
|
330
|
+
'::::' => /^[[:blank:]]*((?:.*[^:])?)(::::)(?:[[:blank:]]+(.*))?$/,
|
331
|
+
';;' => /^[[:blank:]]*(.*)(;;)(?:[[:blank:]]+(.*))?$/
|
265
332
|
},
|
266
333
|
# ====
|
267
334
|
#:example => /^={4,}$/,
|
@@ -269,13 +336,15 @@ module Asciidoctor
|
|
269
336
|
# footnote:[text]
|
270
337
|
# footnoteref:[id,text]
|
271
338
|
# footnoteref:[id]
|
272
|
-
:footnote_macro => /\\?(footnote|footnoteref):\[((?:\\\]|[^\]])*?)\]
|
339
|
+
:footnote_macro => /\\?(footnote|footnoteref):\[((?:\\\]|[^\]])*?)\]/,
|
273
340
|
|
274
341
|
# image::filename.png[Caption]
|
275
|
-
|
342
|
+
# video::http://youtube.com/12345[Cats vs Dogs]
|
343
|
+
:media_blk_macro => /^(image|video|audio)::(\S+?)\[((?:\\\]|[^\]])*?)\]$/,
|
276
344
|
|
277
345
|
# image:filename.png[Alt Text]
|
278
|
-
|
346
|
+
# image:filename.png[More [Alt\] Text] (alt text becomes "More [Alt] Text")
|
347
|
+
:image_macro => /\\?image:([^:\[]+)\[((?:\\\]|[^\]])*?)\]/,
|
279
348
|
|
280
349
|
# indexterm:[Tigers,Big cats]
|
281
350
|
# (((Tigers,Big cats)))
|
@@ -288,6 +357,9 @@ module Asciidoctor
|
|
288
357
|
# whitespace at the beginning of the line
|
289
358
|
:leading_blanks => /^([[:blank:]]*)/,
|
290
359
|
|
360
|
+
# leading parent directory references in path
|
361
|
+
:leading_parent_dirs => /^(?:\.\.\/)*/,
|
362
|
+
|
291
363
|
# + From the Asciidoc User Guide: "A plus character preceded by at
|
292
364
|
# least one space character at the end of a non-blank line forces
|
293
365
|
# a line break. It generates a line break (br) tag for HTML outputs.
|
@@ -299,11 +371,15 @@ module Asciidoctor
|
|
299
371
|
|
300
372
|
# inline link and some inline link macro
|
301
373
|
# FIXME revisit!
|
302
|
-
:link_inline => %r{(^|link:|\s|>|<|[\(\)\[\]])(\\?(?:https?|ftp)://[^\s\[<]*[^\s
|
374
|
+
:link_inline => %r{(^|link:|\s|>|<|[\(\)\[\]])(\\?(?:https?|ftp)://[^\s\[<]*[^\s.,\[<])(?:\[((?:\\\]|[^\]])*?)\])?},
|
303
375
|
|
304
376
|
# inline link macro
|
305
377
|
# link:path[label]
|
306
|
-
:link_macro => /\\?link:([^\s\[]+)(?:\[((?:\\\]|[^\]])*?)\])/,
|
378
|
+
:link_macro => /\\?(?:link|mailto):([^\s\[]+)(?:\[((?:\\\]|[^\]])*?)\])/,
|
379
|
+
|
380
|
+
# inline email address
|
381
|
+
# doc.writer@asciidoc.org
|
382
|
+
:email_inline => /[\\>:]?\w[\w.%+-]*@[[:alnum:]][[:alnum:].-]*\.[[:alpha:]]{2,4}\b/,
|
307
383
|
|
308
384
|
# ----
|
309
385
|
#:listing => /^\-{4,}$/,
|
@@ -323,7 +399,8 @@ module Asciidoctor
|
|
323
399
|
# A. Foo (upperalpha)
|
324
400
|
# i. Foo (lowerroman)
|
325
401
|
# I. Foo (upperroman)
|
326
|
-
|
402
|
+
# REVIEW leading space has already been stripped, so may not need in regex
|
403
|
+
:olist => /^[[:blank:]]*(\.{1,5}|\d+\.|[A-Za-z]\.|[IVXivx]+\))[[:blank:]]+(.*)$/,
|
327
404
|
|
328
405
|
# ''' (ruler)
|
329
406
|
# <<< (pagebreak)
|
@@ -394,8 +471,10 @@ module Asciidoctor
|
|
394
471
|
# .Foo but not . Foo or ..Foo
|
395
472
|
:blk_title => /^\.([^\s.].*)$/,
|
396
473
|
|
474
|
+
# matches double quoted text, capturing quote char and text (single-line)
|
397
475
|
:dbl_quoted => /^("|)(.*)\1$/,
|
398
476
|
|
477
|
+
# matches double quoted text, capturing quote char and text (multi-line)
|
399
478
|
:m_dbl_quoted => /^("|)(.*)\1$/m,
|
400
479
|
|
401
480
|
# == Foo
|
@@ -417,11 +496,17 @@ module Asciidoctor
|
|
417
496
|
:section_name => /^((?=.*\w+.*)[^.].*?)$/,
|
418
497
|
|
419
498
|
# ====== || ------ || ~~~~~~ || ^^^^^^ || ++++++
|
420
|
-
|
499
|
+
# TODO build from SECTION_LEVELS keys
|
500
|
+
:section_underline => /^(?:=|-|~|\^|\+)+$/,
|
501
|
+
|
502
|
+
# toc::[]
|
503
|
+
# toc::[levels=2]
|
504
|
+
:toc => /^toc::\[(.*?)\]$/,
|
421
505
|
|
422
506
|
# * Foo (up to 5 consecutive asterisks)
|
423
507
|
# - Foo
|
424
|
-
|
508
|
+
# REVIEW leading space has already been stripped, so may not need in regex
|
509
|
+
:ulist => /^[[:blank:]]*(-|\*{1,5})[[:blank:]]+(.*)$/,
|
425
510
|
|
426
511
|
# inline xref macro
|
427
512
|
# <<id,reftext>> (special characters have already been escaped, hence the entity references)
|
@@ -443,15 +528,16 @@ module Asciidoctor
|
|
443
528
|
#:eval_expr => /^(true|false|("|'|)\{\w+(?:\-\w+)*\}\2|("|')[^\3]*\3|\-?\d+(?:\.\d+)*)[[:blank:]]*(==|!=|<=|>=|<|>)[[:blank:]]*(true|false|("|'|)\{\w+(?:\-\w+)*\}\6|("|')[^\7]*\7|\-?\d+(?:\.\d+)*)$/,
|
444
529
|
|
445
530
|
# include::chapter1.ad[]
|
446
|
-
|
531
|
+
# include::example.txt[lines=1;2;5..10]
|
532
|
+
:include_macro => /^\\?include::([^\[]+)\[(.*?)\]$/,
|
447
533
|
|
448
534
|
# http://domain
|
449
535
|
# https://domain
|
450
536
|
# data:info
|
451
|
-
:uri_sniff => /^[[:alpha:]][[:alnum:].+-]*:/i
|
452
|
-
}
|
537
|
+
:uri_sniff => /^[[:alpha:]][[:alnum:].+-]*:/i,
|
453
538
|
|
454
|
-
|
539
|
+
:uri_encode_chars => /[^\w\-.!~*';:@=+$,()\[\]]/
|
540
|
+
}
|
455
541
|
|
456
542
|
INTRINSICS = Hash.new{|h,k| STDERR.puts "Missing intrinsic: #{k.inspect}"; "{#{k}}"}.merge(
|
457
543
|
{
|
@@ -493,6 +579,7 @@ module Asciidoctor
|
|
493
579
|
}
|
494
580
|
|
495
581
|
SPECIAL_CHARS_PATTERN = /[#{SPECIAL_CHARS.keys.join}]/
|
582
|
+
#SPECIAL_CHARS_PATTERN = /(?:<|>|&(?![[:alpha:]]{2,};|#[[:digit:]]{2,}+;|#x[[:alnum:]]{2,}+;))/
|
496
583
|
|
497
584
|
# unconstrained quotes:: can appear anywhere
|
498
585
|
# constrained quotes:: must be bordered by non-word characters
|
@@ -545,33 +632,29 @@ module Asciidoctor
|
|
545
632
|
# order is significant
|
546
633
|
REPLACEMENTS = [
|
547
634
|
# (C)
|
548
|
-
[
|
635
|
+
[/\\?\(C\)/, '©', :none],
|
549
636
|
# (R)
|
550
|
-
[
|
637
|
+
[/\\?\(R\)/, '®', :none],
|
551
638
|
# (TM)
|
552
|
-
[
|
639
|
+
[/\\?\(TM\)/, '™', :none],
|
553
640
|
# foo -- bar
|
554
|
-
[/(^|\n| )--( |\n|$)/, ' — '],
|
641
|
+
[/(^|\n| |\\)--( |\n|$)/, ' — ', :none],
|
555
642
|
# foo--bar
|
556
|
-
[/(\w)
|
643
|
+
[/(\w)\\?--(?=\w)/, '—', :leading],
|
557
644
|
# ellipsis
|
558
|
-
[
|
645
|
+
[/\\?\.\.\./, '…', :leading],
|
559
646
|
# single quotes
|
560
|
-
[/(\w)'(\w)/, '
|
561
|
-
# escaped single quotes
|
562
|
-
[/(\w)\\'(\w)/, '\1\'\2'],
|
647
|
+
[/(\w)\\?'(\w)/, '’', :bounding],
|
563
648
|
# right arrow ->
|
564
|
-
[
|
649
|
+
[/\\?->/, '→', :none],
|
565
650
|
# right double arrow =>
|
566
|
-
[
|
651
|
+
[/\\?=>/, '⇒', :none],
|
567
652
|
# left arrow <-
|
568
|
-
[
|
653
|
+
[/\\?<-/, '←', :none],
|
569
654
|
# right left arrow <=
|
570
|
-
[
|
571
|
-
#
|
572
|
-
|
573
|
-
# restore entities; TODO needs cleanup
|
574
|
-
[/(^|[^\\])&(#[a-z0-9]+;)/i, '\1&\2']
|
655
|
+
[/\\?<=/, '⇐', :none],
|
656
|
+
# restore entities
|
657
|
+
[/\\?(&)amp;((?:[[:alpha:]]+|#[[:digit:]]+|#x[[:alnum:]]+);)/, '', :bounding]
|
575
658
|
]
|
576
659
|
|
577
660
|
# Public: Parse the AsciiDoc source input into an Asciidoctor::Document
|
@@ -587,6 +670,10 @@ module Asciidoctor
|
|
587
670
|
#
|
588
671
|
# returns the Asciidoctor::Document
|
589
672
|
def self.load(input, options = {}, &block)
|
673
|
+
if (monitor = options.fetch(:monitor, false))
|
674
|
+
start = Time.now
|
675
|
+
end
|
676
|
+
|
590
677
|
lines = nil
|
591
678
|
if input.is_a?(File)
|
592
679
|
options[:attributes] ||= {}
|
@@ -612,7 +699,19 @@ module Asciidoctor
|
|
612
699
|
raise "Unsupported input type: #{input.class}"
|
613
700
|
end
|
614
701
|
|
615
|
-
|
702
|
+
if monitor
|
703
|
+
read_time = Time.now - start
|
704
|
+
start = Time.now
|
705
|
+
end
|
706
|
+
|
707
|
+
doc = Document.new(lines, options, &block)
|
708
|
+
if monitor
|
709
|
+
parse_time = Time.now - start
|
710
|
+
monitor[:read] = read_time
|
711
|
+
monitor[:parse] = parse_time
|
712
|
+
monitor[:load] = read_time + parse_time
|
713
|
+
end
|
714
|
+
doc
|
616
715
|
end
|
617
716
|
|
618
717
|
# Public: Parse the contents of the AsciiDoc source file into an Asciidoctor::Document
|
@@ -658,18 +757,22 @@ module Asciidoctor
|
|
658
757
|
# see Asciidoctor::Document#initialize for details
|
659
758
|
# block - a callback block for handling include::[] directives
|
660
759
|
#
|
661
|
-
# returns
|
662
|
-
# otherwise the rendered
|
760
|
+
# returns the Document object if the rendered result String is written to a
|
761
|
+
# file, otherwise the rendered result String
|
663
762
|
def self.render(input, options = {}, &block)
|
664
763
|
in_place = options.delete(:in_place) || false
|
665
764
|
to_file = options.delete(:to_file)
|
666
765
|
to_dir = options.delete(:to_dir)
|
667
766
|
mkdirs = options.delete(:mkdirs) || false
|
767
|
+
monitor = options.fetch(:monitor, false)
|
668
768
|
|
669
769
|
write_in_place = in_place && input.is_a?(File)
|
670
770
|
write_to_target = to_file || to_dir
|
771
|
+
stream_output = !to_file.nil? && to_file.respond_to?(:write)
|
671
772
|
|
672
|
-
|
773
|
+
if write_in_place && write_to_target
|
774
|
+
raise ArgumentError, 'the option :in_place cannot be used with either the :to_dir or :to_file option'
|
775
|
+
end
|
673
776
|
|
674
777
|
if !options.has_key?(:header_footer) && (write_in_place || write_to_target)
|
675
778
|
options[:header_footer] = true
|
@@ -677,21 +780,26 @@ module Asciidoctor
|
|
677
780
|
|
678
781
|
doc = Asciidoctor.load(input, options, &block)
|
679
782
|
|
680
|
-
if
|
783
|
+
if to_file == '/dev/null'
|
784
|
+
return doc
|
785
|
+
elsif write_in_place
|
681
786
|
to_file = File.join(File.dirname(input.path), "#{doc.attributes['docname']}#{doc.attributes['outfilesuffix']}")
|
682
|
-
elsif write_to_target
|
787
|
+
elsif !stream_output && write_to_target
|
788
|
+
working_dir = options.has_key?(:base_dir) ? File.expand_path(opts[:base_dir]) : File.expand_path(Dir.pwd)
|
789
|
+
# QUESTION should the jail be the working_dir or doc.base_dir???
|
790
|
+
jail = doc.safe >= SafeMode::SAFE ? working_dir : nil
|
683
791
|
if to_dir
|
684
|
-
to_dir = doc.
|
792
|
+
to_dir = doc.normalize_system_path(to_dir, working_dir, jail, :target_name => 'to_dir', :recover => false)
|
685
793
|
if to_file
|
686
|
-
|
687
|
-
to_file = doc.normalize_asset_path(File.expand_path(to_file, to_dir), 'to_file', false)
|
794
|
+
to_file = doc.normalize_system_path(to_file, to_dir, nil, :target_name => 'to_dir', :recover => false)
|
688
795
|
# reestablish to_dir as the final target directory (in the case to_file had directory segments)
|
689
796
|
to_dir = File.dirname(to_file)
|
690
797
|
else
|
691
798
|
to_file = File.join(to_dir, "#{doc.attributes['docname']}#{doc.attributes['outfilesuffix']}")
|
692
799
|
end
|
693
800
|
elsif to_file
|
694
|
-
to_file = doc.
|
801
|
+
to_file = doc.normalize_system_path(to_file, working_dir, jail, :target_name => 'to_dir', :recover => false)
|
802
|
+
# establish to_dir as the final target directory (in the case to_file had directory segments)
|
695
803
|
to_dir = File.dirname(to_file)
|
696
804
|
end
|
697
805
|
|
@@ -705,11 +813,46 @@ module Asciidoctor
|
|
705
813
|
end
|
706
814
|
end
|
707
815
|
|
816
|
+
start = Time.now if monitor
|
817
|
+
output = doc.render
|
818
|
+
|
819
|
+
if monitor
|
820
|
+
render_time = Time.now - start
|
821
|
+
monitor[:render] = render_time
|
822
|
+
monitor[:load_render] = monitor[:load] + render_time
|
823
|
+
end
|
824
|
+
|
708
825
|
if to_file
|
709
|
-
|
710
|
-
|
826
|
+
start = Time.now if monitor
|
827
|
+
if stream_output
|
828
|
+
to_file.write output.rstrip
|
829
|
+
# ensure there's a trailing endline
|
830
|
+
to_file.write "\n"
|
831
|
+
else
|
832
|
+
File.open(to_file, 'w') {|file| file.write output }
|
833
|
+
# these assignments primarily for testing, diagnostics or reporting
|
834
|
+
doc.attributes['outfile'] = outfile = File.expand_path(to_file)
|
835
|
+
doc.attributes['outdir'] = File.dirname(outfile)
|
836
|
+
end
|
837
|
+
if monitor
|
838
|
+
write_time = Time.now - start
|
839
|
+
monitor[:write] = write_time
|
840
|
+
monitor[:total] = monitor[:load_render] + write_time
|
841
|
+
end
|
842
|
+
|
843
|
+
# NOTE document cannot control this behavior if safe >= SafeMode::SERVER
|
844
|
+
if !stream_output && doc.attr?('copycss') &&
|
845
|
+
doc.attr?('linkcss') && DEFAULT_STYLESHEET_KEYS.include?(doc.attr('stylesheet'))
|
846
|
+
Helpers.require_library 'fileutils'
|
847
|
+
outdir = doc.attr('outdir')
|
848
|
+
stylesdir = doc.normalize_system_path(doc.attr('stylesdir'), outdir,
|
849
|
+
doc.safe >= SafeMode::SAFE ? outdir : nil)
|
850
|
+
FileUtils.mkdir_p stylesdir
|
851
|
+
FileUtils.cp DEFAULT_STYLESHEET_PATH, stylesdir, :preserve => true
|
852
|
+
end
|
853
|
+
doc
|
711
854
|
else
|
712
|
-
|
855
|
+
output
|
713
856
|
end
|
714
857
|
end
|
715
858
|
|
@@ -721,8 +864,8 @@ module Asciidoctor
|
|
721
864
|
# see Asciidoctor::Document#initialize for details
|
722
865
|
# block - a callback block for handling include::[] directives
|
723
866
|
#
|
724
|
-
# returns
|
725
|
-
# otherwise the rendered
|
867
|
+
# returns the Document object if the rendered result String is written to a
|
868
|
+
# file, otherwise the rendered result String
|
726
869
|
def self.render_file(filename, options = {}, &block)
|
727
870
|
Asciidoctor.render(File.new(filename), options, &block)
|
728
871
|
end
|
@@ -750,10 +893,10 @@ module Asciidoctor
|
|
750
893
|
require 'asciidoctor/block'
|
751
894
|
require 'asciidoctor/callouts'
|
752
895
|
require 'asciidoctor/document'
|
753
|
-
#require 'asciidoctor/errors'
|
754
896
|
require 'asciidoctor/inline'
|
755
897
|
require 'asciidoctor/lexer'
|
756
898
|
require 'asciidoctor/list_item'
|
899
|
+
require 'asciidoctor/path_resolver'
|
757
900
|
require 'asciidoctor/reader'
|
758
901
|
require 'asciidoctor/renderer'
|
759
902
|
require 'asciidoctor/section'
|