wallyqs-org-ruby 0.6.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/History.txt +41 -11
  2. data/README.rdoc +55 -50
  3. data/bin/org-ruby +11 -5
  4. data/lib/org-ruby.rb +20 -27
  5. data/lib/org-ruby/headline.rb +0 -10
  6. data/lib/org-ruby/html_output_buffer.rb +224 -143
  7. data/lib/org-ruby/html_symbol_replace.rb +359 -340
  8. data/lib/org-ruby/line.rb +91 -30
  9. data/lib/org-ruby/output_buffer.rb +147 -139
  10. data/lib/org-ruby/parser.rb +45 -111
  11. data/lib/org-ruby/regexp_helper.rb +52 -57
  12. data/lib/org-ruby/textile_output_buffer.rb +90 -37
  13. data/lib/org-ruby/textile_symbol_replace.rb +360 -341
  14. metadata +39 -200
  15. data/.bnsignore +0 -18
  16. data/.gitignore +0 -2
  17. data/Gemfile +0 -7
  18. data/Gemfile.lock +0 -36
  19. data/Rakefile +0 -33
  20. data/TAGS +0 -167
  21. data/announcement.txt +0 -24
  22. data/org-ruby.gemspec +0 -40
  23. data/spec/data/freeform-example.org +0 -113
  24. data/spec/data/freeform.org +0 -111
  25. data/spec/data/hyp-planning.org +0 -335
  26. data/spec/data/remember.org +0 -53
  27. data/spec/headline_spec.rb +0 -65
  28. data/spec/html_examples/advanced-code.html +0 -81
  29. data/spec/html_examples/advanced-code.org +0 -106
  30. data/spec/html_examples/advanced-lists.html +0 -31
  31. data/spec/html_examples/advanced-lists.org +0 -31
  32. data/spec/html_examples/block_code.html +0 -28
  33. data/spec/html_examples/block_code.org +0 -35
  34. data/spec/html_examples/blockcomment.html +0 -3
  35. data/spec/html_examples/blockcomment.org +0 -15
  36. data/spec/html_examples/blockquote.html +0 -7
  37. data/spec/html_examples/blockquote.org +0 -13
  38. data/spec/html_examples/center.html +0 -6
  39. data/spec/html_examples/center.org +0 -7
  40. data/spec/html_examples/code-comment.html +0 -18
  41. data/spec/html_examples/code-comment.org +0 -22
  42. data/spec/html_examples/code-syntax.html +0 -98
  43. data/spec/html_examples/code-syntax.org +0 -99
  44. data/spec/html_examples/comment-trees.html +0 -4
  45. data/spec/html_examples/comment-trees.org +0 -13
  46. data/spec/html_examples/custom-seq-todo.html +0 -15
  47. data/spec/html_examples/custom-seq-todo.org +0 -24
  48. data/spec/html_examples/custom-todo.html +0 -15
  49. data/spec/html_examples/custom-todo.org +0 -24
  50. data/spec/html_examples/custom-typ-todo.html +0 -15
  51. data/spec/html_examples/custom-typ-todo.org +0 -24
  52. data/spec/html_examples/deflist.html +0 -6
  53. data/spec/html_examples/deflist.org +0 -6
  54. data/spec/html_examples/entities.html +0 -4
  55. data/spec/html_examples/entities.org +0 -11
  56. data/spec/html_examples/escape-pre.html +0 -6
  57. data/spec/html_examples/escape-pre.org +0 -6
  58. data/spec/html_examples/export-exclude-only.html +0 -13
  59. data/spec/html_examples/export-exclude-only.org +0 -81
  60. data/spec/html_examples/export-keywords.html +0 -4
  61. data/spec/html_examples/export-keywords.org +0 -18
  62. data/spec/html_examples/export-tags.html +0 -8
  63. data/spec/html_examples/export-tags.org +0 -82
  64. data/spec/html_examples/export-title.html +0 -2
  65. data/spec/html_examples/export-title.org +0 -4
  66. data/spec/html_examples/footnotes.html +0 -10
  67. data/spec/html_examples/footnotes.org +0 -7
  68. data/spec/html_examples/html-literal.html +0 -2
  69. data/spec/html_examples/html-literal.org +0 -6
  70. data/spec/html_examples/inline-formatting.html +0 -20
  71. data/spec/html_examples/inline-formatting.org +0 -33
  72. data/spec/html_examples/inline-images.html +0 -10
  73. data/spec/html_examples/inline-images.org +0 -15
  74. data/spec/html_examples/link-features.html +0 -8
  75. data/spec/html_examples/link-features.org +0 -19
  76. data/spec/html_examples/lists.html +0 -23
  77. data/spec/html_examples/lists.org +0 -47
  78. data/spec/html_examples/metadata-comment.html +0 -27
  79. data/spec/html_examples/metadata-comment.org +0 -30
  80. data/spec/html_examples/only-list.html +0 -5
  81. data/spec/html_examples/only-list.org +0 -3
  82. data/spec/html_examples/only-table.html +0 -6
  83. data/spec/html_examples/only-table.org +0 -5
  84. data/spec/html_examples/skip-header.html +0 -3
  85. data/spec/html_examples/skip-header.org +0 -28
  86. data/spec/html_examples/skip-table.html +0 -4
  87. data/spec/html_examples/skip-table.org +0 -19
  88. data/spec/html_examples/subsupscript-nil.html +0 -3
  89. data/spec/html_examples/subsupscript-nil.org +0 -6
  90. data/spec/html_examples/subsupscript.html +0 -3
  91. data/spec/html_examples/subsupscript.org +0 -5
  92. data/spec/html_examples/tables.html +0 -35
  93. data/spec/html_examples/tables.org +0 -50
  94. data/spec/html_examples/text.html +0 -2
  95. data/spec/html_examples/text.org +0 -16
  96. data/spec/line_spec.rb +0 -155
  97. data/spec/output_buffer_spec.rb +0 -19
  98. data/spec/parser_spec.rb +0 -152
  99. data/spec/regexp_helper_spec.rb +0 -57
  100. data/spec/spec_helper.rb +0 -20
  101. data/spec/textile_examples/block_code.org +0 -35
  102. data/spec/textile_examples/block_code.textile +0 -29
  103. data/spec/textile_examples/blockquote.org +0 -13
  104. data/spec/textile_examples/blockquote.textile +0 -11
  105. data/spec/textile_examples/center.org +0 -7
  106. data/spec/textile_examples/center.textile +0 -6
  107. data/spec/textile_examples/footnotes.org +0 -7
  108. data/spec/textile_examples/footnotes.textile +0 -8
  109. data/spec/textile_examples/keywords.org +0 -13
  110. data/spec/textile_examples/keywords.textile +0 -11
  111. data/spec/textile_examples/links.org +0 -11
  112. data/spec/textile_examples/links.textile +0 -10
  113. data/spec/textile_examples/lists.org +0 -36
  114. data/spec/textile_examples/lists.textile +0 -20
  115. data/spec/textile_examples/single-space-plain-list.org +0 -13
  116. data/spec/textile_examples/single-space-plain-list.textile +0 -10
  117. data/spec/textile_examples/tables.org +0 -50
  118. data/spec/textile_examples/tables.textile +0 -40
  119. data/spec/textile_output_buffer_spec.rb +0 -21
  120. data/tasks/test_case.rake +0 -49
  121. data/test/test_orgmode_parser.rb +0 -0
  122. data/util/gen-special-replace.el +0 -37
@@ -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
@@ -55,7 +63,7 @@ module Orgmode
55
63
  check_assignment_or_regexp(:property_drawer, PropertyDrawerRegexp)
56
64
  end
57
65
 
58
- PropertyDrawerItemRegexp = /^\s*:(\w+):\s*(.*)$/i
66
+ PropertyDrawerItemRegexp = /^\s*:([0-9A-Za-z_\-]+):\s*(.*)$/i
59
67
 
60
68
  def property_drawer_item?
61
69
  @line =~ PropertyDrawerItemRegexp
@@ -78,7 +86,7 @@ module Orgmode
78
86
  ordered_list? or unordered_list? or definition_list?
79
87
  end
80
88
 
81
- UnorderedListRegexp = /^\s*(-|\+)\s+/
89
+ UnorderedListRegexp = /^\s*(-|\+|\s+[*])\s+/
82
90
 
83
91
  def unordered_list?
84
92
  check_assignment_or_regexp(:unordered_list, UnorderedListRegexp)
@@ -88,7 +96,7 @@ module Orgmode
88
96
  @line.sub(UnorderedListRegexp, "")
89
97
  end
90
98
 
91
- DefinitionListRegexp = /^\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)
@@ -104,12 +112,19 @@ module Orgmode
104
112
  @line.sub(OrderedListRegexp, "")
105
113
  end
106
114
 
115
+ HorizontalRuleRegexp = /^\s*-{5,}\s*$/
116
+
117
+ def horizontal_rule?
118
+ check_assignment_or_regexp(:horizontal_rule, HorizontalRuleRegexp)
119
+ end
120
+
107
121
  # Extracts meaningful text and excludes org-mode markup,
108
122
  # like identifiers for lists or headings.
109
123
  def output_text
110
124
  return strip_ordered_list_tag if ordered_list?
111
125
  return strip_unordered_list_tag if unordered_list?
112
126
  return @line.sub(InlineExampleRegexp, "") if inline_example?
127
+ return strip_raw_text_tag if raw_text?
113
128
  return line
114
129
  end
115
130
 
@@ -131,7 +146,7 @@ module Orgmode
131
146
  check_assignment_or_regexp(:table_separator, /^\s*\|[-\|\+]*\s*$/)
132
147
  end
133
148
 
134
- # Checks if this line is a table header.
149
+ # Checks if this line is a table header.
135
150
  def table_header?
136
151
  @assigned_paragraph_type == :table_header
137
152
  end
@@ -140,7 +155,7 @@ module Orgmode
140
155
  table_row? or table_separator? or table_header?
141
156
  end
142
157
 
143
- BlockRegexp = /^\s*#\+(BEGIN|END)_(\w*)\s*(\w*)?/i
158
+ BlockRegexp = /^\s*#\+(BEGIN|END)_(\w*)\s*([0-9A-Za-z_\-]*)?/i
144
159
 
145
160
  def begin_block?
146
161
  @line =~ BlockRegexp && $1 =~ /BEGIN/i
@@ -158,7 +173,7 @@ module Orgmode
158
173
  $3 if @line =~ BlockRegexp
159
174
  end
160
175
 
161
- def code_block_type?
176
+ def code_block?
162
177
  block_type =~ /^(EXAMPLE|SRC)$/i
163
178
  end
164
179
 
@@ -170,6 +185,21 @@ module Orgmode
170
185
  check_assignment_or_regexp(:inline_example, InlineExampleRegexp)
171
186
  end
172
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
+
173
203
  InBufferSettingRegexp = /^#\+(\w+):\s*(.*)$/
174
204
 
175
205
  # call-seq:
@@ -192,29 +222,60 @@ module Orgmode
192
222
  end
193
223
 
194
224
  # Determines the paragraph type of the current line.
195
- def paragraph_type
196
- return :blank if blank?
197
- return :definition_list if definition_list? # order is important! A definition_list is also an unordered_list!
198
- return :ordered_list if ordered_list?
199
- return :unordered_list if unordered_list?
200
- return :property_drawer_begin_block if property_drawer_begin_block?
201
- return :property_drawer_end_block if property_drawer_end_block?
202
- return :property_drawer_item if property_drawer_item?
203
- return :metadata if metadata?
204
- return :begin_block if begin_block?
205
- return :end_block if end_block?
206
- return :comment if comment?
207
- return :table_separator if table_separator?
208
- return :table_row if table_row?
209
- return :table_header if table_header?
210
- return :inline_example if inline_example?
211
- return :paragraph
212
- end
213
-
214
- def self.to_textile(lines)
215
- output = ""
216
- output_buffer = TextileOutputBuffer.new(output)
217
- Parser.translate(lines, output_buffer)
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
218
279
  end
219
280
 
220
281
  ######################################################################
@@ -227,7 +288,7 @@ module Orgmode
227
288
  # What's tricky is lines can have assigned types, so you need to check
228
289
  # the assigned type, if present, or see if the characteristic regexp
229
290
  # for the paragraph type matches if not present.
230
- #
291
+ #
231
292
  # call-seq:
232
293
  # check_assignment_or_regexp(assignment, regexp) => boolean
233
294
  #
@@ -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
- # This is the current type of output being accumulated.
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,33 +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)
81
- @logger.debug "Looking at #{line.paragraph_type}: #{line.to_s}"
82
- if not should_accumulate_output?(line) then
83
- @block_lang = line.block_lang if line.begin_block? and line.code_block_type?
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.
62
+ @logger.debug "Looking at #{line.paragraph_type}(#{current_mode}) : #{line.to_s}"
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)
84
66
  flush!
85
- maintain_list_indent_stack(line)
86
- @output_type = line.paragraph_type
67
+ maintain_mode_stack(line)
87
68
  end
88
- push_mode(:inline_example) if line.inline_example? and current_mode != :inline_example and not line.property_drawer?
89
- pop_mode(:inline_example) if current_mode == :inline_example and !line.inline_example?
90
- push_mode(:property_drawer) if line.property_drawer? and current_mode != :property_drawer
91
- pop_mode(:property_drawer) if current_mode == :property_drawer and line.property_drawer_end_block?
92
- push_mode(:table) if enter_table?
93
- pop_mode(:table) if exit_table?
94
- @buffered_lines.push(line)
95
- end
96
-
97
- # Flushes everything currently in the accumulation buffer into the
98
- # output buffer. Derived classes must override this to actually move
99
- # content into the output buffer with the appropriate markup. This
100
- # method just does common bookkeeping cleanup.
101
- def clear_accumulation_buffer!
102
- @buffer = ""
103
- @buffer_mode = nil
104
- @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
105
102
  end
106
103
 
107
104
  # Gets the next headline number for a given level. The intent is
@@ -120,79 +117,83 @@ module Orgmode
120
117
  @headline_number_stack.join(".")
121
118
  end
122
119
 
123
- # Tests if we are entering a table mode.
124
- def enter_table?
125
- ((@output_type == :table_row) || (@output_type == :table_header) || (@output_type == :table_separator)) &&
126
- (current_mode != :table)
127
- end
128
-
129
- # Tests if we are existing a table mode.
130
- def exit_table?
131
- ((@output_type != :table_row) && (@output_type != :table_header) && (@output_type != :table_separator)) &&
132
- (current_mode == :table)
133
- end
134
-
135
- # Accumulate the string @str@.
136
- def << (str)
137
- if @buffer_mode && @buffer_mode != current_mode then
138
- raise "Accumulation buffer is mixing modes: @buffer_mode == #{@buffer_mode}, current_mode == #{current_mode}"
139
- else
140
- @buffer_mode = current_mode
141
- end
142
- @buffer << str
143
- end
144
-
145
- # Gets the current list indent level.
120
+ # Gets the current list indent level.
146
121
  def list_indent_level
147
122
  @list_indent_stack.length
148
123
  end
149
124
 
150
125
  # Test if we're in an output mode in which whitespace is significant.
151
126
  def preserve_whitespace?
152
- mode_is_code current_mode
127
+ [:example, :inline_example, :raw_text, :src].include? current_mode
153
128
  end
154
129
 
155
130
  ######################################################################
156
131
  private
157
132
 
158
- def mode_is_code(mode)
159
- case mode
160
- when :src, :inline_example, :example
161
- true
162
- else
163
- false
164
- end
133
+ def mode_is_heading?(mode)
134
+ [:heading1, :heading2, :heading3,
135
+ :heading4, :heading5, :heading6].include? mode
165
136
  end
166
137
 
167
- def maintain_list_indent_stack(line)
168
- if (line.plain_list?) then
169
- while (not @list_indent_stack.empty? \
170
- and (@list_indent_stack.last > line.indent))
171
- @list_indent_stack.pop
172
- pop_mode
173
- end
174
- if (@list_indent_stack.empty? \
175
- or @list_indent_stack.last < line.indent)
176
- @list_indent_stack.push(line.indent)
177
- push_mode line.paragraph_type
178
- end
179
- elsif line.blank? then
138
+ def mode_is_block?(mode)
139
+ [:quote, :center, :example, :src].include? mode
140
+ end
180
141
 
181
- # Nothing
142
+ def mode_is_code?(mode)
143
+ [:example, :src].include? mode
144
+ end
182
145
 
183
- elsif ((line.paragraph_type == :paragraph) and
184
- (not @list_indent_stack.empty? and
185
- 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
186
153
 
187
- # Nothing -- output this paragraph inside
188
- # 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)
189
161
 
190
- else
191
- @list_indent_stack = []
192
- while ((current_mode == :ordered_list) or
193
- (current_mode == :definition_list) or
194
- (current_mode == :unordered_list))
195
- 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?
196
197
  end
197
198
  end
198
199
  end
@@ -202,36 +203,43 @@ module Orgmode
202
203
  end
203
204
 
204
205
  # Tests if the current line should be accumulated in the current
205
- # output buffer. (Extraneous line breaks in the orgmode buffer
206
- # are removed by accumulating lines in the output buffer without
207
- # line breaks.)
208
- def should_accumulate_output?(line)
209
-
210
- # Special case: Preserve line breaks in block code mode.
211
- return false if preserve_whitespace?
212
-
213
- # Special case: Multiple blank lines get accumulated.
214
- return true if line.paragraph_type == :blank and @output_type == :blank
215
-
216
- # Currently only "paragraphs" get accumulated with previous output.
217
- return false unless line.paragraph_type == :paragraph
218
- if ((@output_type == :ordered_list) or
219
- (@output_type == :definition_list) or
220
- (@output_type == :unordered_list)) then
221
-
222
- # If the previous output type was a list item, then we only put a paragraph in it
223
- # if its indent level is greater than the list indent level.
224
-
225
- 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
226
236
  end
227
237
 
228
- # Only accumulate paragraphs with lists & paragraphs.
229
- return false unless
230
- ((@output_type == :paragraph) or
231
- (@output_type == :ordered_list) or
232
- (@output_type == :definition_list) or
233
- (@output_type == :unordered_list))
234
- true
238
+ false
239
+ end
240
+
241
+ def buffer_indentation
242
+ return false
235
243
  end
236
244
  end # class OutputBuffer
237
245
  end # module Orgmode