gitlab-rdoc 6.3.2
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 +7 -0
- data/CONTRIBUTING.rdoc +220 -0
- data/CVE-2013-0256.rdoc +49 -0
- data/ExampleMarkdown.md +37 -0
- data/ExampleRDoc.rdoc +208 -0
- data/Gemfile +12 -0
- data/History.rdoc +1666 -0
- data/LEGAL.rdoc +50 -0
- data/LICENSE.rdoc +57 -0
- data/README.rdoc +133 -0
- data/RI.rdoc +57 -0
- data/Rakefile +101 -0
- data/TODO.rdoc +59 -0
- data/bin/console +7 -0
- data/bin/setup +6 -0
- data/exe/rdoc +44 -0
- data/exe/ri +12 -0
- data/lib/rdoc/alias.rb +112 -0
- data/lib/rdoc/anon_class.rb +11 -0
- data/lib/rdoc/any_method.rb +361 -0
- data/lib/rdoc/attr.rb +176 -0
- data/lib/rdoc/class_module.rb +802 -0
- data/lib/rdoc/code_object.rb +421 -0
- data/lib/rdoc/code_objects.rb +6 -0
- data/lib/rdoc/comment.rb +250 -0
- data/lib/rdoc/constant.rb +187 -0
- data/lib/rdoc/context/section.rb +232 -0
- data/lib/rdoc/context.rb +1266 -0
- data/lib/rdoc/cross_reference.rb +202 -0
- data/lib/rdoc/encoding.rb +136 -0
- data/lib/rdoc/erb_partial.rb +19 -0
- data/lib/rdoc/erbio.rb +42 -0
- data/lib/rdoc/extend.rb +10 -0
- data/lib/rdoc/generator/darkfish.rb +790 -0
- data/lib/rdoc/generator/json_index.rb +300 -0
- data/lib/rdoc/generator/markup.rb +160 -0
- data/lib/rdoc/generator/pot/message_extractor.rb +68 -0
- data/lib/rdoc/generator/pot/po.rb +84 -0
- data/lib/rdoc/generator/pot/po_entry.rb +141 -0
- data/lib/rdoc/generator/pot.rb +98 -0
- data/lib/rdoc/generator/ri.rb +31 -0
- data/lib/rdoc/generator/template/darkfish/.document +0 -0
- data/lib/rdoc/generator/template/darkfish/_footer.rhtml +5 -0
- data/lib/rdoc/generator/template/darkfish/_head.rhtml +22 -0
- data/lib/rdoc/generator/template/darkfish/_sidebar_VCS_info.rhtml +19 -0
- data/lib/rdoc/generator/template/darkfish/_sidebar_classes.rhtml +9 -0
- data/lib/rdoc/generator/template/darkfish/_sidebar_extends.rhtml +15 -0
- data/lib/rdoc/generator/template/darkfish/_sidebar_in_files.rhtml +9 -0
- data/lib/rdoc/generator/template/darkfish/_sidebar_includes.rhtml +15 -0
- data/lib/rdoc/generator/template/darkfish/_sidebar_installed.rhtml +15 -0
- data/lib/rdoc/generator/template/darkfish/_sidebar_methods.rhtml +12 -0
- data/lib/rdoc/generator/template/darkfish/_sidebar_navigation.rhtml +11 -0
- data/lib/rdoc/generator/template/darkfish/_sidebar_pages.rhtml +12 -0
- data/lib/rdoc/generator/template/darkfish/_sidebar_parent.rhtml +11 -0
- data/lib/rdoc/generator/template/darkfish/_sidebar_search.rhtml +14 -0
- data/lib/rdoc/generator/template/darkfish/_sidebar_sections.rhtml +11 -0
- data/lib/rdoc/generator/template/darkfish/_sidebar_table_of_contents.rhtml +18 -0
- data/lib/rdoc/generator/template/darkfish/class.rhtml +172 -0
- data/lib/rdoc/generator/template/darkfish/css/fonts.css +167 -0
- data/lib/rdoc/generator/template/darkfish/css/rdoc.css +639 -0
- data/lib/rdoc/generator/template/darkfish/fonts/Lato-Light.ttf +0 -0
- data/lib/rdoc/generator/template/darkfish/fonts/Lato-LightItalic.ttf +0 -0
- data/lib/rdoc/generator/template/darkfish/fonts/Lato-Regular.ttf +0 -0
- data/lib/rdoc/generator/template/darkfish/fonts/Lato-RegularItalic.ttf +0 -0
- data/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Bold.ttf +0 -0
- data/lib/rdoc/generator/template/darkfish/fonts/SourceCodePro-Regular.ttf +0 -0
- data/lib/rdoc/generator/template/darkfish/images/add.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/arrow_up.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/brick.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/brick_link.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/bug.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/bullet_black.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/bullet_toggle_minus.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/bullet_toggle_plus.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/date.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/delete.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/find.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/loadingAnimation.gif +0 -0
- data/lib/rdoc/generator/template/darkfish/images/macFFBgHack.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/package.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/page_green.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/page_white_text.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/page_white_width.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/plugin.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/ruby.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/tag_blue.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/tag_green.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/transparent.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/wrench.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/wrench_orange.png +0 -0
- data/lib/rdoc/generator/template/darkfish/images/zoom.png +0 -0
- data/lib/rdoc/generator/template/darkfish/index.rhtml +22 -0
- data/lib/rdoc/generator/template/darkfish/js/darkfish.js +84 -0
- data/lib/rdoc/generator/template/darkfish/js/search.js +110 -0
- data/lib/rdoc/generator/template/darkfish/page.rhtml +18 -0
- data/lib/rdoc/generator/template/darkfish/servlet_not_found.rhtml +18 -0
- data/lib/rdoc/generator/template/darkfish/servlet_root.rhtml +62 -0
- data/lib/rdoc/generator/template/darkfish/table_of_contents.rhtml +58 -0
- data/lib/rdoc/generator/template/json_index/.document +1 -0
- data/lib/rdoc/generator/template/json_index/js/navigation.js +105 -0
- data/lib/rdoc/generator/template/json_index/js/searcher.js +229 -0
- data/lib/rdoc/generator.rb +51 -0
- data/lib/rdoc/ghost_method.rb +7 -0
- data/lib/rdoc/i18n/locale.rb +102 -0
- data/lib/rdoc/i18n/text.rb +126 -0
- data/lib/rdoc/i18n.rb +10 -0
- data/lib/rdoc/include.rb +10 -0
- data/lib/rdoc/known_classes.rb +73 -0
- data/lib/rdoc/markdown/entities.rb +2132 -0
- data/lib/rdoc/markdown/literals.kpeg +23 -0
- data/lib/rdoc/markdown/literals.rb +417 -0
- data/lib/rdoc/markdown.kpeg +1237 -0
- data/lib/rdoc/markdown.rb +16685 -0
- data/lib/rdoc/markup/attr_changer.rb +23 -0
- data/lib/rdoc/markup/attr_span.rb +36 -0
- data/lib/rdoc/markup/attribute_manager.rb +409 -0
- data/lib/rdoc/markup/attributes.rb +71 -0
- data/lib/rdoc/markup/blank_line.rb +28 -0
- data/lib/rdoc/markup/block_quote.rb +15 -0
- data/lib/rdoc/markup/document.rb +165 -0
- data/lib/rdoc/markup/formatter.rb +266 -0
- data/lib/rdoc/markup/hard_break.rb +32 -0
- data/lib/rdoc/markup/heading.rb +79 -0
- data/lib/rdoc/markup/include.rb +43 -0
- data/lib/rdoc/markup/indented_paragraph.rb +48 -0
- data/lib/rdoc/markup/list.rb +102 -0
- data/lib/rdoc/markup/list_item.rb +100 -0
- data/lib/rdoc/markup/paragraph.rb +29 -0
- data/lib/rdoc/markup/parser.rb +575 -0
- data/lib/rdoc/markup/pre_process.rb +296 -0
- data/lib/rdoc/markup/raw.rb +70 -0
- data/lib/rdoc/markup/regexp_handling.rb +41 -0
- data/lib/rdoc/markup/rule.rb +21 -0
- data/lib/rdoc/markup/table.rb +47 -0
- data/lib/rdoc/markup/to_ansi.rb +94 -0
- data/lib/rdoc/markup/to_bs.rb +77 -0
- data/lib/rdoc/markup/to_html.rb +444 -0
- data/lib/rdoc/markup/to_html_crossref.rb +176 -0
- data/lib/rdoc/markup/to_html_snippet.rb +285 -0
- data/lib/rdoc/markup/to_joined_paragraph.rb +47 -0
- data/lib/rdoc/markup/to_label.rb +75 -0
- data/lib/rdoc/markup/to_markdown.rb +192 -0
- data/lib/rdoc/markup/to_rdoc.rb +362 -0
- data/lib/rdoc/markup/to_table_of_contents.rb +89 -0
- data/lib/rdoc/markup/to_test.rb +70 -0
- data/lib/rdoc/markup/to_tt_only.rb +121 -0
- data/lib/rdoc/markup/verbatim.rb +84 -0
- data/lib/rdoc/markup.rb +867 -0
- data/lib/rdoc/meta_method.rb +7 -0
- data/lib/rdoc/method_attr.rb +419 -0
- data/lib/rdoc/mixin.rb +121 -0
- data/lib/rdoc/normal_class.rb +93 -0
- data/lib/rdoc/normal_module.rb +74 -0
- data/lib/rdoc/options.rb +1285 -0
- data/lib/rdoc/parser/c.rb +1225 -0
- data/lib/rdoc/parser/changelog.rb +335 -0
- data/lib/rdoc/parser/markdown.rb +24 -0
- data/lib/rdoc/parser/rd.rb +23 -0
- data/lib/rdoc/parser/ripper_state_lex.rb +590 -0
- data/lib/rdoc/parser/ruby.rb +2327 -0
- data/lib/rdoc/parser/ruby_tools.rb +167 -0
- data/lib/rdoc/parser/simple.rb +61 -0
- data/lib/rdoc/parser/text.rb +12 -0
- data/lib/rdoc/parser.rb +277 -0
- data/lib/rdoc/rd/block_parser.rb +1056 -0
- data/lib/rdoc/rd/block_parser.ry +639 -0
- data/lib/rdoc/rd/inline.rb +72 -0
- data/lib/rdoc/rd/inline_parser.rb +1208 -0
- data/lib/rdoc/rd/inline_parser.ry +593 -0
- data/lib/rdoc/rd.rb +100 -0
- data/lib/rdoc/rdoc.rb +579 -0
- data/lib/rdoc/require.rb +52 -0
- data/lib/rdoc/ri/driver.rb +1572 -0
- data/lib/rdoc/ri/formatter.rb +6 -0
- data/lib/rdoc/ri/paths.rb +171 -0
- data/lib/rdoc/ri/store.rb +7 -0
- data/lib/rdoc/ri/task.rb +71 -0
- data/lib/rdoc/ri.rb +21 -0
- data/lib/rdoc/rubygems_hook.rb +246 -0
- data/lib/rdoc/servlet.rb +451 -0
- data/lib/rdoc/single_class.rb +26 -0
- data/lib/rdoc/stats/normal.rb +58 -0
- data/lib/rdoc/stats/quiet.rb +60 -0
- data/lib/rdoc/stats/verbose.rb +46 -0
- data/lib/rdoc/stats.rb +462 -0
- data/lib/rdoc/store.rb +979 -0
- data/lib/rdoc/task.rb +329 -0
- data/lib/rdoc/text.rb +304 -0
- data/lib/rdoc/token_stream.rb +119 -0
- data/lib/rdoc/tom_doc.rb +263 -0
- data/lib/rdoc/top_level.rb +289 -0
- data/lib/rdoc/version.rb +8 -0
- data/lib/rdoc.rb +201 -0
- data/man/ri.1 +247 -0
- data/rdoc.gemspec +249 -0
- metadata +279 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
##
|
|
3
|
+
# A hard-break in the middle of a paragraph.
|
|
4
|
+
|
|
5
|
+
class RDoc::Markup::HardBreak
|
|
6
|
+
|
|
7
|
+
@instance = new
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# RDoc::Markup::HardBreak is a singleton
|
|
11
|
+
|
|
12
|
+
def self.new
|
|
13
|
+
@instance
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
# Calls #accept_hard_break on +visitor+
|
|
18
|
+
|
|
19
|
+
def accept visitor
|
|
20
|
+
visitor.accept_hard_break self
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def == other # :nodoc:
|
|
24
|
+
self.class === other
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def pretty_print q # :nodoc:
|
|
28
|
+
q.text "[break]"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
##
|
|
3
|
+
# A heading with a level (1-6) and text
|
|
4
|
+
|
|
5
|
+
RDoc::Markup::Heading =
|
|
6
|
+
Struct.new :level, :text do
|
|
7
|
+
|
|
8
|
+
@to_html = nil
|
|
9
|
+
@to_label = nil
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# A singleton RDoc::Markup::ToLabel formatter for headings.
|
|
13
|
+
|
|
14
|
+
def self.to_label
|
|
15
|
+
@to_label ||= RDoc::Markup::ToLabel.new
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# A singleton plain HTML formatter for headings. Used for creating labels
|
|
20
|
+
# for the Table of Contents
|
|
21
|
+
|
|
22
|
+
def self.to_html
|
|
23
|
+
return @to_html if @to_html
|
|
24
|
+
|
|
25
|
+
markup = RDoc::Markup.new
|
|
26
|
+
markup.add_regexp_handling RDoc::CrossReference::CROSSREF_REGEXP, :CROSSREF
|
|
27
|
+
|
|
28
|
+
@to_html = RDoc::Markup::ToHtml.new nil
|
|
29
|
+
|
|
30
|
+
def @to_html.handle_regexp_CROSSREF target
|
|
31
|
+
target.text.sub(/^\\/, '')
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
@to_html
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
##
|
|
38
|
+
# Calls #accept_heading on +visitor+
|
|
39
|
+
|
|
40
|
+
def accept visitor
|
|
41
|
+
visitor.accept_heading self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
##
|
|
45
|
+
# An HTML-safe anchor reference for this header.
|
|
46
|
+
|
|
47
|
+
def aref
|
|
48
|
+
"label-#{self.class.to_label.convert text.dup}"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
##
|
|
52
|
+
# Creates a fully-qualified label which will include the label from
|
|
53
|
+
# +context+. This helps keep ids unique in HTML.
|
|
54
|
+
|
|
55
|
+
def label context = nil
|
|
56
|
+
label = aref
|
|
57
|
+
|
|
58
|
+
label = [context.aref, label].compact.join '-' if
|
|
59
|
+
context and context.respond_to? :aref
|
|
60
|
+
|
|
61
|
+
label
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
##
|
|
65
|
+
# HTML markup of the text of this label without the surrounding header
|
|
66
|
+
# element.
|
|
67
|
+
|
|
68
|
+
def plain_html
|
|
69
|
+
self.class.to_html.to_html(text.dup)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def pretty_print q # :nodoc:
|
|
73
|
+
q.group 2, "[head: #{level} ", ']' do
|
|
74
|
+
q.pp text
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
##
|
|
3
|
+
# A file included at generation time. Objects of this class are created by
|
|
4
|
+
# RDoc::RD for an extension-less include.
|
|
5
|
+
#
|
|
6
|
+
# This implementation in incomplete.
|
|
7
|
+
|
|
8
|
+
class RDoc::Markup::Include
|
|
9
|
+
|
|
10
|
+
##
|
|
11
|
+
# The filename to be included, without extension
|
|
12
|
+
|
|
13
|
+
attr_reader :file
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# Directories to search for #file
|
|
17
|
+
|
|
18
|
+
attr_reader :include_path
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# Creates a new include that will import +file+ from +include_path+
|
|
22
|
+
|
|
23
|
+
def initialize file, include_path
|
|
24
|
+
@file = file
|
|
25
|
+
@include_path = include_path
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def == other # :nodoc:
|
|
29
|
+
self.class === other and
|
|
30
|
+
@file == other.file and @include_path == other.include_path
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def pretty_print q # :nodoc:
|
|
34
|
+
q.group 2, '[incl ', ']' do
|
|
35
|
+
q.text file
|
|
36
|
+
q.breakable
|
|
37
|
+
q.text 'from '
|
|
38
|
+
q.pp include_path
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
##
|
|
3
|
+
# An Indented Paragraph of text
|
|
4
|
+
|
|
5
|
+
class RDoc::Markup::IndentedParagraph < RDoc::Markup::Raw
|
|
6
|
+
|
|
7
|
+
##
|
|
8
|
+
# The indent in number of spaces
|
|
9
|
+
|
|
10
|
+
attr_reader :indent
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
# Creates a new IndentedParagraph containing +parts+ indented with +indent+
|
|
14
|
+
# spaces
|
|
15
|
+
|
|
16
|
+
def initialize indent, *parts
|
|
17
|
+
@indent = indent
|
|
18
|
+
|
|
19
|
+
super(*parts)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def == other # :nodoc:
|
|
23
|
+
super and indent == other.indent
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# Calls #accept_indented_paragraph on +visitor+
|
|
28
|
+
|
|
29
|
+
def accept visitor
|
|
30
|
+
visitor.accept_indented_paragraph self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
# Joins the raw paragraph text and converts inline HardBreaks to the
|
|
35
|
+
# +hard_break+ text followed by the indent.
|
|
36
|
+
|
|
37
|
+
def text hard_break = nil
|
|
38
|
+
@parts.map do |part|
|
|
39
|
+
if RDoc::Markup::HardBreak === part then
|
|
40
|
+
'%1$s%3$*2$s' % [hard_break, @indent, ' '] if hard_break
|
|
41
|
+
else
|
|
42
|
+
part
|
|
43
|
+
end
|
|
44
|
+
end.join
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
##
|
|
3
|
+
# A List is a homogeneous set of ListItems.
|
|
4
|
+
#
|
|
5
|
+
# The supported list types include:
|
|
6
|
+
#
|
|
7
|
+
# :BULLET::
|
|
8
|
+
# An unordered list
|
|
9
|
+
# :LABEL::
|
|
10
|
+
# An unordered definition list, but using an alternate RDoc::Markup syntax
|
|
11
|
+
# :LALPHA::
|
|
12
|
+
# An ordered list using increasing lowercase English letters
|
|
13
|
+
# :NOTE::
|
|
14
|
+
# An unordered definition list
|
|
15
|
+
# :NUMBER::
|
|
16
|
+
# An ordered list using increasing Arabic numerals
|
|
17
|
+
# :UALPHA::
|
|
18
|
+
# An ordered list using increasing uppercase English letters
|
|
19
|
+
#
|
|
20
|
+
# Definition lists behave like HTML definition lists. Each list item can
|
|
21
|
+
# describe multiple terms. See RDoc::Markup::ListItem for how labels and
|
|
22
|
+
# definition are stored as list items.
|
|
23
|
+
|
|
24
|
+
class RDoc::Markup::List
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# The list's type
|
|
28
|
+
|
|
29
|
+
attr_accessor :type
|
|
30
|
+
|
|
31
|
+
##
|
|
32
|
+
# Items in the list
|
|
33
|
+
|
|
34
|
+
attr_reader :items
|
|
35
|
+
|
|
36
|
+
##
|
|
37
|
+
# Creates a new list of +type+ with +items+. Valid list types are:
|
|
38
|
+
# +:BULLET+, +:LABEL+, +:LALPHA+, +:NOTE+, +:NUMBER+, +:UALPHA+
|
|
39
|
+
|
|
40
|
+
def initialize type = nil, *items
|
|
41
|
+
@type = type
|
|
42
|
+
@items = []
|
|
43
|
+
@items.concat items
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
##
|
|
47
|
+
# Appends +item+ to the list
|
|
48
|
+
|
|
49
|
+
def << item
|
|
50
|
+
@items << item
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def == other # :nodoc:
|
|
54
|
+
self.class == other.class and
|
|
55
|
+
@type == other.type and
|
|
56
|
+
@items == other.items
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
##
|
|
60
|
+
# Runs this list and all its #items through +visitor+
|
|
61
|
+
|
|
62
|
+
def accept visitor
|
|
63
|
+
visitor.accept_list_start self
|
|
64
|
+
|
|
65
|
+
@items.each do |item|
|
|
66
|
+
item.accept visitor
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
visitor.accept_list_end self
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# Is the list empty?
|
|
74
|
+
|
|
75
|
+
def empty?
|
|
76
|
+
@items.empty?
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
##
|
|
80
|
+
# Returns the last item in the list
|
|
81
|
+
|
|
82
|
+
def last
|
|
83
|
+
@items.last
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def pretty_print q # :nodoc:
|
|
87
|
+
q.group 2, "[list: #{@type} ", ']' do
|
|
88
|
+
q.seplist @items do |item|
|
|
89
|
+
q.pp item
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
##
|
|
95
|
+
# Appends +items+ to the list
|
|
96
|
+
|
|
97
|
+
def push *items
|
|
98
|
+
@items.concat items
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|
|
102
|
+
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
##
|
|
3
|
+
# An item within a List that contains paragraphs, headings, etc.
|
|
4
|
+
#
|
|
5
|
+
# For BULLET, NUMBER, LALPHA and UALPHA lists, the label will always be nil.
|
|
6
|
+
# For NOTE and LABEL lists, the list label may contain:
|
|
7
|
+
#
|
|
8
|
+
# * a single String for a single label
|
|
9
|
+
# * an Array of Strings for a list item with multiple terms
|
|
10
|
+
# * nil for an extra description attached to a previously labeled list item
|
|
11
|
+
|
|
12
|
+
class RDoc::Markup::ListItem
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
# The label for the ListItem
|
|
16
|
+
|
|
17
|
+
attr_accessor :label
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# Parts of the ListItem
|
|
21
|
+
|
|
22
|
+
attr_reader :parts
|
|
23
|
+
|
|
24
|
+
##
|
|
25
|
+
# Creates a new ListItem with an optional +label+ containing +parts+
|
|
26
|
+
|
|
27
|
+
def initialize label = nil, *parts
|
|
28
|
+
@label = label
|
|
29
|
+
@parts = []
|
|
30
|
+
@parts.concat parts
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
# Appends +part+ to the ListItem
|
|
35
|
+
|
|
36
|
+
def << part
|
|
37
|
+
@parts << part
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def == other # :nodoc:
|
|
41
|
+
self.class == other.class and
|
|
42
|
+
@label == other.label and
|
|
43
|
+
@parts == other.parts
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
##
|
|
47
|
+
# Runs this list item and all its #parts through +visitor+
|
|
48
|
+
|
|
49
|
+
def accept visitor
|
|
50
|
+
visitor.accept_list_item_start self
|
|
51
|
+
|
|
52
|
+
@parts.each do |part|
|
|
53
|
+
part.accept visitor
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
visitor.accept_list_item_end self
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
##
|
|
60
|
+
# Is the ListItem empty?
|
|
61
|
+
|
|
62
|
+
def empty?
|
|
63
|
+
@parts.empty?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
##
|
|
67
|
+
# Length of parts in the ListItem
|
|
68
|
+
|
|
69
|
+
def length
|
|
70
|
+
@parts.length
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def pretty_print q # :nodoc:
|
|
74
|
+
q.group 2, '[item: ', ']' do
|
|
75
|
+
case @label
|
|
76
|
+
when Array then
|
|
77
|
+
q.pp @label
|
|
78
|
+
q.text ';'
|
|
79
|
+
q.breakable
|
|
80
|
+
when String then
|
|
81
|
+
q.pp @label
|
|
82
|
+
q.text ';'
|
|
83
|
+
q.breakable
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
q.seplist @parts do |part|
|
|
87
|
+
q.pp part
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
##
|
|
93
|
+
# Adds +parts+ to the ListItem
|
|
94
|
+
|
|
95
|
+
def push *parts
|
|
96
|
+
@parts.concat parts
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
##
|
|
3
|
+
# A Paragraph of text
|
|
4
|
+
|
|
5
|
+
class RDoc::Markup::Paragraph < RDoc::Markup::Raw
|
|
6
|
+
|
|
7
|
+
##
|
|
8
|
+
# Calls #accept_paragraph on +visitor+
|
|
9
|
+
|
|
10
|
+
def accept visitor
|
|
11
|
+
visitor.accept_paragraph self
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
# Joins the raw paragraph text and converts inline HardBreaks to the
|
|
16
|
+
# +hard_break+ text.
|
|
17
|
+
|
|
18
|
+
def text hard_break = ''
|
|
19
|
+
@parts.map do |part|
|
|
20
|
+
if RDoc::Markup::HardBreak === part then
|
|
21
|
+
hard_break
|
|
22
|
+
else
|
|
23
|
+
part
|
|
24
|
+
end
|
|
25
|
+
end.join
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
@@ -0,0 +1,575 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'strscan'
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
# A recursive-descent parser for RDoc markup.
|
|
6
|
+
#
|
|
7
|
+
# The parser tokenizes an input string then parses the tokens into a Document.
|
|
8
|
+
# Documents can be converted into output formats by writing a visitor like
|
|
9
|
+
# RDoc::Markup::ToHTML.
|
|
10
|
+
#
|
|
11
|
+
# The parser only handles the block-level constructs Paragraph, List,
|
|
12
|
+
# ListItem, Heading, Verbatim, BlankLine, Rule and BlockQuote.
|
|
13
|
+
# Inline markup such as <tt>\+blah\+</tt> is handled separately by
|
|
14
|
+
# RDoc::Markup::AttributeManager.
|
|
15
|
+
#
|
|
16
|
+
# To see what markup the Parser implements read RDoc. To see how to use
|
|
17
|
+
# RDoc markup to format text in your program read RDoc::Markup.
|
|
18
|
+
|
|
19
|
+
class RDoc::Markup::Parser
|
|
20
|
+
|
|
21
|
+
include RDoc::Text
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
# List token types
|
|
25
|
+
|
|
26
|
+
LIST_TOKENS = [
|
|
27
|
+
:BULLET,
|
|
28
|
+
:LABEL,
|
|
29
|
+
:LALPHA,
|
|
30
|
+
:NOTE,
|
|
31
|
+
:NUMBER,
|
|
32
|
+
:UALPHA,
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
##
|
|
36
|
+
# Parser error subclass
|
|
37
|
+
|
|
38
|
+
class Error < RuntimeError; end
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
# Raised when the parser is unable to handle the given markup
|
|
42
|
+
|
|
43
|
+
class ParseError < Error; end
|
|
44
|
+
|
|
45
|
+
##
|
|
46
|
+
# Enables display of debugging information
|
|
47
|
+
|
|
48
|
+
attr_accessor :debug
|
|
49
|
+
|
|
50
|
+
##
|
|
51
|
+
# Token accessor
|
|
52
|
+
|
|
53
|
+
attr_reader :tokens
|
|
54
|
+
|
|
55
|
+
##
|
|
56
|
+
# Parses +str+ into a Document.
|
|
57
|
+
#
|
|
58
|
+
# Use RDoc::Markup#parse instead of this method.
|
|
59
|
+
|
|
60
|
+
def self.parse str
|
|
61
|
+
parser = new
|
|
62
|
+
parser.tokenize str
|
|
63
|
+
doc = RDoc::Markup::Document.new
|
|
64
|
+
parser.parse doc
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
##
|
|
68
|
+
# Returns a token stream for +str+, for testing
|
|
69
|
+
|
|
70
|
+
def self.tokenize str
|
|
71
|
+
parser = new
|
|
72
|
+
parser.tokenize str
|
|
73
|
+
parser.tokens
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
##
|
|
77
|
+
# Creates a new Parser. See also ::parse
|
|
78
|
+
|
|
79
|
+
def initialize
|
|
80
|
+
@binary_input = nil
|
|
81
|
+
@current_token = nil
|
|
82
|
+
@debug = false
|
|
83
|
+
@s = nil
|
|
84
|
+
@tokens = []
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
##
|
|
88
|
+
# Builds a Heading of +level+
|
|
89
|
+
|
|
90
|
+
def build_heading level
|
|
91
|
+
type, text, = get
|
|
92
|
+
|
|
93
|
+
text = case type
|
|
94
|
+
when :TEXT then
|
|
95
|
+
skip :NEWLINE
|
|
96
|
+
text
|
|
97
|
+
else
|
|
98
|
+
unget
|
|
99
|
+
''
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
RDoc::Markup::Heading.new level, text
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
##
|
|
106
|
+
# Builds a List flush to +margin+
|
|
107
|
+
|
|
108
|
+
def build_list margin
|
|
109
|
+
p :list_start => margin if @debug
|
|
110
|
+
|
|
111
|
+
list = RDoc::Markup::List.new
|
|
112
|
+
label = nil
|
|
113
|
+
|
|
114
|
+
until @tokens.empty? do
|
|
115
|
+
type, data, column, = get
|
|
116
|
+
|
|
117
|
+
case type
|
|
118
|
+
when *LIST_TOKENS then
|
|
119
|
+
if column < margin || (list.type && list.type != type) then
|
|
120
|
+
unget
|
|
121
|
+
break
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
list.type = type
|
|
125
|
+
peek_type, _, column, = peek_token
|
|
126
|
+
|
|
127
|
+
case type
|
|
128
|
+
when :NOTE, :LABEL then
|
|
129
|
+
label = [] unless label
|
|
130
|
+
|
|
131
|
+
if peek_type == :NEWLINE then
|
|
132
|
+
# description not on the same line as LABEL/NOTE
|
|
133
|
+
# skip the trailing newline & any blank lines below
|
|
134
|
+
while peek_type == :NEWLINE
|
|
135
|
+
get
|
|
136
|
+
peek_type, _, column, = peek_token
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# we may be:
|
|
140
|
+
# - at end of stream
|
|
141
|
+
# - at a column < margin:
|
|
142
|
+
# [text]
|
|
143
|
+
# blah blah blah
|
|
144
|
+
# - at the same column, but with a different type of list item
|
|
145
|
+
# [text]
|
|
146
|
+
# * blah blah
|
|
147
|
+
# - at the same column, with the same type of list item
|
|
148
|
+
# [one]
|
|
149
|
+
# [two]
|
|
150
|
+
# In all cases, we have an empty description.
|
|
151
|
+
# In the last case only, we continue.
|
|
152
|
+
if peek_type.nil? || column < margin then
|
|
153
|
+
empty = true
|
|
154
|
+
elsif column == margin then
|
|
155
|
+
case peek_type
|
|
156
|
+
when type
|
|
157
|
+
empty = :continue
|
|
158
|
+
when *LIST_TOKENS
|
|
159
|
+
empty = true
|
|
160
|
+
else
|
|
161
|
+
empty = false
|
|
162
|
+
end
|
|
163
|
+
else
|
|
164
|
+
empty = false
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
if empty then
|
|
168
|
+
label << data
|
|
169
|
+
next if empty == :continue
|
|
170
|
+
break
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
else
|
|
174
|
+
data = nil
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
if label then
|
|
178
|
+
data = label << data
|
|
179
|
+
label = nil
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
list_item = RDoc::Markup::ListItem.new data
|
|
183
|
+
parse list_item, column
|
|
184
|
+
list << list_item
|
|
185
|
+
|
|
186
|
+
else
|
|
187
|
+
unget
|
|
188
|
+
break
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
p :list_end => margin if @debug
|
|
193
|
+
|
|
194
|
+
if list.empty? then
|
|
195
|
+
return nil unless label
|
|
196
|
+
return nil unless [:LABEL, :NOTE].include? list.type
|
|
197
|
+
|
|
198
|
+
list_item = RDoc::Markup::ListItem.new label, RDoc::Markup::BlankLine.new
|
|
199
|
+
list << list_item
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
list
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
##
|
|
206
|
+
# Builds a Paragraph that is flush to +margin+
|
|
207
|
+
|
|
208
|
+
def build_paragraph margin
|
|
209
|
+
p :paragraph_start => margin if @debug
|
|
210
|
+
|
|
211
|
+
paragraph = RDoc::Markup::Paragraph.new
|
|
212
|
+
|
|
213
|
+
until @tokens.empty? do
|
|
214
|
+
type, data, column, = get
|
|
215
|
+
|
|
216
|
+
if type == :TEXT and column == margin then
|
|
217
|
+
paragraph << data
|
|
218
|
+
|
|
219
|
+
break if peek_token.first == :BREAK
|
|
220
|
+
|
|
221
|
+
data << ' ' if skip :NEWLINE
|
|
222
|
+
else
|
|
223
|
+
unget
|
|
224
|
+
break
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
paragraph.parts.last.sub!(/ \z/, '') # cleanup
|
|
229
|
+
|
|
230
|
+
p :paragraph_end => margin if @debug
|
|
231
|
+
|
|
232
|
+
paragraph
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
##
|
|
236
|
+
# Builds a Verbatim that is indented from +margin+.
|
|
237
|
+
#
|
|
238
|
+
# The verbatim block is shifted left (the least indented lines start in
|
|
239
|
+
# column 0). Each part of the verbatim is one line of text, always
|
|
240
|
+
# terminated by a newline. Blank lines always consist of a single newline
|
|
241
|
+
# character, and there is never a single newline at the end of the verbatim.
|
|
242
|
+
|
|
243
|
+
def build_verbatim margin
|
|
244
|
+
p :verbatim_begin => margin if @debug
|
|
245
|
+
verbatim = RDoc::Markup::Verbatim.new
|
|
246
|
+
|
|
247
|
+
min_indent = nil
|
|
248
|
+
generate_leading_spaces = true
|
|
249
|
+
line = ''.dup
|
|
250
|
+
|
|
251
|
+
until @tokens.empty? do
|
|
252
|
+
type, data, column, = get
|
|
253
|
+
|
|
254
|
+
if type == :NEWLINE then
|
|
255
|
+
line << data
|
|
256
|
+
verbatim << line
|
|
257
|
+
line = ''.dup
|
|
258
|
+
generate_leading_spaces = true
|
|
259
|
+
next
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
if column <= margin
|
|
263
|
+
unget
|
|
264
|
+
break
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
if generate_leading_spaces then
|
|
268
|
+
indent = column - margin
|
|
269
|
+
line << ' ' * indent
|
|
270
|
+
min_indent = indent if min_indent.nil? || indent < min_indent
|
|
271
|
+
generate_leading_spaces = false
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
case type
|
|
275
|
+
when :HEADER then
|
|
276
|
+
line << '=' * data
|
|
277
|
+
_, _, peek_column, = peek_token
|
|
278
|
+
peek_column ||= column + data
|
|
279
|
+
indent = peek_column - column - data
|
|
280
|
+
line << ' ' * indent
|
|
281
|
+
when :RULE then
|
|
282
|
+
width = 2 + data
|
|
283
|
+
line << '-' * width
|
|
284
|
+
_, _, peek_column, = peek_token
|
|
285
|
+
peek_column ||= column + width
|
|
286
|
+
indent = peek_column - column - width
|
|
287
|
+
line << ' ' * indent
|
|
288
|
+
when :BREAK, :TEXT then
|
|
289
|
+
line << data
|
|
290
|
+
else # *LIST_TOKENS
|
|
291
|
+
list_marker = case type
|
|
292
|
+
when :BULLET then data
|
|
293
|
+
when :LABEL then "[#{data}]"
|
|
294
|
+
when :NOTE then "#{data}::"
|
|
295
|
+
else # :LALPHA, :NUMBER, :UALPHA
|
|
296
|
+
"#{data}."
|
|
297
|
+
end
|
|
298
|
+
line << list_marker
|
|
299
|
+
peek_type, _, peek_column = peek_token
|
|
300
|
+
unless peek_type == :NEWLINE then
|
|
301
|
+
peek_column ||= column + list_marker.length
|
|
302
|
+
indent = peek_column - column - list_marker.length
|
|
303
|
+
line << ' ' * indent
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
verbatim << line << "\n" unless line.empty?
|
|
310
|
+
verbatim.parts.each { |p| p.slice!(0, min_indent) unless p == "\n" } if min_indent > 0
|
|
311
|
+
verbatim.normalize
|
|
312
|
+
|
|
313
|
+
p :verbatim_end => margin if @debug
|
|
314
|
+
|
|
315
|
+
verbatim
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
##
|
|
319
|
+
# Pulls the next token from the stream.
|
|
320
|
+
|
|
321
|
+
def get
|
|
322
|
+
@current_token = @tokens.shift
|
|
323
|
+
p :get => @current_token if @debug
|
|
324
|
+
@current_token
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
##
|
|
328
|
+
# Parses the tokens into an array of RDoc::Markup::XXX objects,
|
|
329
|
+
# and appends them to the passed +parent+ RDoc::Markup::YYY object.
|
|
330
|
+
#
|
|
331
|
+
# Exits at the end of the token stream, or when it encounters a token
|
|
332
|
+
# in a column less than +indent+ (unless it is a NEWLINE).
|
|
333
|
+
#
|
|
334
|
+
# Returns +parent+.
|
|
335
|
+
|
|
336
|
+
def parse parent, indent = 0
|
|
337
|
+
p :parse_start => indent if @debug
|
|
338
|
+
|
|
339
|
+
until @tokens.empty? do
|
|
340
|
+
type, data, column, = get
|
|
341
|
+
|
|
342
|
+
case type
|
|
343
|
+
when :BREAK then
|
|
344
|
+
parent << RDoc::Markup::BlankLine.new
|
|
345
|
+
skip :NEWLINE, false
|
|
346
|
+
next
|
|
347
|
+
when :NEWLINE then
|
|
348
|
+
# trailing newlines are skipped below, so this is a blank line
|
|
349
|
+
parent << RDoc::Markup::BlankLine.new
|
|
350
|
+
skip :NEWLINE, false
|
|
351
|
+
next
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
# indentation change: break or verbatim
|
|
355
|
+
if column < indent then
|
|
356
|
+
unget
|
|
357
|
+
break
|
|
358
|
+
elsif column > indent then
|
|
359
|
+
unget
|
|
360
|
+
parent << build_verbatim(indent)
|
|
361
|
+
next
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
# indentation is the same
|
|
365
|
+
case type
|
|
366
|
+
when :HEADER then
|
|
367
|
+
parent << build_heading(data)
|
|
368
|
+
when :RULE then
|
|
369
|
+
parent << RDoc::Markup::Rule.new(data)
|
|
370
|
+
skip :NEWLINE
|
|
371
|
+
when :TEXT then
|
|
372
|
+
unget
|
|
373
|
+
parse_text parent, indent
|
|
374
|
+
when :BLOCKQUOTE then
|
|
375
|
+
type, _, column = get
|
|
376
|
+
if type == :NEWLINE
|
|
377
|
+
type, _, column = get
|
|
378
|
+
end
|
|
379
|
+
unget if type
|
|
380
|
+
bq = RDoc::Markup::BlockQuote.new
|
|
381
|
+
p :blockquote_start => [data, column] if @debug
|
|
382
|
+
parse bq, column
|
|
383
|
+
p :blockquote_end => indent if @debug
|
|
384
|
+
parent << bq
|
|
385
|
+
when *LIST_TOKENS then
|
|
386
|
+
unget
|
|
387
|
+
parent << build_list(indent)
|
|
388
|
+
else
|
|
389
|
+
type, data, column, line = @current_token
|
|
390
|
+
raise ParseError, "Unhandled token #{type} (#{data.inspect}) at #{line}:#{column}"
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
p :parse_end => indent if @debug
|
|
395
|
+
|
|
396
|
+
parent
|
|
397
|
+
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
##
|
|
401
|
+
# Small hook that is overridden by RDoc::TomDoc
|
|
402
|
+
|
|
403
|
+
def parse_text parent, indent # :nodoc:
|
|
404
|
+
parent << build_paragraph(indent)
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
##
|
|
408
|
+
# Returns the next token on the stream without modifying the stream
|
|
409
|
+
|
|
410
|
+
def peek_token
|
|
411
|
+
token = @tokens.first || []
|
|
412
|
+
p :peek => token if @debug
|
|
413
|
+
token
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
##
|
|
417
|
+
# A simple wrapper of StringScanner that is aware of the current column and lineno
|
|
418
|
+
|
|
419
|
+
class MyStringScanner
|
|
420
|
+
def initialize(input)
|
|
421
|
+
@line = @column = 0
|
|
422
|
+
@s = StringScanner.new input
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
def scan(re)
|
|
426
|
+
ret = @s.scan(re)
|
|
427
|
+
@column += ret.length if ret
|
|
428
|
+
ret
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def unscan(s)
|
|
432
|
+
@s.pos -= s.bytesize
|
|
433
|
+
@column -= s.length
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
def pos
|
|
437
|
+
[@column, @line]
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
def newline!
|
|
441
|
+
@column = 0
|
|
442
|
+
@line += 1
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
def eos?
|
|
446
|
+
@s.eos?
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def matched
|
|
450
|
+
@s.matched
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
def [](i)
|
|
454
|
+
@s[i]
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
##
|
|
459
|
+
# Creates the StringScanner
|
|
460
|
+
|
|
461
|
+
def setup_scanner input
|
|
462
|
+
@s = MyStringScanner.new input
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
##
|
|
466
|
+
# Skips the next token if its type is +token_type+.
|
|
467
|
+
#
|
|
468
|
+
# Optionally raises an error if the next token is not of the expected type.
|
|
469
|
+
|
|
470
|
+
def skip token_type, error = true
|
|
471
|
+
type, = get
|
|
472
|
+
return unless type # end of stream
|
|
473
|
+
return @current_token if token_type == type
|
|
474
|
+
unget
|
|
475
|
+
raise ParseError, "expected #{token_type} got #{@current_token.inspect}" if error
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
##
|
|
479
|
+
# Turns text +input+ into a stream of tokens
|
|
480
|
+
|
|
481
|
+
def tokenize input
|
|
482
|
+
setup_scanner input
|
|
483
|
+
|
|
484
|
+
until @s.eos? do
|
|
485
|
+
pos = @s.pos
|
|
486
|
+
|
|
487
|
+
# leading spaces will be reflected by the column of the next token
|
|
488
|
+
# the only thing we loose are trailing spaces at the end of the file
|
|
489
|
+
next if @s.scan(/ +/)
|
|
490
|
+
|
|
491
|
+
# note: after BULLET, LABEL, etc.,
|
|
492
|
+
# indent will be the column of the next non-newline token
|
|
493
|
+
|
|
494
|
+
@tokens << case
|
|
495
|
+
# [CR]LF => :NEWLINE
|
|
496
|
+
when @s.scan(/\r?\n/) then
|
|
497
|
+
token = [:NEWLINE, @s.matched, *pos]
|
|
498
|
+
@s.newline!
|
|
499
|
+
token
|
|
500
|
+
# === text => :HEADER then :TEXT
|
|
501
|
+
when @s.scan(/(=+)(\s*)/) then
|
|
502
|
+
level = @s[1].length
|
|
503
|
+
header = [:HEADER, level, *pos]
|
|
504
|
+
|
|
505
|
+
if @s[2] =~ /^\r?\n/ then
|
|
506
|
+
@s.unscan(@s[2])
|
|
507
|
+
header
|
|
508
|
+
else
|
|
509
|
+
pos = @s.pos
|
|
510
|
+
@s.scan(/.*/)
|
|
511
|
+
@tokens << header
|
|
512
|
+
[:TEXT, @s.matched.sub(/\r$/, ''), *pos]
|
|
513
|
+
end
|
|
514
|
+
# --- (at least 3) and nothing else on the line => :RULE
|
|
515
|
+
when @s.scan(/(-{3,}) *\r?$/) then
|
|
516
|
+
[:RULE, @s[1].length - 2, *pos]
|
|
517
|
+
# * or - followed by white space and text => :BULLET
|
|
518
|
+
when @s.scan(/([*-]) +(\S)/) then
|
|
519
|
+
@s.unscan(@s[2])
|
|
520
|
+
[:BULLET, @s[1], *pos]
|
|
521
|
+
# A. text, a. text, 12. text => :UALPHA, :LALPHA, :NUMBER
|
|
522
|
+
when @s.scan(/([a-z]|\d+)\. +(\S)/i) then
|
|
523
|
+
# FIXME if tab(s), the column will be wrong
|
|
524
|
+
# either support tabs everywhere by first expanding them to
|
|
525
|
+
# spaces, or assume that they will have been replaced
|
|
526
|
+
# before (and provide a check for that at least in debug
|
|
527
|
+
# mode)
|
|
528
|
+
list_label = @s[1]
|
|
529
|
+
@s.unscan(@s[2])
|
|
530
|
+
list_type =
|
|
531
|
+
case list_label
|
|
532
|
+
when /[a-z]/ then :LALPHA
|
|
533
|
+
when /[A-Z]/ then :UALPHA
|
|
534
|
+
when /\d/ then :NUMBER
|
|
535
|
+
else
|
|
536
|
+
raise ParseError, "BUG token #{list_label}"
|
|
537
|
+
end
|
|
538
|
+
[list_type, list_label, *pos]
|
|
539
|
+
# [text] followed by spaces or end of line => :LABEL
|
|
540
|
+
when @s.scan(/\[(.*?)\]( +|\r?$)/) then
|
|
541
|
+
[:LABEL, @s[1], *pos]
|
|
542
|
+
# text:: followed by spaces or end of line => :NOTE
|
|
543
|
+
when @s.scan(/(.*?)::( +|\r?$)/) then
|
|
544
|
+
[:NOTE, @s[1], *pos]
|
|
545
|
+
# >>> followed by end of line => :BLOCKQUOTE
|
|
546
|
+
when @s.scan(/>>> *(\w+)?$/) then
|
|
547
|
+
[:BLOCKQUOTE, @s[1], *pos]
|
|
548
|
+
# anything else: :TEXT
|
|
549
|
+
else
|
|
550
|
+
@s.scan(/(.*?)( )?\r?$/)
|
|
551
|
+
token = [:TEXT, @s[1], *pos]
|
|
552
|
+
|
|
553
|
+
if @s[2] then
|
|
554
|
+
@tokens << token
|
|
555
|
+
[:BREAK, @s[2], pos[0] + @s[1].length, pos[1]]
|
|
556
|
+
else
|
|
557
|
+
token
|
|
558
|
+
end
|
|
559
|
+
end
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
self
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
##
|
|
566
|
+
# Returns the current token to the token stream
|
|
567
|
+
|
|
568
|
+
def unget
|
|
569
|
+
token = @current_token
|
|
570
|
+
p :unget => token if @debug
|
|
571
|
+
raise Error, 'too many #ungets' if token == @tokens.first
|
|
572
|
+
@tokens.unshift token if token
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
end
|