wikicloth 0.7.1 → 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.
@@ -0,0 +1,39 @@
1
+ module WikiCloth
2
+ class MathExtension < Extension
3
+
4
+ # <math>latex markup</math>
5
+ #
6
+ element 'math', :skip_html => true, :run_globals => false do |buffer|
7
+
8
+ blahtex_path = @options[:blahtex_path] || '/usr/bin/blahtex'
9
+ blahtex_png_path = @options[:blahtex_png_path] || '/tmp'
10
+ blahtex_options = @options[:blahtex_options] || '--texvc-compatible-commands --mathml-version-1-fonts --disallow-plane-1 --spacing strict'
11
+
12
+ if File.exists?(blahtex_path) && @options[:math_formatter] != :google
13
+ begin
14
+ # pass tex markup to blahtex
15
+ response = `echo '#{buffer.element_content}' | #{blahtex_path} #{blahtex_options} --png --mathml --png-directory #{blahtex_png_path}`
16
+ xml_response = REXML::Document.new(response).root
17
+
18
+ if @options[:blahtex_html_prefix]
19
+ # render as embedded image
20
+ file_md5 = xml_response.elements["png/md5"].text
21
+ "<img src=\"#{File.join(@options[:blahtex_html_prefix],"#{file_md5}.png")}\" />"
22
+ else
23
+ # render as mathml
24
+ html = xml_response.elements["mathml/markup"].text
25
+ "<math xmlns=\"http://www.w3.org/1998/Math/MathML\">#{xml_response.elements["mathml/markup"].children.to_s}</math>"
26
+ end
27
+ rescue => err
28
+ # blahtex error
29
+ "<span class=\"error\">#{I18n.t("unable to parse mathml", :error => err)}</span>"
30
+ end
31
+ else
32
+ # if blahtex does not exist fallback to google charts api
33
+ encoded_string = URI.escape(buffer.element_content, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
34
+ "<img src=\"https://chart.googleapis.com/chart?cht=tx&chl=#{encoded_string}\" />"
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,15 @@
1
+ module WikiCloth
2
+ class PoemExtension < Extension
3
+
4
+ # <poem>poem content (to preserve spacing)</poem>
5
+ #
6
+ element 'poem' do |buffer|
7
+ buffer.element_content.gsub!(/\A\n/,"") # remove new line at beginning of string
8
+ buffer.element_content.gsub!(/\n\z/,"") # remove new line at end of string
9
+ buffer.element_content.gsub!(/^\s+/) { |m| "&nbsp;" * m.length } # replace all spaces at beginning of line with &nbsp;
10
+ buffer.element_content.gsub!(/\n/,'<br />') # replace all new lines with <br />
11
+ "<div class=\"poem\">#{buffer.element_content}</div>"
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,48 @@
1
+ module WikiCloth
2
+ class ReferencesExtension < Extension
3
+
4
+ # <ref>reference content</ref>
5
+ # <ref name="named">reference content</ref>
6
+ # <ref name="named" />
7
+ # <ref group="group_name">reference content</ref>
8
+ #
9
+ element 'ref' do |buffer|
10
+ # find our named reference reference if it exists
11
+ named_ref = buffer.get_attribute_by_name("name")
12
+ ref = @options[:link_handler].find_reference_by_name(named_ref) unless named_ref.nil?
13
+
14
+ # reference either not "named" or first time in document
15
+ if ref.nil?
16
+ @options[:link_handler].references << { :name => named_ref, :value => buffer.element_content, :count => 0, :group => buffer.get_attribute_by_name("group") }
17
+ ref = @options[:link_handler].references.last
18
+ end
19
+
20
+ ref_id = (named_ref.nil? ? "" : "#{named_ref}_") + "#{@options[:link_handler].reference_index(ref)}-#{ref[:count]}"
21
+ cite_anchor = "#cite_note-" + (named_ref.nil? ? "" : "#{named_ref}_") + @options[:link_handler].reference_index(ref).to_s
22
+ group_label = buffer.get_attribute_by_name("group") ? "#{buffer.get_attribute_by_name("group")} " : ""
23
+ ref_link = "<a href=\"#{cite_anchor}\">#{@options[:link_handler].reference_index(ref)}</a>"
24
+ ref[:count] += 1
25
+
26
+ "<sup class=\"reference\" id=\"cite_ref-#{ref_id}\">[#{group_label}#{ref_link}]</sup>"
27
+ end
28
+
29
+ # <references />
30
+ # <references group="group_name" />
31
+ #
32
+ element 'references' do |buffer|
33
+ ref_count = 0
34
+ group_match = buffer.get_attribute_by_name("group")
35
+ refs = @options[:link_handler].references.collect { |r|
36
+ next if r[:group] != group_match
37
+ ref_count += 1
38
+ ref_name = (r[:name].nil? ? "" : r[:name].to_slug + "_")
39
+ ret = "<li id=\"cite_note-#{ref_name}#{ref_count}\"><b>"
40
+ 1.upto(r[:count]) { |x| ret += "<a href=\"#cite_ref-#{ref_name}#{ref_count}-#{x-1}\">" +
41
+ (r[:count] == 1 ? "^" : (x-1).to_s(26).tr('0-9a-p', 'a-z')) + "</a> " }
42
+ ret += "</b> #{r[:value]}</li>"
43
+ }.to_s
44
+ "<ol>#{refs}</ol>"
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,46 @@
1
+ module WikiCloth
2
+ class LuaExtension < Extension
3
+
4
+ VALID_LANGUAGES = [ 'as','applescript','arm','asp','asm','awk','bat','bibtex','bbcode','bison','lua',
5
+ 'bms','boo','c','c++','cc','cpp','cxx','h','hh','hpp','hxx','clojure','cbl','cob','cobol','cfc','cfm',
6
+ 'coldfusion','csharp','cs','css','d','diff','patch','erlang','erl','hrl','go','hs','haskell','html',
7
+ 'htm','xml','xhtml','httpd','js','javascript','matlab','m','perl','cgi','pl','plex','plx','pm','php',
8
+ 'php3','php4','php5','php6','python','py','ruby','rb' ]
9
+
10
+ # <source lang="language">source code</source>
11
+ #
12
+ element 'source', :skip_html => true, :run_globals => false do |buffer|
13
+
14
+ highlight_path = @options[:highlight_path] || '/usr/bin/highlight'
15
+ highlight_options = @options[:highlight_options] || '--inline-css'
16
+
17
+ name = buffer.element_name
18
+ content = buffer.element_content
19
+ content = $1 if content =~ /^\s*\n(.*)$/m
20
+ error = nil
21
+
22
+ if File.exists?(highlight_path)
23
+ begin
24
+ raise I18n.t("lang attribute is required") unless buffer.element_attributes.has_key?('lang')
25
+ raise I18n.t("unknown lang", :lang => buffer.element_attributes['lang'].downcase) unless LuaExtension::VALID_LANGUAGES.include?(buffer.element_attributes['lang'].downcase)
26
+ IO.popen("#{highlight_path} #{highlight_options} -f --syntax #{buffer.element_attributes['lang'].downcase}", "r+") do |io|
27
+ io.puts content
28
+ io.close_write
29
+ content = io.read
30
+ end
31
+ rescue => err
32
+ error = "<span class=\"error\">#{err.message}</span>"
33
+ end
34
+ else
35
+ content = content.gsub('<','&lt;').gsub('>','&gt;')
36
+ end
37
+
38
+ if error.nil?
39
+ "<pre>#{content}</pre>"
40
+ else
41
+ error
42
+ end
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,108 @@
1
+ require 'yaml'
2
+ module I18n
3
+
4
+ class << self
5
+
6
+ def default_locale
7
+ :en
8
+ end
9
+
10
+ def locale
11
+ @@locale ||= default_locale
12
+ end
13
+
14
+ def locale=(val)
15
+ @@locale = val
16
+ end
17
+
18
+ def t(*args)
19
+ options = args.last.is_a?(Hash) ? args.pop : {}
20
+ key = args.shift
21
+
22
+ load_translations
23
+ use_locale = @@translations[locale].nil? || @@translations[locale].empty? ? default_locale : locale
24
+
25
+ if @@translations[use_locale].has_key?(key)
26
+ add_vars(@@translations[use_locale][key], options)
27
+ elsif use_locale != default_locale && @@translations[default_locale].has_key?(key)
28
+ add_vars(@@translations[default_locale][key], options)
29
+ else
30
+ "translation missing: #{locale}, #{key}"
31
+ end
32
+ end
33
+
34
+ def available_locales
35
+ load_translations
36
+ @@available_locales
37
+ end
38
+
39
+ def load_path
40
+ @@load_paths ||= []
41
+ end
42
+
43
+ def load_path=(val)
44
+ @@load_paths = val
45
+ end
46
+
47
+ def load_translations
48
+ return if initialized?
49
+
50
+ @@available_locales = []
51
+ @@translations = {}
52
+ load_path.each do |path|
53
+ Dir[path].each do |file|
54
+ begin
55
+ data = YAML::load(File.read(file))
56
+ data.each do |key,value|
57
+ @@available_locales << key.to_sym unless @@available_locales.include?(key.to_sym)
58
+ @@translations[key.to_sym] ||= {}
59
+ import_values(key.to_sym,value)
60
+ end
61
+ rescue ArgumentError => err
62
+ puts "error in #{file}: #{err.message}"
63
+ end
64
+ end
65
+ end
66
+
67
+ initialized!
68
+ end
69
+
70
+ def initialized?
71
+ @@initialized ||= false
72
+ end
73
+
74
+ def initialized!
75
+ @@initialized = true
76
+ end
77
+
78
+ # Executes block with given I18n.locale set.
79
+ def with_locale(tmp_locale = nil)
80
+ if tmp_locale
81
+ current_locale = self.locale
82
+ self.locale = tmp_locale
83
+ end
84
+ yield
85
+ ensure
86
+ self.locale = current_locale if tmp_locale
87
+ end
88
+
89
+ private
90
+ def import_values(key,values,prefix=[])
91
+ values.each do |k,value|
92
+ if value.is_a?(Hash)
93
+ import_values(key,value,prefix+[k])
94
+ else
95
+ @@translations[key.to_sym][(prefix+[k]).join(".")] = value
96
+ end
97
+ end
98
+ end
99
+
100
+ def add_vars(string, options)
101
+ options.each do |key,value|
102
+ string.gsub!(/(%\{#{key}\})/, value.to_s)
103
+ end
104
+ string
105
+ end
106
+ end
107
+
108
+ end
@@ -0,0 +1,62 @@
1
+ module WikiCloth
2
+
3
+ class WikiNamespaces
4
+ class << self
5
+
6
+ NAMESPACE_TYPES = [:file,:category,:template,:special,:language,:help,:talk,:media]
7
+
8
+ def language_namespace_names
9
+ I18n.available_locales.collect { |l| l.to_s.gsub(/[_]+/,'-') }
10
+ end
11
+
12
+ def language_name(ns, locale=nil)
13
+ return nil unless language_namespace_names.include?(ns)
14
+ locale ||= I18n.locale
15
+ I18n.with_locale(locale) do
16
+ I18n.t("languages.#{ns}")
17
+ end
18
+ end
19
+
20
+ def localise_ns(name, locale=nil)
21
+ locale ||= I18n.locale
22
+ ns_type = namespace_type(name)
23
+ unless ns_type.nil? || ns_type == :language
24
+ I18n.with_locale(locale) do
25
+ I18n.t("namespaces.#{ns_type.to_s}").split(",").first
26
+ end
27
+ else
28
+ name
29
+ end
30
+ end
31
+
32
+ def namespace_type(name)
33
+ return :language if language_namespace_names.include?(name)
34
+ NAMESPACE_TYPES.each { |ns| return ns if send("#{ns}_namespace_names").include?(name.downcase) }
35
+ nil
36
+ end
37
+
38
+ def method_missing(method, *args)
39
+ if method.to_s =~ /^([a-z]+)_namespace_names$/
40
+ @@ns_cache ||= {}
41
+ @@ns_cache[$1] ||= get_namespace_names_for($1)
42
+ elsif method.to_s =~ /^([a-z]+)_namespace\?$/
43
+ namespace_type(args.first) == $1.to_sym ? true : false
44
+ else
45
+ super(method, *args)
46
+ end
47
+ end
48
+
49
+ def get_namespace_names_for(name)
50
+ ret = []
51
+ I18n.available_locales.each do |locale|
52
+ I18n.with_locale(locale) do
53
+ I18n.t("namespaces.#{name}").split(",").each { |ns| ret << ns.downcase unless ret.include?(ns.downcase) }
54
+ end
55
+ end
56
+ ret
57
+ end
58
+
59
+ end
60
+ end
61
+
62
+ end
@@ -2,16 +2,16 @@ module WikiCloth
2
2
 
3
3
  class Parser < WikiLinkHandler
4
4
 
5
- def initialize(opt={})
6
- opt.each { |k,v|
5
+ def initialize(options={})
6
+ options.each { |k,v|
7
7
  if v.instance_of?(Proc)
8
8
  self.class.send :define_method, k.to_sym do |*args|
9
9
  self.instance_exec(args,&v)
10
10
  end
11
11
  end
12
12
  }
13
- @params = opt[:params] || {}
14
- @wikicloth = WikiCloth.new(:data => opt[:data], :link_handler => self, :params => @params)
13
+ @options = { :link_handler => self, :params => {} }.merge(options)
14
+ @wikicloth = WikiCloth.new(@options)
15
15
  end
16
16
 
17
17
  class << self
@@ -22,8 +22,8 @@ module WikiCloth
22
22
  end
23
23
 
24
24
  def toc(&block)
25
- self.send :define_method, 'toc' do |sections|
26
- self.instance_exec(sections, &block)
25
+ self.send :define_method, 'toc' do |sections, numbered|
26
+ self.instance_exec(sections, numbered, &block)
27
27
  end
28
28
  end
29
29
 
@@ -76,12 +76,26 @@ module WikiCloth
76
76
  self.instance_exec(page,&block)
77
77
  end
78
78
  end
79
+
80
+ def cache(&block)
81
+ self.send :define_method, 'cache' do |item|
82
+ self.instance_exec(item,&block)
83
+ end
84
+ end
85
+ end
86
+
87
+ def method_missing(method, *args)
88
+ if @wikicloth.respond_to?(method)
89
+ @wikicloth.send(method, *args)
90
+ else
91
+ super(method, *args)
92
+ end
79
93
  end
80
94
 
81
95
  # Replace a section, along with any sub-section in the document
82
96
  def put_section(id,data)
83
97
  data = @wikicloth.sections.collect { |s| s.wikitext({ :replace => { id => data.last(1) == "\n" ? data : "#{data}\n" } }) }.join
84
- @wikicloth = WikiCloth.new(:data => data, :link_handler => self, :params => @params)
98
+ @wikicloth = WikiCloth.new(:data => data, :link_handler => self, :params => @options[:params])
85
99
  end
86
100
 
87
101
  # Get the section, along with any sub-section of the document
@@ -89,14 +103,6 @@ module WikiCloth
89
103
  @wikicloth.sections.collect { |s| s.get_section(id) }.join
90
104
  end
91
105
 
92
- def sections
93
- @wikicloth.sections
94
- end
95
-
96
- def to_html(opts = {})
97
- @wikicloth.to_html(opts)
98
- end
99
-
100
106
  def to_wiki
101
107
  to_wikitext
102
108
  end
@@ -72,12 +72,8 @@ module WikiCloth
72
72
  if self.title.nil?
73
73
  ret = ""
74
74
  else
75
- ret = "<h#{self.depth}>" + (options[:noedit] == true ? "" :
76
- "<span class=\"editsection\">&#91;<a href=\"" + options[:link_handler].section_link(self.id) +
77
- "\" title=\"Edit section: #{self.title}\">edit</a>&#93;</span> ") +
78
- "<span id=\"#{self.id}\" class=\"mw-headline\"><a name=\"#{self.id}\">#{self.title}</a></span></h#{self.depth}>\n"
75
+ ret = "\n#{@title}\n"
79
76
  end
80
- #ret += @template ? self.gsub(/\{\{\{\s*([A-Za-z0-9]+)\s*\}\}\}/,'\1') : self
81
77
  ret += self
82
78
  ret += "__TOC__" if @auto_toc
83
79
  ret += @children.collect { |c| c.render(options) } .join
@@ -1,3 +1,3 @@
1
1
  module WikiCloth
2
- VERSION = "0.7.1" unless defined?(::WikiCloth::VERSION)
2
+ VERSION = "0.8.0" unless defined?(::WikiCloth::VERSION)
3
3
  end
@@ -63,7 +63,7 @@ class WikiBuffer
63
63
  @buffer_type
64
64
  end
65
65
 
66
- def to_s
66
+ def to_html
67
67
  self.params.join("\n") + (@list_data.empty? ? "" : render_list_data()) + (@paragraph_open ? "</p>" : "")
68
68
  end
69
69
 
@@ -138,7 +138,7 @@ class WikiBuffer
138
138
  while @buffers.size > 1
139
139
  @buffers[-1].eof()
140
140
  tmp = @buffers.pop
141
- @buffers[-1].data += tmp.to_s
141
+ @buffers[-1].data += tmp.send("to_#{@options[:output]}")
142
142
  unless tmp.data.blank?
143
143
  tmp.data.each_char { |x| self.add_char(x) }
144
144
  end
@@ -158,9 +158,9 @@ class WikiBuffer
158
158
  return self.new_char()
159
159
  when @buffers[-1].add_char(c) == false && self.class == WikiBuffer
160
160
  tmp = @buffers.pop
161
- @buffers[-1].data += tmp.to_s
161
+ @buffers[-1].data += tmp.send("to_#{@options[:output]}")
162
162
  # any data left in the buffer we feed into the parent
163
- unless tmp.data.blank?
163
+ unless tmp.data.nil?
164
164
  tmp.data.each_char { |x| self.add_char(x) }
165
165
  end
166
166
  end
@@ -178,11 +178,15 @@ class WikiBuffer
178
178
  self.data.gsub!(/_([^_]+)_/,"<u>\\1</u>")
179
179
  end
180
180
 
181
- # Magic Words
182
- self.data.gsub!(/__([A-Z]+)__/) { |r|
183
- case $1
184
- when "TOC"
181
+ # Behavior Switches
182
+ self.data.gsub!(/__([\w]+)__/) { |r|
183
+ case behavior_switch_key_name($1)
184
+ when "behavior_switches.toc"
185
185
  @options[:link_handler].toc(@options[:sections], @options[:toc_numbered])
186
+ when "behavior_switches.noeditsection"
187
+ @options[:noedit] = true
188
+ when "behavior_switches.editsection"
189
+ @options[:noedit] = false
186
190
  else
187
191
  ""
188
192
  end
@@ -191,14 +195,7 @@ class WikiBuffer
191
195
  # Horizontal Rule
192
196
  self.data.gsub!(/^([-]{4,})/) { |r| "<hr />" }
193
197
 
194
- # Bold, Italic
195
- self.data.gsub!(/([\']{2,5})(.*?)(\1)/) { |r|
196
- tmp = "<i>#{$2}</i>" if $1.length == 2
197
- tmp = "<b>#{$2}</b>" if $1.length == 3
198
- tmp = "<b>'#{$2}'</b>" if $1.length == 4
199
- tmp = "<b><i>#{$2}</i></b>" if $1.length == 5
200
- tmp
201
- }
198
+ render_bold_italic()
202
199
 
203
200
  # Lists
204
201
  tmp = ''
@@ -218,7 +215,7 @@ class WikiBuffer
218
215
  is_heading = false
219
216
  self.data.gsub!(/^([=]{1,6})\s*(.*?)\s*(\1)/) { |r|
220
217
  is_heading = true
221
- (@paragraph_open ? "</p>" : "") + "<h#{$1.length}>#{$2}</h#{$1.length}>"
218
+ (@paragraph_open ? "</p>" : "") + gen_heading($1.length,$2)
222
219
  }
223
220
 
224
221
  # Paragraphs
@@ -238,11 +235,43 @@ class WikiBuffer
238
235
  self.params << self.data.auto_link
239
236
  self.data = ""
240
237
  else
241
- self.data += current_char
238
+ self.data << current_char
242
239
  end
243
240
  return true
244
241
  end
245
242
 
243
+ def behavior_switch_key_name(name)
244
+ keys = [:toc,:notoc,:forcetoc,:noeditsection,:editsection]
245
+ locales = [@options[:locale],I18n.default_locale]
246
+ values = {}
247
+
248
+ locales.each do |locale|
249
+ I18n.with_locale(locale) do
250
+ keys.each do |key|
251
+ values[I18n.t("behavior_switches.#{key.to_s}")] = "behavior_switches.#{key.to_s}"
252
+ end
253
+ end
254
+ end
255
+
256
+ values[name]
257
+ end
258
+
259
+ def gen_heading(hnum,title)
260
+ id = get_id_for(title.gsub(/\s+/,'_'))
261
+ "<h#{hnum}>" + (@options[:noedit] == true ? "" :
262
+ "<span class=\"editsection\">&#91;<a href=\"" + @options[:link_handler].section_link(id) +
263
+ "\" title=\"#{I18n.t('edit section', :name => title)}\">#{I18n.t('edit')}</a>&#93;</span> ") +
264
+ "<span class=\"mw-headline\" id=\"#{id}\"><a name=\"#{id}\">#{title}</a></span></h#{hnum}>\n"
265
+ end
266
+
267
+ def get_id_for(val)
268
+ val.gsub!(/[^A-Za-z0-9_]+/,'')
269
+ @idmap ||= {}
270
+ @idmap[val] ||= 0
271
+ @idmap[val] += 1
272
+ @idmap[val] == 1 ? val : "#{val}-#{@idmap[val]}"
273
+ end
274
+
246
275
  def name_current_param()
247
276
  params[-1] = { :value => "", :name => params[-1] } unless params[-1].kind_of?(Hash) || params[-1].nil?
248
277
  end
@@ -291,35 +320,116 @@ class WikiBuffer
291
320
  @current_line ||= ""
292
321
  end
293
322
 
323
+ BOLD_ITALIC_MAP = {
324
+ 0 => {
325
+ :bold => [10, "<b>"],
326
+ :italic => [20, "<i>"],
327
+ :bold_italic => [40, "<i><b>"],
328
+ :four => [10, "'<b>"],
329
+ :finish => [0, ""]
330
+ },
331
+ 10 => {
332
+ :bold => [0, "</b>"],
333
+ :italic => [30, "<i>"],
334
+ :bold_italic => [20, "</b><i>"],
335
+ :four => [0, "'</b>"],
336
+ :finish => [0, "</b>"]
337
+ },
338
+ 20 => {
339
+ :bold => [40, "<b>"],
340
+ :italic => [0, "</i>"],
341
+ :bold_italic => [10, "</i><b>"],
342
+ :four => [40, "'<b>"],
343
+ :finish => [0, "</i>"]
344
+ },
345
+ 30 => {
346
+ :bold => [20, "</i></b><i>"],
347
+ :italic => [10, "</i>"],
348
+ :bold_italic => [0, "</i></b>"],
349
+ :four => [20, "'</i></b><i>"],
350
+ :finish => [0, "</i></b>"]
351
+ },
352
+ 40 => {
353
+ :bold => [20, "</b>"],
354
+ :italic => [10, "</b></i><b>"],
355
+ :bold_italic => [0, "</b></i>"],
356
+ :four => [20, "'</b>"],
357
+ :finish => [0, "</b></i>"]
358
+ },
359
+ }
360
+
361
+ def render_bold_italic()
362
+
363
+ commands = []
364
+ self.data.scan(/([\']{2,5})/) do
365
+ commands << {
366
+ :len => $1.length,
367
+ :type => [nil, nil, :italic, :bold, :four, :bold_italic][$1.length],
368
+ :pos => $~.offset(0).first
369
+ }
370
+ end
371
+ commands << {:type => :finish}
372
+
373
+ state = 0
374
+ commands.each do |c|
375
+ trans = BOLD_ITALIC_MAP[state][c[:type]]
376
+ c[:output] = trans.last
377
+ state = trans.first
378
+ end
379
+
380
+ index = 0
381
+ self.data.gsub!(/([\']{2,5})/) do
382
+ output = commands[index][:output]
383
+ index += 1
384
+ output
385
+ end
386
+ self.data << commands.last[:output]
387
+ end
388
+
294
389
  def render_list_data()
390
+
295
391
  ret = ""
296
- depth = 0
297
- peices = ""
392
+ last = ""
298
393
 
299
- @list_data.each do |l|
300
- if l =~ /^([#\*:;]+)\s*(.*)$/
301
- peices = $1
302
- content = $2
303
- if peices.length > depth
304
- while peices.length > depth
305
- ret += "<#{list_tag_for(peices[depth,1])}><#{list_inner_tag_for(peices[depth,1])}>"
306
- depth += 1
394
+ process_line = Proc.new do |pieces, content|
395
+
396
+ common = 0
397
+ (0..last.length - 1).each do |i|
398
+ if last[i] == pieces[i]
399
+ common += 1
400
+ else
401
+ break
307
402
  end
308
- elsif peices.length == depth
309
- ret += "</#{list_inner_tag_for(peices[depth-1,1])}><#{list_inner_tag_for(peices[depth-1,1])}>"
310
- else
311
- while peices.length < depth
312
- depth -= 1
313
- ret += "</#{list_inner_tag_for(peices[depth-1,1])}></#{list_tag_for(peices[depth-1,1])}><#{list_inner_tag_for(peices[depth-1,1])}>"
403
+ end
404
+
405
+ close = last[common..-1].reverse
406
+ open = pieces[common..-1]
407
+
408
+ close.each_char do |e|
409
+ ret << "</#{list_inner_tag_for(e)}></#{list_tag_for(e)}>"
410
+ end
411
+ if open == '' && pieces != ''
412
+ if last != ''
413
+ ret << "</#{list_inner_tag_for(pieces[-1,1])}>"
314
414
  end
415
+ ret << "<#{list_inner_tag_for(pieces[-1,1])}>"
416
+ end
417
+ open.each_char do |e|
418
+ ret << "<#{list_tag_for(e)}><#{list_inner_tag_for(e)}>"
315
419
  end
316
- ret += "#{content}"
420
+
421
+ ret << content
422
+
423
+ last = pieces.clone
424
+ end
425
+
426
+ (@list_data + ['']).each do |l|
427
+ if l =~ /^([#\*:;]+)\s*(.*)$/
428
+ process_line.call($1, $2)
317
429
  end
318
430
  end
319
- while depth > 0
320
- depth -= 1
321
- ret += "</#{list_inner_tag_for(peices[depth,1])}></#{list_tag_for(peices[depth,1])}>"
322
- end
431
+ process_line.call('', '')
432
+
323
433
  @list_data = []
324
434
  ret + "\n"
325
435
  end
@@ -350,3 +460,5 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "html
350
460
  require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "table")
351
461
  require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "var")
352
462
  require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "link")
463
+ # load all extensions
464
+ Dir[File.join(File.expand_path(File.dirname(__FILE__)), "extensions/*.rb")].each { |r| require r }