org-ruby 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.bnsignore +18 -0
- data/History.txt +40 -32
- data/README.txt +66 -66
- data/Rakefile +27 -26
- data/bin/org-ruby +40 -40
- data/lib/org-ruby.rb +50 -50
- data/lib/org-ruby/headline.rb +80 -75
- data/lib/org-ruby/html_output_buffer.rb +105 -81
- data/lib/org-ruby/line.rb +173 -173
- data/lib/org-ruby/output_buffer.rb +172 -154
- data/lib/org-ruby/parser.rb +80 -76
- data/lib/org-ruby/regexp_helper.rb +156 -156
- data/lib/org-ruby/textile_output_buffer.rb +67 -67
- data/spec/data/freeform.org +111 -111
- data/spec/data/hyp-planning.org +335 -335
- data/spec/data/remember.org +53 -53
- data/spec/headline_spec.rb +55 -55
- data/spec/html_examples/advanced-lists.html +31 -0
- data/spec/html_examples/advanced-lists.org +31 -0
- data/spec/html_examples/block_code.html +30 -30
- data/spec/html_examples/block_code.org +35 -35
- data/spec/html_examples/blockquote.html +7 -7
- data/spec/html_examples/blockquote.org +13 -13
- data/spec/html_examples/escape-pre.html +7 -7
- data/spec/html_examples/escape-pre.org +6 -6
- data/spec/html_examples/inline-formatting.html +10 -10
- data/spec/html_examples/inline-formatting.org +17 -17
- data/spec/html_examples/lists.html +19 -19
- data/spec/html_examples/lists.org +36 -36
- data/spec/html_examples/only-list.html +5 -5
- data/spec/html_examples/only-list.org +3 -3
- data/spec/html_examples/only-table.html +6 -6
- data/spec/html_examples/only-table.org +5 -5
- data/spec/html_examples/tables.html +20 -20
- data/spec/html_examples/tables.org +26 -26
- data/spec/html_examples/text.html +2 -2
- data/spec/html_examples/text.org +16 -16
- data/spec/line_spec.rb +89 -89
- data/spec/parser_spec.rb +86 -86
- data/spec/regexp_helper_spec.rb +57 -57
- data/spec/spec_helper.rb +20 -20
- data/spec/textile_examples/block_code.org +35 -35
- data/spec/textile_examples/block_code.textile +29 -29
- data/spec/textile_examples/blockquote.org +13 -13
- data/spec/textile_examples/blockquote.textile +11 -11
- data/spec/textile_examples/keywords.org +13 -13
- data/spec/textile_examples/keywords.textile +11 -11
- data/spec/textile_examples/links.org +11 -11
- data/spec/textile_examples/links.textile +10 -10
- data/spec/textile_examples/lists.org +36 -36
- data/spec/textile_examples/lists.textile +20 -20
- data/spec/textile_examples/single-space-plain-list.org +13 -13
- data/spec/textile_examples/single-space-plain-list.textile +10 -10
- data/spec/textile_examples/tables.org +26 -26
- data/spec/textile_examples/tables.textile +23 -23
- data/spec/textile_output_buffer_spec.rb +21 -21
- data/tasks/test_case.rake +49 -49
- metadata +5 -2
data/lib/org-ruby/headline.rb
CHANGED
@@ -1,75 +1,80 @@
|
|
1
|
-
require OrgRuby.libpath(*%w[org-ruby line])
|
2
|
-
|
3
|
-
module Orgmode
|
4
|
-
|
5
|
-
# Represents a headline in an orgmode file.
|
6
|
-
class Headline < Line
|
7
|
-
|
8
|
-
# This is the "level" of the headline
|
9
|
-
attr_reader :level
|
10
|
-
|
11
|
-
# This is the headline text -- the part of the headline minus the leading
|
12
|
-
# asterisks, the keywords, and the tags.
|
13
|
-
attr_reader :headline_text
|
14
|
-
|
15
|
-
# This contains the lines that "belong" to the headline.
|
16
|
-
attr_reader :body_lines
|
17
|
-
|
18
|
-
# These are the headline tags
|
19
|
-
attr_reader :tags
|
20
|
-
|
21
|
-
# Optional keyword found at the beginning of the headline.
|
22
|
-
attr_reader :keyword
|
23
|
-
|
24
|
-
# This is the regex that matches a line
|
25
|
-
LineRegexp = /^\*+\s+/
|
26
|
-
|
27
|
-
# This matches the tags on a headline
|
28
|
-
TagsRegexp = /\s*:[\w:]*:\s*$/
|
29
|
-
|
30
|
-
# Special keywords allowed at the start of a line.
|
31
|
-
Keywords = %w[TODO DONE]
|
32
|
-
|
33
|
-
KeywordsRegexp = Regexp.new("\\s*(#{Keywords.join('|')})\\s*")
|
34
|
-
|
35
|
-
def initialize(line)
|
36
|
-
super(line)
|
37
|
-
@body_lines = []
|
38
|
-
@tags = []
|
39
|
-
if (@line =~ LineRegexp) then
|
40
|
-
@level = $&.strip.length
|
41
|
-
@headline_text = $'.strip
|
42
|
-
if (@headline_text =~ TagsRegexp) then
|
43
|
-
@tags = $&.split(/:/) # split tag text on semicolon
|
44
|
-
@tags.delete_at(0) # the first item will be empty; discard
|
45
|
-
@headline_text.gsub!(TagsRegexp, "") # Removes the tags from the headline
|
46
|
-
end
|
47
|
-
if (@headline_text =~ KeywordsRegexp) then
|
48
|
-
@headline_text = $'
|
49
|
-
@keyword = $1
|
50
|
-
end
|
51
|
-
else
|
52
|
-
raise "'#{line}' is not a valid headline"
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# Determines if a line is an orgmode "headline":
|
57
|
-
# A headline begins with one or more asterisks.
|
58
|
-
def self.headline?(line)
|
59
|
-
line =~ LineRegexp
|
60
|
-
end
|
61
|
-
|
62
|
-
# Converts this headline and its body to textile.
|
63
|
-
def to_textile
|
64
|
-
output = "h#{@level}. #{@headline_text}\n"
|
65
|
-
output << Line.to_textile(@body_lines)
|
66
|
-
output
|
67
|
-
end
|
68
|
-
|
69
|
-
def to_html
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
1
|
+
require OrgRuby.libpath(*%w[org-ruby line])
|
2
|
+
|
3
|
+
module Orgmode
|
4
|
+
|
5
|
+
# Represents a headline in an orgmode file.
|
6
|
+
class Headline < Line
|
7
|
+
|
8
|
+
# This is the "level" of the headline
|
9
|
+
attr_reader :level
|
10
|
+
|
11
|
+
# This is the headline text -- the part of the headline minus the leading
|
12
|
+
# asterisks, the keywords, and the tags.
|
13
|
+
attr_reader :headline_text
|
14
|
+
|
15
|
+
# This contains the lines that "belong" to the headline.
|
16
|
+
attr_reader :body_lines
|
17
|
+
|
18
|
+
# These are the headline tags
|
19
|
+
attr_reader :tags
|
20
|
+
|
21
|
+
# Optional keyword found at the beginning of the headline.
|
22
|
+
attr_reader :keyword
|
23
|
+
|
24
|
+
# This is the regex that matches a line
|
25
|
+
LineRegexp = /^\*+\s+/
|
26
|
+
|
27
|
+
# This matches the tags on a headline
|
28
|
+
TagsRegexp = /\s*:[\w:]*:\s*$/
|
29
|
+
|
30
|
+
# Special keywords allowed at the start of a line.
|
31
|
+
Keywords = %w[TODO DONE]
|
32
|
+
|
33
|
+
KeywordsRegexp = Regexp.new("\\s*(#{Keywords.join('|')})\\s*")
|
34
|
+
|
35
|
+
def initialize(line)
|
36
|
+
super(line)
|
37
|
+
@body_lines = []
|
38
|
+
@tags = []
|
39
|
+
if (@line =~ LineRegexp) then
|
40
|
+
@level = $&.strip.length
|
41
|
+
@headline_text = $'.strip
|
42
|
+
if (@headline_text =~ TagsRegexp) then
|
43
|
+
@tags = $&.split(/:/) # split tag text on semicolon
|
44
|
+
@tags.delete_at(0) # the first item will be empty; discard
|
45
|
+
@headline_text.gsub!(TagsRegexp, "") # Removes the tags from the headline
|
46
|
+
end
|
47
|
+
if (@headline_text =~ KeywordsRegexp) then
|
48
|
+
@headline_text = $'
|
49
|
+
@keyword = $1
|
50
|
+
end
|
51
|
+
else
|
52
|
+
raise "'#{line}' is not a valid headline"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Determines if a line is an orgmode "headline":
|
57
|
+
# A headline begins with one or more asterisks.
|
58
|
+
def self.headline?(line)
|
59
|
+
line =~ LineRegexp
|
60
|
+
end
|
61
|
+
|
62
|
+
# Converts this headline and its body to textile.
|
63
|
+
def to_textile
|
64
|
+
output = "h#{@level}. #{@headline_text}\n"
|
65
|
+
output << Line.to_textile(@body_lines)
|
66
|
+
output
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_html(opts = {})
|
70
|
+
if opts[:decorate_title]
|
71
|
+
decoration = " class=\"title\""
|
72
|
+
else
|
73
|
+
decoration = ""
|
74
|
+
end
|
75
|
+
output = "<h#{@level}#{decoration}>#{@headline_text}</h#{@level}>\n"
|
76
|
+
output << Line.to_html(@body_lines)
|
77
|
+
output
|
78
|
+
end
|
79
|
+
end # class Headline
|
80
|
+
end # class Orgmode
|
@@ -1,81 +1,105 @@
|
|
1
|
-
require OrgRuby.libpath(*%w[org-ruby output_buffer])
|
2
|
-
require 'cgi'
|
3
|
-
|
4
|
-
module Orgmode
|
5
|
-
|
6
|
-
class HtmlOutputBuffer < OutputBuffer
|
7
|
-
|
8
|
-
HtmlBlockTag = {
|
9
|
-
:paragraph => "p",
|
10
|
-
:ordered_list => "li",
|
11
|
-
:unordered_list => "li",
|
12
|
-
:table_row => "tr"
|
13
|
-
}
|
14
|
-
|
15
|
-
ModeTag = {
|
16
|
-
:unordered_list => "ul",
|
17
|
-
:ordered_list => "ol",
|
18
|
-
:table => "table",
|
19
|
-
:blockquote => "blockquote",
|
20
|
-
:code => "pre"
|
21
|
-
}
|
22
|
-
|
23
|
-
def
|
24
|
-
super(
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
#
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
1
|
+
require OrgRuby.libpath(*%w[org-ruby output_buffer])
|
2
|
+
require 'cgi'
|
3
|
+
|
4
|
+
module Orgmode
|
5
|
+
|
6
|
+
class HtmlOutputBuffer < OutputBuffer
|
7
|
+
|
8
|
+
HtmlBlockTag = {
|
9
|
+
:paragraph => "p",
|
10
|
+
:ordered_list => "li",
|
11
|
+
:unordered_list => "li",
|
12
|
+
:table_row => "tr"
|
13
|
+
}
|
14
|
+
|
15
|
+
ModeTag = {
|
16
|
+
:unordered_list => "ul",
|
17
|
+
:ordered_list => "ol",
|
18
|
+
:table => "table",
|
19
|
+
:blockquote => "blockquote",
|
20
|
+
:code => "pre"
|
21
|
+
}
|
22
|
+
|
23
|
+
def initialize(output, opts = {})
|
24
|
+
super(output)
|
25
|
+
if opts[:decorate_title] then
|
26
|
+
@title_decoration = " class=\"title\""
|
27
|
+
else
|
28
|
+
@title_decoration = ""
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def push_mode(mode)
|
33
|
+
if ModeTag[mode] then
|
34
|
+
output_indentation
|
35
|
+
@output << "<#{ModeTag[mode]}>\n"
|
36
|
+
# Entering a new mode obliterates the title decoration
|
37
|
+
@title_decoration = ""
|
38
|
+
end
|
39
|
+
super(mode)
|
40
|
+
end
|
41
|
+
|
42
|
+
def pop_mode(mode = nil)
|
43
|
+
m = super(mode)
|
44
|
+
if ModeTag[m] then
|
45
|
+
output_indentation
|
46
|
+
@output << "</#{ModeTag[m]}>\n"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def flush!
|
51
|
+
@logger.debug "FLUSH ==========> #{@output_type}"
|
52
|
+
if current_mode == :code then
|
53
|
+
# Whitespace is significant in :code mode. Always output the buffer
|
54
|
+
# and do not do any additional translation.
|
55
|
+
@output << CGI.escapeHTML(@buffer) << "\n"
|
56
|
+
else
|
57
|
+
if (@buffer.length > 0) then
|
58
|
+
output_indentation
|
59
|
+
@output << "<#{HtmlBlockTag[@output_type]}#{@title_decoration}>" \
|
60
|
+
<< inline_formatting(@buffer) \
|
61
|
+
<< "</#{HtmlBlockTag[@output_type]}>\n"
|
62
|
+
@title_decoration = ""
|
63
|
+
end
|
64
|
+
end
|
65
|
+
@buffer = ""
|
66
|
+
end
|
67
|
+
|
68
|
+
######################################################################
|
69
|
+
private
|
70
|
+
|
71
|
+
def output_indentation
|
72
|
+
indent = " " * (@mode_stack.length - 1)
|
73
|
+
@output << indent
|
74
|
+
end
|
75
|
+
|
76
|
+
Tags = {
|
77
|
+
"*" => { :open => "<b>", :close => "</b>" },
|
78
|
+
"/" => { :open => "<i>", :close => "</i>" },
|
79
|
+
"_" => { :open => "<span style=\"text-decoration:underline;\">",
|
80
|
+
:close => "</span>" },
|
81
|
+
"=" => { :open => "<code>", :close => "</code>" },
|
82
|
+
"~" => { :open => "<code>", :close => "</code>" },
|
83
|
+
"+" => { :open => "<del>", :close => "</del>" }
|
84
|
+
}
|
85
|
+
|
86
|
+
# Applies inline formatting rules to a string.
|
87
|
+
def inline_formatting(str)
|
88
|
+
str.rstrip!
|
89
|
+
str = @re_help.rewrite_emphasis(str) do |marker, s|
|
90
|
+
"#{Tags[marker][:open]}#{s}#{Tags[marker][:close]}"
|
91
|
+
end
|
92
|
+
str = @re_help.rewrite_links(str) do |link, text|
|
93
|
+
text ||= link
|
94
|
+
"<a href=\"#{link}\">#{text}</a>"
|
95
|
+
end
|
96
|
+
if (@output_type == :table_row) then
|
97
|
+
str.gsub!(/^\|\s*/, "<td>")
|
98
|
+
str.gsub!(/\s*\|$/, "</td>")
|
99
|
+
str.gsub!(/\s*\|\s*/, "</td><td>")
|
100
|
+
end
|
101
|
+
str
|
102
|
+
end
|
103
|
+
|
104
|
+
end # class HtmlOutputBuffer
|
105
|
+
end # module Orgmode
|
data/lib/org-ruby/line.rb
CHANGED
@@ -1,173 +1,173 @@
|
|
1
|
-
module Orgmode
|
2
|
-
|
3
|
-
# Represents a single line of an orgmode file.
|
4
|
-
class Line
|
5
|
-
|
6
|
-
# This is the line itself.
|
7
|
-
attr_reader :line
|
8
|
-
|
9
|
-
# The indent level of this line. this is important to properly translate
|
10
|
-
# nested lists from orgmode to textile.
|
11
|
-
# TODO 2009-12-20 bdewey: Handle tabs
|
12
|
-
attr_reader :indent
|
13
|
-
|
14
|
-
def initialize(line)
|
15
|
-
@line = line
|
16
|
-
@indent = 0
|
17
|
-
@line =~ /\s*/
|
18
|
-
@indent = $&.length unless blank?
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_s
|
22
|
-
return @line
|
23
|
-
end
|
24
|
-
|
25
|
-
# Tests if a line is a comment.
|
26
|
-
def comment?
|
27
|
-
@line =~ /^\s*#/
|
28
|
-
end
|
29
|
-
|
30
|
-
# Tests if a line contains metadata instead of actual content.
|
31
|
-
def metadata?
|
32
|
-
@line =~ /^\s*(CLOCK|DEADLINE|START|CLOSED|SCHEDULED):/
|
33
|
-
end
|
34
|
-
|
35
|
-
def nonprinting?
|
36
|
-
comment? || metadata?
|
37
|
-
end
|
38
|
-
|
39
|
-
def blank?
|
40
|
-
@line =~ /^\s*$/
|
41
|
-
end
|
42
|
-
|
43
|
-
def plain_list?
|
44
|
-
ordered_list? or unordered_list?
|
45
|
-
end
|
46
|
-
|
47
|
-
UnorderedListRegexp = /^\s*(-|\+)\s*/
|
48
|
-
|
49
|
-
def unordered_list?
|
50
|
-
@line =~ UnorderedListRegexp
|
51
|
-
end
|
52
|
-
|
53
|
-
def strip_unordered_list_tag
|
54
|
-
@line.sub(UnorderedListRegexp, "")
|
55
|
-
end
|
56
|
-
|
57
|
-
OrderedListRegexp = /^\s*\d+(\.|\))\s*/
|
58
|
-
|
59
|
-
def ordered_list?
|
60
|
-
@line =~ OrderedListRegexp
|
61
|
-
end
|
62
|
-
|
63
|
-
def strip_ordered_list_tag
|
64
|
-
@line.sub(OrderedListRegexp, "")
|
65
|
-
end
|
66
|
-
|
67
|
-
def plain_text?
|
68
|
-
not metadata? and not blank? and not plain_list?
|
69
|
-
end
|
70
|
-
|
71
|
-
def table_row?
|
72
|
-
# for an org-mode table, the first non-whitespace character is a
|
73
|
-
# | (pipe).
|
74
|
-
@line =~ /^\s*\|/
|
75
|
-
end
|
76
|
-
|
77
|
-
def table_separator?
|
78
|
-
# an org-mode table separator has the first non-whitespace
|
79
|
-
# character as a | (pipe), then consists of nothing else other
|
80
|
-
# than pipes, hyphens, and pluses.
|
81
|
-
|
82
|
-
@line =~ /^\s*\|[-\|\+]*\s*$/
|
83
|
-
end
|
84
|
-
|
85
|
-
def table?
|
86
|
-
table_row? or table_separator?
|
87
|
-
end
|
88
|
-
|
89
|
-
BlockRegexp = /^\s*#\+(BEGIN|END)_(\w*)/
|
90
|
-
|
91
|
-
def begin_block?
|
92
|
-
@line =~ BlockRegexp && $1 == "BEGIN"
|
93
|
-
end
|
94
|
-
|
95
|
-
def end_block?
|
96
|
-
@line =~ BlockRegexp && $1 == "END"
|
97
|
-
end
|
98
|
-
|
99
|
-
def block_type
|
100
|
-
$2 if @line =~ BlockRegexp
|
101
|
-
end
|
102
|
-
|
103
|
-
# Determines the paragraph type of the current line.
|
104
|
-
def paragraph_type
|
105
|
-
return :blank if blank?
|
106
|
-
return :ordered_list if ordered_list?
|
107
|
-
return :unordered_list if unordered_list?
|
108
|
-
return :metadata if metadata?
|
109
|
-
return :comment if comment?
|
110
|
-
return :table_separator if table_separator?
|
111
|
-
return :table_row if table_row?
|
112
|
-
return :paragraph
|
113
|
-
end
|
114
|
-
|
115
|
-
def self.to_textile(lines)
|
116
|
-
output = ""
|
117
|
-
output_buffer = TextileOutputBuffer.new(output)
|
118
|
-
translate(lines, output_buffer)
|
119
|
-
end
|
120
|
-
|
121
|
-
def self.to_html(lines)
|
122
|
-
output = ""
|
123
|
-
output_buffer = HtmlOutputBuffer.new(output)
|
124
|
-
translate(lines, output_buffer)
|
125
|
-
end
|
126
|
-
|
127
|
-
# Converts an array of lines to textile format.
|
128
|
-
def self.translate(lines, output_buffer)
|
129
|
-
lines.each do |line|
|
130
|
-
|
131
|
-
# See if we're carrying paragraph payload, and output
|
132
|
-
# it if we're about to switch to some other output type.
|
133
|
-
output_buffer.prepare(line)
|
134
|
-
|
135
|
-
case line.paragraph_type
|
136
|
-
when :metadata, :table_separator, :blank
|
137
|
-
|
138
|
-
# IGNORE
|
139
|
-
|
140
|
-
when :comment
|
141
|
-
|
142
|
-
output_buffer.push_mode(:blockquote) if line.begin_block? and line.block_type == "QUOTE"
|
143
|
-
output_buffer.push_mode(:code) if line.begin_block? and line.block_type == "EXAMPLE"
|
144
|
-
output_buffer.pop_mode(:blockquote) if line.end_block? and line.block_type == "QUOTE"
|
145
|
-
output_buffer.pop_mode(:code) if line.end_block? and line.block_type == "EXAMPLE"
|
146
|
-
|
147
|
-
when :table_row
|
148
|
-
|
149
|
-
output_buffer << line.line.lstrip
|
150
|
-
|
151
|
-
when :ordered_list
|
152
|
-
|
153
|
-
output_buffer << line.strip_ordered_list_tag << " "
|
154
|
-
|
155
|
-
when :unordered_list
|
156
|
-
|
157
|
-
output_buffer << line.strip_unordered_list_tag << " "
|
158
|
-
|
159
|
-
when :paragraph
|
160
|
-
|
161
|
-
if output_buffer.preserve_whitespace? then
|
162
|
-
output_buffer << line.line
|
163
|
-
else
|
164
|
-
output_buffer << line.line.strip << " "
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
output_buffer.flush!
|
169
|
-
output_buffer.pop_mode until output_buffer.current_mode == :normal
|
170
|
-
output_buffer.output
|
171
|
-
end
|
172
|
-
end # class Line
|
173
|
-
end # module Orgmode
|
1
|
+
module Orgmode
|
2
|
+
|
3
|
+
# Represents a single line of an orgmode file.
|
4
|
+
class Line
|
5
|
+
|
6
|
+
# This is the line itself.
|
7
|
+
attr_reader :line
|
8
|
+
|
9
|
+
# The indent level of this line. this is important to properly translate
|
10
|
+
# nested lists from orgmode to textile.
|
11
|
+
# TODO 2009-12-20 bdewey: Handle tabs
|
12
|
+
attr_reader :indent
|
13
|
+
|
14
|
+
def initialize(line)
|
15
|
+
@line = line
|
16
|
+
@indent = 0
|
17
|
+
@line =~ /\s*/
|
18
|
+
@indent = $&.length unless blank?
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
return @line
|
23
|
+
end
|
24
|
+
|
25
|
+
# Tests if a line is a comment.
|
26
|
+
def comment?
|
27
|
+
@line =~ /^\s*#/
|
28
|
+
end
|
29
|
+
|
30
|
+
# Tests if a line contains metadata instead of actual content.
|
31
|
+
def metadata?
|
32
|
+
@line =~ /^\s*(CLOCK|DEADLINE|START|CLOSED|SCHEDULED):/
|
33
|
+
end
|
34
|
+
|
35
|
+
def nonprinting?
|
36
|
+
comment? || metadata?
|
37
|
+
end
|
38
|
+
|
39
|
+
def blank?
|
40
|
+
@line =~ /^\s*$/
|
41
|
+
end
|
42
|
+
|
43
|
+
def plain_list?
|
44
|
+
ordered_list? or unordered_list?
|
45
|
+
end
|
46
|
+
|
47
|
+
UnorderedListRegexp = /^\s*(-|\+)\s*/
|
48
|
+
|
49
|
+
def unordered_list?
|
50
|
+
@line =~ UnorderedListRegexp
|
51
|
+
end
|
52
|
+
|
53
|
+
def strip_unordered_list_tag
|
54
|
+
@line.sub(UnorderedListRegexp, "")
|
55
|
+
end
|
56
|
+
|
57
|
+
OrderedListRegexp = /^\s*\d+(\.|\))\s*/
|
58
|
+
|
59
|
+
def ordered_list?
|
60
|
+
@line =~ OrderedListRegexp
|
61
|
+
end
|
62
|
+
|
63
|
+
def strip_ordered_list_tag
|
64
|
+
@line.sub(OrderedListRegexp, "")
|
65
|
+
end
|
66
|
+
|
67
|
+
def plain_text?
|
68
|
+
not metadata? and not blank? and not plain_list?
|
69
|
+
end
|
70
|
+
|
71
|
+
def table_row?
|
72
|
+
# for an org-mode table, the first non-whitespace character is a
|
73
|
+
# | (pipe).
|
74
|
+
@line =~ /^\s*\|/
|
75
|
+
end
|
76
|
+
|
77
|
+
def table_separator?
|
78
|
+
# an org-mode table separator has the first non-whitespace
|
79
|
+
# character as a | (pipe), then consists of nothing else other
|
80
|
+
# than pipes, hyphens, and pluses.
|
81
|
+
|
82
|
+
@line =~ /^\s*\|[-\|\+]*\s*$/
|
83
|
+
end
|
84
|
+
|
85
|
+
def table?
|
86
|
+
table_row? or table_separator?
|
87
|
+
end
|
88
|
+
|
89
|
+
BlockRegexp = /^\s*#\+(BEGIN|END)_(\w*)/
|
90
|
+
|
91
|
+
def begin_block?
|
92
|
+
@line =~ BlockRegexp && $1 == "BEGIN"
|
93
|
+
end
|
94
|
+
|
95
|
+
def end_block?
|
96
|
+
@line =~ BlockRegexp && $1 == "END"
|
97
|
+
end
|
98
|
+
|
99
|
+
def block_type
|
100
|
+
$2 if @line =~ BlockRegexp
|
101
|
+
end
|
102
|
+
|
103
|
+
# Determines the paragraph type of the current line.
|
104
|
+
def paragraph_type
|
105
|
+
return :blank if blank?
|
106
|
+
return :ordered_list if ordered_list?
|
107
|
+
return :unordered_list if unordered_list?
|
108
|
+
return :metadata if metadata?
|
109
|
+
return :comment if comment?
|
110
|
+
return :table_separator if table_separator?
|
111
|
+
return :table_row if table_row?
|
112
|
+
return :paragraph
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.to_textile(lines)
|
116
|
+
output = ""
|
117
|
+
output_buffer = TextileOutputBuffer.new(output)
|
118
|
+
translate(lines, output_buffer)
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.to_html(lines, opts = { })
|
122
|
+
output = ""
|
123
|
+
output_buffer = HtmlOutputBuffer.new(output, opts)
|
124
|
+
translate(lines, output_buffer)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Converts an array of lines to textile format.
|
128
|
+
def self.translate(lines, output_buffer)
|
129
|
+
lines.each do |line|
|
130
|
+
|
131
|
+
# See if we're carrying paragraph payload, and output
|
132
|
+
# it if we're about to switch to some other output type.
|
133
|
+
output_buffer.prepare(line)
|
134
|
+
|
135
|
+
case line.paragraph_type
|
136
|
+
when :metadata, :table_separator, :blank
|
137
|
+
|
138
|
+
# IGNORE
|
139
|
+
|
140
|
+
when :comment
|
141
|
+
|
142
|
+
output_buffer.push_mode(:blockquote) if line.begin_block? and line.block_type == "QUOTE"
|
143
|
+
output_buffer.push_mode(:code) if line.begin_block? and line.block_type == "EXAMPLE"
|
144
|
+
output_buffer.pop_mode(:blockquote) if line.end_block? and line.block_type == "QUOTE"
|
145
|
+
output_buffer.pop_mode(:code) if line.end_block? and line.block_type == "EXAMPLE"
|
146
|
+
|
147
|
+
when :table_row
|
148
|
+
|
149
|
+
output_buffer << line.line.lstrip
|
150
|
+
|
151
|
+
when :ordered_list
|
152
|
+
|
153
|
+
output_buffer << line.strip_ordered_list_tag << " "
|
154
|
+
|
155
|
+
when :unordered_list
|
156
|
+
|
157
|
+
output_buffer << line.strip_unordered_list_tag << " "
|
158
|
+
|
159
|
+
when :paragraph
|
160
|
+
|
161
|
+
if output_buffer.preserve_whitespace? then
|
162
|
+
output_buffer << line.line
|
163
|
+
else
|
164
|
+
output_buffer << line.line.strip << " "
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
output_buffer.flush!
|
169
|
+
output_buffer.pop_mode until output_buffer.current_mode == :normal
|
170
|
+
output_buffer.output
|
171
|
+
end
|
172
|
+
end # class Line
|
173
|
+
end # module Orgmode
|