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/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 paragraph_type
206
- return :blank if blank?
207
- return :src if code_block_line? # Do not try to guess the type of this line if it is accumulating source code
208
- return :definition_list if definition_list? # order is important! A definition_list is also an unordered_list!
209
- return :ordered_list if ordered_list?
210
- return :unordered_list if unordered_list?
211
- return :property_drawer_begin_block if property_drawer_begin_block?
212
- return :property_drawer_end_block if property_drawer_end_block?
213
- return :property_drawer_item if property_drawer_item?
214
- return :metadata if metadata?
215
- return :begin_block if begin_block?
216
- return :end_block if end_block?
217
- return :comment if comment?
218
- return :table_separator if table_separator?
219
- return :table_row if table_row?
220
- return :table_header if table_header?
221
- return :inline_example if inline_example?
222
- return :horizontal_rule if horizontal_rule?
223
- return :paragraph
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
- @output = output
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
- @buffered_lines = []
38
- @buffer_mode = nil
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
- @headline_number_stack = []
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
- # Prepares the output buffer to receive content from a line.
79
- # As a side effect, this may flush the current accumulated text.
80
- def prepare(line)
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
- if line.begin_block? and line.code_block?
83
- flush!
84
- # We try to get the lang from #+BEGIN_SRC blocks
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
- @output_type = line.paragraph_type
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
- push_mode(:inline_example) if line.inline_example? and current_mode != :inline_example and not line.property_drawer?
96
- pop_mode(:inline_example) if current_mode == :inline_example and !line.inline_example?
97
- push_mode(:property_drawer) if line.property_drawer? and current_mode != :property_drawer
98
- pop_mode(:property_drawer) if current_mode == :property_drawer and line.property_drawer_end_block?
99
- push_mode(:table) if enter_table?
100
- pop_mode(:table) if exit_table?
101
- @buffered_lines.push(line)
102
- end
103
-
104
- # Flushes everything currently in the accumulation buffer into the
105
- # output buffer. Derived classes must override this to actually move
106
- # content into the output buffer with the appropriate markup. This
107
- # method just does common bookkeeping cleanup.
108
- def clear_accumulation_buffer!
109
- @buffer = ""
110
- @buffer_mode = nil
111
- @buffered_lines = []
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
- mode_is_code current_mode
127
+ [:example, :inline_example, :raw_text, :src].include? current_mode
160
128
  end
161
129
 
162
130
  ######################################################################
163
131
  private
164
132
 
165
- def mode_is_code(mode)
166
- case mode
167
- when :src, :inline_example, :example
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 maintain_list_indent_stack(line)
175
- if (line.plain_list?) then
176
- while (not @list_indent_stack.empty? \
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
- # Nothing
142
+ def mode_is_code?(mode)
143
+ [:example, :src].include? mode
144
+ end
189
145
 
190
- elsif ((not line.plain_list?) and
191
- (not @list_indent_stack.empty?) and
192
- (line.indent > @list_indent_stack.last))
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
- # Nothing -- output this paragraph inside
195
- # the list block (ul/ol)
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
- else
198
- @list_indent_stack = []
199
- while ((current_mode == :ordered_list) or
200
- (current_mode == :definition_list) or
201
- (current_mode == :unordered_list))
202
- pop_mode
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. (Extraneous line breaks in the orgmode buffer
213
- # are removed by accumulating lines in the output buffer without
214
- # line breaks.)
215
- def should_accumulate_output?(line)
216
-
217
- # Special case: We are accumulating source code block content for colorizing
218
- return true if line.paragraph_type == :src and @output_type == :src
219
-
220
- # Special case: Preserve line breaks in block code mode.
221
- return false if preserve_whitespace?
222
-
223
- # Special case: Multiple blank lines get accumulated.
224
- return true if line.paragraph_type == :blank and @output_type == :blank
225
-
226
- # Currently only "paragraphs" get accumulated with previous output.
227
- return false unless line.paragraph_type == :paragraph
228
- if ((@output_type == :ordered_list) or
229
- (@output_type == :definition_list) or
230
- (@output_type == :unordered_list)) then
231
-
232
- # If the previous output type was a list item, then we only put a paragraph in it
233
- # if its indent level is greater than the list indent level.
234
-
235
- return false unless line.indent > @list_indent_stack.last
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
- # Only accumulate paragraphs with lists & paragraphs.
239
- return false unless
240
- ((@output_type == :paragraph) or
241
- (@output_type == :ordered_list) or
242
- (@output_type == :definition_list) or
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