org-ruby 0.7.2 → 0.8.0
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.
- data/History.txt +10 -0
- data/README.rdoc +55 -51
- data/lib/org-ruby.rb +1 -1
- data/lib/org-ruby/headline.rb +0 -1
- data/lib/org-ruby/html_output_buffer.rb +201 -214
- data/lib/org-ruby/html_symbol_replace.rb +359 -340
- data/lib/org-ruby/line.rb +79 -24
- data/lib/org-ruby/output_buffer.rb +144 -146
- data/lib/org-ruby/parser.rb +37 -122
- data/lib/org-ruby/regexp_helper.rb +49 -49
- data/lib/org-ruby/textile_output_buffer.rb +91 -44
- data/lib/org-ruby/textile_symbol_replace.rb +360 -341
- metadata +3 -14
data/lib/org-ruby/line.rb
CHANGED
@@ -14,6 +14,12 @@ module Orgmode
|
|
14
14
|
# Backpointer to the parser that owns this line.
|
15
15
|
attr_reader :parser
|
16
16
|
|
17
|
+
# Paragraph type determined for the line.
|
18
|
+
attr_reader :paragraph_type
|
19
|
+
|
20
|
+
# Major modes associate paragraphs with a table, list and so on.
|
21
|
+
attr_reader :major_mode
|
22
|
+
|
17
23
|
# A line can have its type assigned instead of inferred from its
|
18
24
|
# content. For example, something that parses as a "table" on its
|
19
25
|
# own ("| one | two|\n") may just be a paragraph if it's inside
|
@@ -26,6 +32,8 @@ module Orgmode
|
|
26
32
|
@line = line
|
27
33
|
@indent = 0
|
28
34
|
@line =~ /\s*/
|
35
|
+
determine_paragraph_type
|
36
|
+
determine_major_mode
|
29
37
|
@assigned_paragraph_type = nil
|
30
38
|
@indent = $&.length unless blank?
|
31
39
|
end
|
@@ -88,7 +96,7 @@ module Orgmode
|
|
88
96
|
@line.sub(UnorderedListRegexp, "")
|
89
97
|
end
|
90
98
|
|
91
|
-
DefinitionListRegexp = /^\s*(-|\+|\s+[*])\s
|
99
|
+
DefinitionListRegexp = /^\s*(-|\+|\s+[*])\s+(.*\s+|)::($|\s+)/
|
92
100
|
|
93
101
|
def definition_list?
|
94
102
|
check_assignment_or_regexp(:definition_list, DefinitionListRegexp)
|
@@ -116,6 +124,7 @@ module Orgmode
|
|
116
124
|
return strip_ordered_list_tag if ordered_list?
|
117
125
|
return strip_unordered_list_tag if unordered_list?
|
118
126
|
return @line.sub(InlineExampleRegexp, "") if inline_example?
|
127
|
+
return strip_raw_text_tag if raw_text?
|
119
128
|
return line
|
120
129
|
end
|
121
130
|
|
@@ -168,10 +177,6 @@ module Orgmode
|
|
168
177
|
block_type =~ /^(EXAMPLE|SRC)$/i
|
169
178
|
end
|
170
179
|
|
171
|
-
def code_block_line?
|
172
|
-
@assigned_paragraph_type == :src
|
173
|
-
end
|
174
|
-
|
175
180
|
InlineExampleRegexp = /^\s*:\s/
|
176
181
|
|
177
182
|
# Test if the line matches the "inline example" case:
|
@@ -180,6 +185,21 @@ module Orgmode
|
|
180
185
|
check_assignment_or_regexp(:inline_example, InlineExampleRegexp)
|
181
186
|
end
|
182
187
|
|
188
|
+
RawTextRegexp = /^(\s*)#\+(\w+):\s*/
|
189
|
+
|
190
|
+
# Checks if this line is raw text.
|
191
|
+
def raw_text?
|
192
|
+
check_assignment_or_regexp(:raw_text, RawTextRegexp)
|
193
|
+
end
|
194
|
+
|
195
|
+
def raw_text_tag
|
196
|
+
$2.upcase if @line =~ RawTextRegexp
|
197
|
+
end
|
198
|
+
|
199
|
+
def strip_raw_text_tag
|
200
|
+
@line.sub(RawTextRegexp) { |match| $1 }
|
201
|
+
end
|
202
|
+
|
183
203
|
InBufferSettingRegexp = /^#\+(\w+):\s*(.*)$/
|
184
204
|
|
185
205
|
# call-seq:
|
@@ -202,25 +222,60 @@ module Orgmode
|
|
202
222
|
end
|
203
223
|
|
204
224
|
# Determines the paragraph type of the current line.
|
205
|
-
def
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
225
|
+
def determine_paragraph_type
|
226
|
+
@paragraph_type = \
|
227
|
+
case
|
228
|
+
when blank?
|
229
|
+
:blank
|
230
|
+
when definition_list? # order is important! A definition_list is also an unordered_list!
|
231
|
+
:definition_term
|
232
|
+
when (ordered_list? or unordered_list?)
|
233
|
+
:list_item
|
234
|
+
when property_drawer_begin_block?
|
235
|
+
:property_drawer_begin_block
|
236
|
+
when property_drawer_end_block?
|
237
|
+
:property_drawer_end_block
|
238
|
+
when property_drawer_item?
|
239
|
+
:property_drawer_item
|
240
|
+
when metadata?
|
241
|
+
:metadata
|
242
|
+
when block_type
|
243
|
+
case block_type.downcase.to_sym
|
244
|
+
when :center, :comment, :example, :html, :quote, :src
|
245
|
+
block_type.downcase.to_sym
|
246
|
+
else
|
247
|
+
:comment
|
248
|
+
end
|
249
|
+
when raw_text? # order is important! Raw text can be also a comment
|
250
|
+
:raw_text
|
251
|
+
when comment?
|
252
|
+
:comment
|
253
|
+
when table_separator?
|
254
|
+
:table_separator
|
255
|
+
when table_row?
|
256
|
+
:table_row
|
257
|
+
when table_header?
|
258
|
+
:table_header
|
259
|
+
when inline_example?
|
260
|
+
:inline_example
|
261
|
+
when horizontal_rule?
|
262
|
+
:horizontal_rule
|
263
|
+
else :paragraph
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def determine_major_mode
|
268
|
+
@major_mode = \
|
269
|
+
case
|
270
|
+
when definition_list? # order is important! A definition_list is also an unordered_list!
|
271
|
+
:definition_list
|
272
|
+
when ordered_list?
|
273
|
+
:ordered_list
|
274
|
+
when unordered_list?
|
275
|
+
:unordered_list
|
276
|
+
when table?
|
277
|
+
:table
|
278
|
+
end
|
224
279
|
end
|
225
280
|
|
226
281
|
######################################################################
|
@@ -8,40 +8,29 @@ module Orgmode
|
|
8
8
|
# add a newline character prior emitting the output.
|
9
9
|
class OutputBuffer
|
10
10
|
|
11
|
-
# This is the accumulation buffer. It's a holding pen so
|
12
|
-
# consecutive lines of the right type can get stuck together
|
13
|
-
# without intervening newlines.
|
14
|
-
attr_reader :buffer
|
15
|
-
|
16
|
-
# These are the Line objects that are currently in the accumulation
|
17
|
-
# buffer.
|
18
|
-
attr_reader :buffered_lines
|
19
|
-
|
20
|
-
# This is the output mode of the accumulation buffer.
|
21
|
-
attr_reader :buffer_mode
|
22
|
-
|
23
11
|
# This is the overall output buffer
|
24
12
|
attr_reader :output
|
25
13
|
|
26
14
|
# This is the current type of output being accumulated.
|
27
15
|
attr_accessor :output_type
|
28
16
|
|
29
|
-
# This stack is used to do proper outline numbering of headlines.
|
30
|
-
attr_accessor :headline_number_stack
|
31
|
-
|
32
17
|
# Creates a new OutputBuffer object that is bound to an output object.
|
33
18
|
# The output will get flushed to =output=.
|
34
19
|
def initialize(output)
|
35
|
-
|
20
|
+
# This is the accumulation buffer. It's a holding pen so
|
21
|
+
# consecutive lines of the right type can get stuck together
|
22
|
+
# without intervening newlines.
|
36
23
|
@buffer = ""
|
37
|
-
|
38
|
-
|
24
|
+
|
25
|
+
# This stack is used to do proper outline numbering of
|
26
|
+
# headlines.
|
27
|
+
@headline_number_stack = []
|
28
|
+
|
29
|
+
@output = output
|
39
30
|
@output_type = :start
|
40
31
|
@list_indent_stack = []
|
41
|
-
@paragraph_modifier = nil
|
42
|
-
@cancel_modifier = false
|
43
32
|
@mode_stack = []
|
44
|
-
@
|
33
|
+
@code_block_indent = nil
|
45
34
|
|
46
35
|
@logger = Logger.new(STDERR)
|
47
36
|
if ENV['DEBUG'] or $DEBUG
|
@@ -51,21 +40,13 @@ module Orgmode
|
|
51
40
|
end
|
52
41
|
|
53
42
|
@re_help = RegexpHelper.new
|
54
|
-
push_mode(:normal)
|
55
43
|
end
|
56
44
|
|
57
|
-
Modes = [:normal, :ordered_list, :unordered_list, :definition_list, :blockquote, :src, :example, :table, :inline_example, :center, :property_drawer]
|
58
|
-
|
59
45
|
def current_mode
|
60
46
|
@mode_stack.last
|
61
47
|
end
|
62
48
|
|
63
|
-
def current_mode_list?
|
64
|
-
(current_mode == :ordered_list) or (current_mode == :unordered_list)
|
65
|
-
end
|
66
|
-
|
67
49
|
def push_mode(mode)
|
68
|
-
raise "Not a recognized mode: #{mode}" unless Modes.include?(mode)
|
69
50
|
@mode_stack.push(mode)
|
70
51
|
end
|
71
52
|
|
@@ -75,40 +56,49 @@ module Orgmode
|
|
75
56
|
m
|
76
57
|
end
|
77
58
|
|
78
|
-
|
79
|
-
|
80
|
-
|
59
|
+
def insert(line)
|
60
|
+
# Prepares the output buffer to receive content from a line.
|
61
|
+
# As a side effect, this may flush the current accumulated text.
|
81
62
|
@logger.debug "Looking at #{line.paragraph_type}(#{current_mode}) : #{line.to_s}"
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
@block_lang = line.block_lang
|
86
|
-
@output_type = line.paragraph_type
|
87
|
-
elsif current_mode == :example and line.end_block?
|
63
|
+
# We try to get the lang from #+BEGIN_SRC blocks
|
64
|
+
@block_lang = line.block_lang if line.begin_block?
|
65
|
+
unless should_accumulate_output?(line)
|
88
66
|
flush!
|
89
|
-
|
90
|
-
elsif not should_accumulate_output?(line)
|
91
|
-
flush!
|
92
|
-
maintain_list_indent_stack(line)
|
93
|
-
@output_type = line.paragraph_type
|
67
|
+
maintain_mode_stack(line)
|
94
68
|
end
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
69
|
+
|
70
|
+
# Adds the current line to the output buffer
|
71
|
+
case
|
72
|
+
when line.raw_text?
|
73
|
+
@buffer << "\n" << line.output_text if line.raw_text_tag == @buffer_tag
|
74
|
+
when preserve_whitespace?
|
75
|
+
@buffer << "\n" << line.output_text unless line.block_type
|
76
|
+
when line.assigned_paragraph_type == :code
|
77
|
+
# If the line is contained within a code block but we should
|
78
|
+
# not preserve whitespaces, then we do nothing.
|
79
|
+
when (line.kind_of? Headline)
|
80
|
+
add_line_attributes line
|
81
|
+
@buffer << "\n" << line.output_text.strip
|
82
|
+
when ([:definition_term, :list_item, :table_row, :table_header,
|
83
|
+
:horizontal_rule].include? line.paragraph_type)
|
84
|
+
@buffer << "\n" << line.output_text.strip
|
85
|
+
when line.paragraph_type == :paragraph
|
86
|
+
@buffer << "\n"
|
87
|
+
buffer_indentation
|
88
|
+
@buffer << line.output_text.strip
|
89
|
+
end
|
90
|
+
|
91
|
+
if mode_is_code? current_mode and not line.block_type
|
92
|
+
# Determines the amount of whitespaces to be stripped at the
|
93
|
+
# beginning of each line in code block.
|
94
|
+
if @code_block_indent
|
95
|
+
@code_block_indent = [@code_block_indent, line.indent].min
|
96
|
+
else
|
97
|
+
@code_block_indent = line.indent
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
@output_type = line.assigned_paragraph_type || line.paragraph_type
|
112
102
|
end
|
113
103
|
|
114
104
|
# Gets the next headline number for a given level. The intent is
|
@@ -127,28 +117,6 @@ module Orgmode
|
|
127
117
|
@headline_number_stack.join(".")
|
128
118
|
end
|
129
119
|
|
130
|
-
# Tests if we are entering a table mode.
|
131
|
-
def enter_table?
|
132
|
-
((@output_type == :table_row) || (@output_type == :table_header) || (@output_type == :table_separator)) &&
|
133
|
-
(current_mode != :table)
|
134
|
-
end
|
135
|
-
|
136
|
-
# Tests if we are existing a table mode.
|
137
|
-
def exit_table?
|
138
|
-
((@output_type != :table_row) && (@output_type != :table_header) && (@output_type != :table_separator)) &&
|
139
|
-
(current_mode == :table)
|
140
|
-
end
|
141
|
-
|
142
|
-
# Accumulate the string @str@.
|
143
|
-
def << (str)
|
144
|
-
if @buffer_mode && @buffer_mode != current_mode then
|
145
|
-
raise "Accumulation buffer is mixing modes: @buffer_mode == #{@buffer_mode}, current_mode == #{current_mode}"
|
146
|
-
else
|
147
|
-
@buffer_mode = current_mode
|
148
|
-
end
|
149
|
-
@buffer << str
|
150
|
-
end
|
151
|
-
|
152
120
|
# Gets the current list indent level.
|
153
121
|
def list_indent_level
|
154
122
|
@list_indent_stack.length
|
@@ -156,50 +124,76 @@ module Orgmode
|
|
156
124
|
|
157
125
|
# Test if we're in an output mode in which whitespace is significant.
|
158
126
|
def preserve_whitespace?
|
159
|
-
|
127
|
+
[:example, :inline_example, :raw_text, :src].include? current_mode
|
160
128
|
end
|
161
129
|
|
162
130
|
######################################################################
|
163
131
|
private
|
164
132
|
|
165
|
-
def
|
166
|
-
|
167
|
-
|
168
|
-
true
|
169
|
-
else
|
170
|
-
false
|
171
|
-
end
|
133
|
+
def mode_is_heading?(mode)
|
134
|
+
[:heading1, :heading2, :heading3,
|
135
|
+
:heading4, :heading5, :heading6].include? mode
|
172
136
|
end
|
173
137
|
|
174
|
-
def
|
175
|
-
|
176
|
-
|
177
|
-
and (@list_indent_stack.last > line.indent))
|
178
|
-
@list_indent_stack.pop
|
179
|
-
pop_mode
|
180
|
-
end
|
181
|
-
if (@list_indent_stack.empty? \
|
182
|
-
or @list_indent_stack.last < line.indent)
|
183
|
-
@list_indent_stack.push(line.indent)
|
184
|
-
push_mode line.paragraph_type
|
185
|
-
end
|
186
|
-
elsif line.blank? then
|
138
|
+
def mode_is_block?(mode)
|
139
|
+
[:quote, :center, :example, :src].include? mode
|
140
|
+
end
|
187
141
|
|
188
|
-
|
142
|
+
def mode_is_code?(mode)
|
143
|
+
[:example, :src].include? mode
|
144
|
+
end
|
189
145
|
|
190
|
-
|
191
|
-
|
192
|
-
|
146
|
+
def boundary_of_block?(line)
|
147
|
+
# Boundary of inline example
|
148
|
+
return true if ((line.paragraph_type == :inline_example) ^
|
149
|
+
(@output_type == :inline_example))
|
150
|
+
# Boundary of begin...end block
|
151
|
+
return true if mode_is_block? @output_type
|
152
|
+
end
|
193
153
|
|
194
|
-
|
195
|
-
|
154
|
+
def maintain_mode_stack(line)
|
155
|
+
# Always close the following lines
|
156
|
+
pop_mode if (mode_is_heading? current_mode or
|
157
|
+
current_mode == :paragraph or
|
158
|
+
current_mode == :horizontal_rule or
|
159
|
+
current_mode == :inline_example or
|
160
|
+
current_mode == :raw_text)
|
196
161
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
162
|
+
# End-block line closes every mode within block
|
163
|
+
if line.end_block? and @mode_stack.include? line.paragraph_type
|
164
|
+
pop_mode until current_mode == line.paragraph_type
|
165
|
+
end
|
166
|
+
|
167
|
+
if ((not line.paragraph_type == :blank) or
|
168
|
+
@output_type == :blank)
|
169
|
+
# Close previous tags on demand. Two blank lines close all tags.
|
170
|
+
while ((not @list_indent_stack.empty?) and
|
171
|
+
@list_indent_stack.last >= line.indent and
|
172
|
+
# Don't allow an arbitrary line to close block
|
173
|
+
(not mode_is_block? current_mode))
|
174
|
+
# Item can't close its major mode
|
175
|
+
if (@list_indent_stack.last == line.indent and
|
176
|
+
line.major_mode == current_mode)
|
177
|
+
break
|
178
|
+
else
|
179
|
+
pop_mode
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Special case: Only end-block line closes block
|
185
|
+
pop_mode if line.end_block? and line.paragraph_type == current_mode
|
186
|
+
|
187
|
+
unless line.paragraph_type == :blank
|
188
|
+
if (@list_indent_stack.empty? or
|
189
|
+
@list_indent_stack.last <= line.indent or
|
190
|
+
mode_is_block? current_mode)
|
191
|
+
# Opens the major mode of line if it exists
|
192
|
+
if @list_indent_stack.last != line.indent or mode_is_block? current_mode
|
193
|
+
push_mode(line.major_mode, line.indent) if line.major_mode
|
194
|
+
end
|
195
|
+
# Opens tag that precedes text immediately
|
196
|
+
push_mode(line.paragraph_type, line.indent) unless line.end_block?
|
203
197
|
end
|
204
198
|
end
|
205
199
|
end
|
@@ -209,39 +203,43 @@ module Orgmode
|
|
209
203
|
end
|
210
204
|
|
211
205
|
# Tests if the current line should be accumulated in the current
|
212
|
-
# output buffer.
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
# Special case:
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
206
|
+
# output buffer.
|
207
|
+
def should_accumulate_output? line
|
208
|
+
# Special case: Assign mode if not yet done.
|
209
|
+
return false unless current_mode
|
210
|
+
|
211
|
+
# Special case: Handles accumulating block content and example lines
|
212
|
+
if mode_is_code? current_mode
|
213
|
+
return true unless (line.end_block? and
|
214
|
+
line.paragraph_type == current_mode)
|
215
|
+
end
|
216
|
+
return false if boundary_of_block? line
|
217
|
+
return true if current_mode == :inline_example
|
218
|
+
|
219
|
+
# Special case: Don't accumulate the following lines.
|
220
|
+
return false if (mode_is_heading? @output_type or
|
221
|
+
@output_type == :comment or
|
222
|
+
@output_type == :horizontal_rule or
|
223
|
+
@output_type == :raw_text)
|
224
|
+
|
225
|
+
# Special case: Blank line at least splits paragraphs
|
226
|
+
return false if @output_type == :blank
|
227
|
+
|
228
|
+
if line.paragraph_type == :paragraph
|
229
|
+
# Paragraph gets accumulated only if its indent level is
|
230
|
+
# greater than the indent level of the previous mode.
|
231
|
+
if @mode_stack[-2] and not mode_is_block? @mode_stack[-2]
|
232
|
+
return false if line.indent <= @list_indent_stack[-2]
|
233
|
+
end
|
234
|
+
# Special case: Multiple "paragraphs" get accumulated.
|
235
|
+
return true
|
236
236
|
end
|
237
237
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
(@output_type == :unordered_list))
|
244
|
-
true
|
238
|
+
false
|
239
|
+
end
|
240
|
+
|
241
|
+
def buffer_indentation
|
242
|
+
return false
|
245
243
|
end
|
246
244
|
end # class OutputBuffer
|
247
245
|
end # module Orgmode
|