trac-wiki 0.2.24 → 0.3.10
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/.gitignore +1 -0
- data/Gemfile +0 -2
- data/Gemfile.lock +1 -9
- data/README +92 -11
- data/lib/trac-wiki/env.rb +92 -63
- data/lib/trac-wiki/parser.rb +248 -254
- data/lib/trac-wiki/tree.rb +22 -27
- data/lib/trac-wiki/version.rb +1 -1
- data/lib/trac-wiki.rb +4 -4
- data/test/parser_test.rb +112 -33
- metadata +2 -2
data/lib/trac-wiki/parser.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
require 'cgi'
|
2
3
|
require 'uri'
|
3
|
-
require 'iconv'
|
4
4
|
require 'yaml'
|
5
|
+
require 'unicode_utils/compatibility_decomposition'
|
5
6
|
|
6
7
|
# :main: TracWiki
|
7
8
|
|
8
9
|
# The TracWiki parses and translates Trac formatted text into
|
9
|
-
# XHTML.
|
10
|
+
# XHTML. TracWiki is a lightweight markup syntax similar to what many
|
10
11
|
# WikiWikiWebs use. Example syntax:
|
11
12
|
#
|
12
13
|
# = Heading 1 =
|
@@ -20,12 +21,7 @@ require 'yaml'
|
|
20
21
|
# [[Image(image.png)]]
|
21
22
|
# [[Image(image.png, options)]]
|
22
23
|
#
|
23
|
-
#
|
24
|
-
# links allow explicit local links using the [[link]] syntax. External
|
25
|
-
# links will only be allowed if specified using http(s) and ftp(s)
|
26
|
-
# schemes. If special link handling is needed, such as inter-wiki or
|
27
|
-
# hierachical local links, you must inherit Creole::CreoleParser and
|
28
|
-
# override make_local_link.
|
24
|
+
# for more see http://trac.edgewall.org/wiki/WikiFormatting
|
29
25
|
#
|
30
26
|
# You can customize the created image markup by overriding
|
31
27
|
# make_image.
|
@@ -48,7 +44,19 @@ module TracWiki
|
|
48
44
|
# Examples: http https ftp ftps
|
49
45
|
attr_accessor :allowed_schemes
|
50
46
|
|
47
|
+
# structure where headings are stroed
|
48
|
+
# list of hasheses with `level` and `title`, `sline`
|
49
|
+
# [ { leven: 1, # <h1>
|
50
|
+
# sline: 3, # line where head starts
|
51
|
+
# eline: 4, # line before next heading starts
|
52
|
+
# aname: 'anchor-to-this-heading',
|
53
|
+
# title: 'heading title'
|
54
|
+
# },
|
55
|
+
# ...
|
56
|
+
# ]
|
51
57
|
attr_accessor :headings
|
58
|
+
|
59
|
+
# url base for links
|
52
60
|
attr_writer :base
|
53
61
|
|
54
62
|
# Disable url escaping for local links
|
@@ -62,14 +70,19 @@ module TracWiki
|
|
62
70
|
attr_writer :no_link
|
63
71
|
def no_link?; @no_link; end
|
64
72
|
|
73
|
+
# math syntax extension:
|
74
|
+
# $e^x$ for inline math
|
75
|
+
# $$ e^x $$ for display math
|
65
76
|
attr_writer :math
|
66
77
|
def math?; @math; end
|
67
78
|
|
68
79
|
# allow some <b> <form> <html>
|
69
80
|
# html will be sanitized
|
70
|
-
attr_writer :
|
71
|
-
def
|
81
|
+
attr_writer :allow_html
|
82
|
+
def allow_html?; @allow_html; end
|
72
83
|
|
84
|
+
# add '<a class='editheading' href="?edit=N>edit</a>'
|
85
|
+
# to each heading
|
73
86
|
attr_writer :edit_heading
|
74
87
|
def edit_heading?; @edit_heading; end
|
75
88
|
|
@@ -82,44 +95,94 @@ module TracWiki
|
|
82
95
|
attr_writer :merge
|
83
96
|
def merge?; @merge; end
|
84
97
|
|
85
|
-
# every heading
|
98
|
+
# every heading had id, generated from heading text
|
86
99
|
attr_writer :id_from_heading
|
87
100
|
def id_from_heading?; @id_from_heading; end
|
88
101
|
|
102
|
+
# use macros? defalut yes
|
103
|
+
attr_writer :macros
|
104
|
+
def macros?; @macros; end
|
105
|
+
|
89
106
|
# when id_from_heading, non ascii char are transliterated to ascii
|
90
107
|
attr_writer :id_translit
|
91
|
-
|
92
|
-
|
108
|
+
def id_translit?; @id_translit; end
|
109
|
+
|
110
|
+
# like template but more powerfull
|
111
|
+
# do no use.
|
112
|
+
attr_accessor :macro_commands
|
113
|
+
@macro_commands = {}
|
114
|
+
|
115
|
+
# template_handler(macroname) -> template_text
|
116
|
+
# when macros enabled and {{myCoolMacro}} ocured,
|
117
|
+
# result fo `template_handler('myCoolMacro') inserted
|
118
|
+
attr_accessor :template_handler
|
93
119
|
|
94
120
|
# string begins with macro
|
95
121
|
MACRO_BEG_REX = /\A\{\{ ( \$[\$\.\w]+ | [\#!]\w* |\w+ ) /x
|
96
122
|
MACRO_BEG_INSIDE_REX = /\A(.*?)(?<!\{)\{\{ ( \$[\$\.\w]+ | [\#!]\w* | \w+ ) /xm
|
97
123
|
# find end of marcro or begin of inner macro
|
98
124
|
MACRO_END_REX = /\A(.*?) ( \}\} | \{\{ ( \$[\$\.\w]+ | [\#!]\w* | \w+) )/mx
|
99
|
-
def id_translit?; @id_translit; end
|
100
125
|
|
101
126
|
# Create a new Parser instance.
|
102
|
-
def initialize(
|
103
|
-
|
127
|
+
def initialize(options = nil)
|
128
|
+
init_macros
|
129
|
+
@macros = true
|
104
130
|
@allowed_schemes = %w(http https ftp ftps)
|
105
|
-
|
106
|
-
|
107
|
-
@plugins.merge! plugins if ! plugins.nil?
|
108
|
-
@text = text
|
131
|
+
macro_commands = options.delete :macro_commands
|
132
|
+
@macro_commands.merge! macro_commands if ! macro_commands.nil?
|
109
133
|
@no_escape = nil
|
110
134
|
@base = ''
|
111
135
|
options.each_pair {|k,v| send("#{k}=", v) }
|
112
136
|
@base += '/' if !@base.empty? && @base[-1] != '/'
|
113
137
|
end
|
114
138
|
|
115
|
-
def
|
116
|
-
@
|
139
|
+
def text(text)
|
140
|
+
@text = text
|
141
|
+
return self
|
142
|
+
end
|
143
|
+
|
144
|
+
def was_math?; @was_math; end
|
145
|
+
|
146
|
+
def to_html(text = nil)
|
147
|
+
text(text) if ! text.nil?
|
148
|
+
@was_math = false
|
149
|
+
@anames = {}
|
150
|
+
@count_lines_level = 0
|
151
|
+
@text = text if !text.nil?
|
152
|
+
@tree = TracWiki::Tree.new
|
153
|
+
@edit_heading_class = 'editheading'
|
154
|
+
@headings = [ {level: 0, sline: 1 } ]
|
155
|
+
@p = false
|
156
|
+
@stack = []
|
157
|
+
@stacki = []
|
158
|
+
@was_math = false
|
159
|
+
@line_no = 1
|
160
|
+
parse_block(@text)
|
161
|
+
@tree.to_html
|
162
|
+
end
|
163
|
+
|
164
|
+
def make_toc_html
|
165
|
+
@tree = TracWiki::Tree.new
|
166
|
+
parse_block(make_toc)
|
167
|
+
@tree.to_html
|
168
|
+
end
|
169
|
+
|
170
|
+
def add_macro_command(name, &block)
|
171
|
+
@macro_commands[name] = block
|
172
|
+
end
|
173
|
+
|
174
|
+
protected
|
175
|
+
|
176
|
+
def add_line_no(count)
|
177
|
+
@line_no += count if @count_lines_level == 0
|
178
|
+
end
|
179
|
+
|
180
|
+
def init_macros
|
181
|
+
@macro_commands = {
|
117
182
|
'!ifeq' => proc { |env| env.expand_arg(0) == env.expand_arg(1) ? env.expand_arg(2) : env.expand_arg(3) },
|
118
183
|
'!ifdef' => proc { |env| env.at(env.expand_arg(0), nil, false).nil? ? env.expand_arg(2) : env.expand_arg(1) },
|
119
184
|
'!set' => proc { |env| env[env.expand_arg(0)] = env.expand_arg(1); '' },
|
120
185
|
'!yset' => proc { |env| env[env.expand_arg(0)] = YAML.load(env.arg(1)); '' },
|
121
|
-
|
122
|
-
# '!html' => proc { |env| "\n{{{!\n#{env.arg(0)}\n}}}\n" },
|
123
186
|
'!sub' => proc { |env| pat = env.expand_arg(1)
|
124
187
|
pat = Regexp.new(pat[1..-2]) if pat =~ /\A\/.*\/\Z/
|
125
188
|
env.expand_arg(0).gsub(pat, env.expand_arg(2))
|
@@ -136,10 +199,11 @@ module TracWiki
|
|
136
199
|
set = set.keys.sort
|
137
200
|
elsif set.is_a?(Array)
|
138
201
|
set = (0 .. set.size-1)
|
202
|
+
elsif set.nil?
|
203
|
+
set = []
|
139
204
|
else
|
140
205
|
print "error top(#{top}), set#{set} #{set.class}\n"
|
141
|
-
|
142
|
-
raise "Error in {{!for #{i_name}|#{top}|#{tmpl}}}"
|
206
|
+
raise "Error in {{!for #{i_name}|#{top}|#{tmpl}}} $#{top}.class=#{set.class}(#{set.to_s})"
|
143
207
|
end
|
144
208
|
end
|
145
209
|
set.map do |i|
|
@@ -151,52 +215,9 @@ module TracWiki
|
|
151
215
|
|
152
216
|
end
|
153
217
|
|
154
|
-
# th(macroname) -> template_text
|
155
|
-
attr_accessor :template_handler
|
156
|
-
|
157
|
-
@was_math = false
|
158
|
-
def was_math?; @was_math; end
|
159
|
-
|
160
|
-
# Convert CCreole text to HTML and return
|
161
|
-
# the result. The resulting HTML does not contain <html> and
|
162
|
-
# <body> tags.
|
163
|
-
#
|
164
|
-
# Example:
|
165
|
-
#
|
166
|
-
# parser = Parser.new("**Hello //World//**")
|
167
|
-
# parser.to_html
|
168
|
-
# #=> "<p><strong>Hello <em>World</em></strong></p>"
|
169
|
-
def to_html
|
170
|
-
@tree = TracWiki::Tree.new
|
171
|
-
@edit_heading_class = 'editheading'
|
172
|
-
@headings = [ {level: 0, sline: 1 } ]
|
173
|
-
@p = false
|
174
|
-
@stack = []
|
175
|
-
@stacki = []
|
176
|
-
@was_math = false
|
177
|
-
@line_no = 1
|
178
|
-
parse_block(@text)
|
179
|
-
@tree.to_html
|
180
|
-
end
|
181
|
-
|
182
|
-
def make_toc_html
|
183
|
-
@tree = TracWiki::Tree.new
|
184
|
-
parse_block(make_toc)
|
185
|
-
@tree.to_html
|
186
|
-
end
|
187
|
-
|
188
|
-
def add_plugin(name, &block)
|
189
|
-
@plugins[name] = block
|
190
|
-
end
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
protected
|
195
|
-
|
196
218
|
# Escape any characters with special meaning in HTML using HTML
|
197
219
|
# entities. (&<>" not ')
|
198
220
|
def escape_html(string)
|
199
|
-
#CGI::escapeHTML(string)
|
200
221
|
Parser.escapeHTML(string)
|
201
222
|
end
|
202
223
|
|
@@ -252,10 +273,10 @@ module TracWiki
|
|
252
273
|
@p = false
|
253
274
|
end
|
254
275
|
|
255
|
-
def start_paragraph
|
276
|
+
def start_paragraph(add_spc = true)
|
256
277
|
if @p
|
257
278
|
#FIXME: multiple space s
|
258
|
-
@tree.add_spc
|
279
|
+
@tree.add_spc if add_spc
|
259
280
|
else
|
260
281
|
end_paragraph
|
261
282
|
start_tag('p')
|
@@ -294,44 +315,12 @@ module TracWiki
|
|
294
315
|
"#{@base}#{escape_url(link)}##{escape_url(anch)}"
|
295
316
|
end
|
296
317
|
|
297
|
-
# Sanatize a direct url (e.g. http://wikipedia.org/). The default
|
298
|
-
# behaviour returns the original link as-is.
|
299
|
-
#
|
300
|
-
# Must ensure that the result is properly URL-escaped. The caller
|
301
|
-
# will handle HTML escaping as necessary. Links will not be
|
302
|
-
# converted to HTML links if the function returns link.
|
303
|
-
#
|
304
|
-
# Custom versions of this function in inherited classes can
|
305
|
-
# implement specific link handling behaviour, such as redirection
|
306
|
-
# to intermediate pages (for example, for notifing the user that
|
307
|
-
# he is leaving the site).
|
308
|
-
def make_direct_link(url) #:doc:
|
309
|
-
url
|
310
|
-
end
|
311
|
-
|
312
|
-
# Sanatize and prefix image URLs. When images are encountered in
|
313
|
-
# Creole text, this function is called to obtain the actual URL of
|
314
|
-
# the image. The default behaviour is to return the image link
|
315
|
-
# as-is. No image tags are inserted if the function returns nil.
|
316
|
-
#
|
317
|
-
# Custom version of the method can be used to sanatize URLs
|
318
|
-
# (e.g. remove query-parts), inhibit off-site images, or add a
|
319
|
-
# base URL, for example:
|
320
|
-
#
|
321
|
-
# def make_image_link(url)
|
322
|
-
# URI.join("http://mywiki.org/images/", url)
|
323
|
-
# end
|
324
|
-
def make_image_link(url) #:doc:
|
325
|
-
url
|
326
|
-
end
|
327
|
-
|
328
318
|
# Create image markup. This
|
329
319
|
# method can be overridden to generate custom
|
330
320
|
# markup, for example to add html additional attributes or
|
331
321
|
# to put divs around the imgs.
|
332
322
|
def make_image(uri, attrs='')
|
333
|
-
|
334
|
-
@tree.tag(:img, make_image_attrs(uri, attrs))
|
323
|
+
@tree.tag(:img, make_image_attrs(@base + uri, attrs))
|
335
324
|
end
|
336
325
|
|
337
326
|
def make_image_attrs(uri, attrs)
|
@@ -361,12 +350,12 @@ module TracWiki
|
|
361
350
|
return a;
|
362
351
|
end
|
363
352
|
|
364
|
-
def make_headline(level,
|
353
|
+
def make_headline(level, title, aname, title_offset)
|
365
354
|
|
366
355
|
hN = "h#{level}".to_sym
|
367
356
|
|
368
357
|
@tree.tag_beg(hN, { id: aname } )
|
369
|
-
parse_inline(
|
358
|
+
parse_inline(title, title_offset)
|
370
359
|
if edit_heading?
|
371
360
|
edit_heading_link(@headings.size - 1)
|
372
361
|
end
|
@@ -398,148 +387,137 @@ module TracWiki
|
|
398
387
|
end.join
|
399
388
|
end
|
400
389
|
|
401
|
-
def parse_inline(str)
|
390
|
+
def parse_inline(str, offset)
|
391
|
+
raise "offset is nil" if offset.nil?
|
402
392
|
until str.empty?
|
403
|
-
case
|
404
|
-
# raw url
|
405
|
-
when /\A(!)?((https?|ftps?):\/\/\S+?)(?=([\]\,.?!:;"'\)]+)?(\s|$))/
|
406
|
-
|
407
|
-
|
408
|
-
@tree.add($2)
|
409
|
-
else
|
410
|
-
if uri = make_direct_link($2)
|
411
|
-
@tree.tag(:a, {href:uri}, $2)
|
412
|
-
else
|
413
|
-
@tree.add($&)
|
414
|
-
end
|
415
|
-
end
|
393
|
+
case
|
394
|
+
# raw url http://example.com/
|
395
|
+
when str =~ /\A(!)?((https?|ftps?):\/\/\S+?)(?=([\]\,.?!:;"'\)]+)?(\s|$))/
|
396
|
+
notlink, link = $1, $2
|
397
|
+
make_link(link, nil, link, 0, !!notlink)
|
416
398
|
# [[Image(pic.jpg|tag)]]
|
417
|
-
when /\A\[\[Image\(([^,]*?)(,(.*?))?\)\]\]/ # image
|
418
|
-
str = $'
|
399
|
+
when str =~ /\A\[\[Image\(([^,]*?)(,(.*?))?\)\]\]/ # image
|
419
400
|
make_image($1, $3)
|
420
401
|
# [[link]]
|
421
|
-
# [
|
422
|
-
when /\A \[ \s* ([^\[|]*?) \s* (\|\s*(.*?))? \s* \] /mx
|
423
|
-
|
424
|
-
link, content, whole
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
link, content, whole
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
@tree.
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
402
|
+
# [ link2 | text5 ]
|
403
|
+
when str =~ /\A (\[ \s* ([^\[|]*?) \s*) ((\|\s*)(.*?))? \s* \] /mx
|
404
|
+
link, content, content_offset, whole = $2, $5, $1.size + ($4||'').size, $&
|
405
|
+
make_link(link, content, "[#{whole}]",offset + content_offset)
|
406
|
+
# [[ link2 | text5 ]]
|
407
|
+
when str =~ /\A (\[\[ \s* ([^|]*?) \s*) ((\|\s*)(.*?))? \s* \]\] /mx
|
408
|
+
link, content, content_offset, whole= $2, $5, $1.size + ($4||'').size, $&
|
409
|
+
#print "link: #{content_offset} of:#{offset}, '#{$1}', '#{$4||''}'\n"
|
410
|
+
make_link(link, content, whole, offset + content_offset)
|
411
|
+
when allow_html? && str =~ /\A<(\/)?(\w+)(?:([^>]*?))?(\/\s*)?>/ # single inline <html> tag
|
412
|
+
eot, tag, args, closed = $1, $2, $3, $4
|
413
|
+
do_raw_tag(eot, tag, args, closed, $'.size)
|
414
|
+
when str =~ /\A\{\{\{(.*?\}*)\}\}\}/ # inline {{{ }}} pre (tt)
|
415
|
+
@tree.tag(:tt, $1)
|
416
|
+
when macros? && str =~ MACRO_BEG_REX # macro {{
|
417
|
+
mac, str, lines, offset = parse_macro($1, $', offset, $&.size)
|
418
|
+
parse_inline(mac.gsub(/\n/, ' '),0);
|
419
|
+
#print "MACRO.inline(#{$1}), next:#{str}"
|
420
|
+
#return str, offset
|
421
|
+
next
|
422
|
+
when str =~ /\A`(.*?)`/ # inline pre (tt)
|
423
|
+
@tree.tag(:tt, $1)
|
424
|
+
when math? && str =~ /\A\$(.+?)\$/ # inline math (tt)
|
425
|
+
@tree.tag(:span, {:class => 'math'}, $1)
|
426
|
+
@was_math = true
|
427
|
+
when str =~ /\A(\&\w*;)/ # html entity
|
428
|
+
#print "add html ent: #{$1}\n"
|
429
|
+
@tree.add_raw($1)
|
430
|
+
when str =~ /\A([:alpha:]|[:digit:])+/
|
431
|
+
@tree.add($&) # word
|
432
|
+
when str =~ /\A\s+/
|
433
|
+
@tree.add_spc
|
434
|
+
when str =~ /\A'''''/
|
435
|
+
toggle_tag 'strongem', $& # bolditallic
|
436
|
+
when str =~ /\A\*\*/ || str =~ /\A'''/
|
437
|
+
toggle_tag 'strong', $& # bold
|
438
|
+
when str =~ /\A''/ || str =~ /\A\/\//
|
439
|
+
toggle_tag 'em', $& # italic
|
440
|
+
when str =~ /\A\\\\/ || str =~ /\A\[\[br\]\]/i
|
441
|
+
@tree.tag(:br) # newline
|
442
|
+
when str =~ /\A__/
|
443
|
+
toggle_tag 'u', $& # underline
|
444
|
+
when str =~ /\A~~/
|
445
|
+
toggle_tag 'del', $& # delete
|
446
|
+
when str =~ /\A~/
|
447
|
+
@tree.add_raw(' ') # tilde
|
448
|
+
# when /\A\+\+/
|
449
|
+
# toggle_tag 'ins', $& # insert
|
450
|
+
when str =~ /\A\^/
|
451
|
+
toggle_tag 'sup', $& # ^{}
|
452
|
+
when str =~ /\A,,/
|
453
|
+
toggle_tag 'sub', $& # _{}
|
454
|
+
when str =~ /\A!(\{\{|[^\s])/
|
455
|
+
@tree.add($1) # !neco !{{
|
456
|
+
when str =~ /\A./
|
457
|
+
@tree.add($&) # ordinal char
|
461
458
|
end
|
462
|
-
|
463
|
-
|
464
|
-
end
|
465
|
-
@tree.tag_end(:a)
|
466
|
-
end
|
467
|
-
|
468
|
-
def parse_inline_tag(str)
|
469
|
-
case
|
470
|
-
when raw_html? && str =~ /\A<(\/)?(\w+)(?:([^>]*?))?(\/\s*)?>/ # single inline <html> tag
|
471
|
-
eot, tag, args, closed = $1, $2, $3, $4
|
472
|
-
do_raw_tag(eot, tag, args, closed, $'.size)
|
473
|
-
when str =~ /\A\{\{\{(.*?\}*)\}\}\}/ # inline {{{ }}} pre (tt)
|
474
|
-
@tree.tag(:tt, $1)
|
475
|
-
when str =~ MACRO_BEG_REX # macro {{
|
476
|
-
str, lines = parse_macro($1, $')
|
477
|
-
#print "MACRO.inline(#{$1}), next:#{str}"
|
478
|
-
return str
|
479
|
-
when str =~ /\A`(.*?)`/ # inline pre (tt)
|
480
|
-
@tree.tag(:tt, $1)
|
481
|
-
when math? && str =~ /\A\$(.+?)\$/ # inline math (tt)
|
482
|
-
#@tree.add("\\( #{$1} \\)")
|
483
|
-
@tree.tag(:span, {class:'math'}, $1)
|
484
|
-
@was_math = true
|
485
|
-
when str =~ /\A(\&\w*;)/ # html entity
|
486
|
-
#print "add html ent: #{$1}\n"
|
487
|
-
@tree.add_raw($1)
|
488
|
-
when str =~ /\A([:alpha:]|[:digit:])+/
|
489
|
-
@tree.add($&) # word
|
490
|
-
when str =~ /\A\s+/
|
491
|
-
@tree.add_spc
|
492
|
-
when str =~ /\A'''''/
|
493
|
-
toggle_tag 'strongem', $& # bolditallic
|
494
|
-
when str =~ /\A\*\*/ || str =~ /\A'''/
|
495
|
-
toggle_tag 'strong', $& # bold
|
496
|
-
when str =~ /\A''/ || str =~ /\A\/\//
|
497
|
-
toggle_tag 'em', $& # italic
|
498
|
-
when str =~ /\A\\\\/ || str =~ /\A\[\[br\]\]/i
|
499
|
-
@tree.tag(:br) # newline
|
500
|
-
when str =~ /\A__/
|
501
|
-
toggle_tag 'u', $& # underline
|
502
|
-
when str =~ /\A~~/
|
503
|
-
toggle_tag 'del', $& # delete
|
504
|
-
when str =~ /\A~/
|
505
|
-
@tree.add_raw(' ') # tilde
|
506
|
-
# when /\A\+\+/
|
507
|
-
# toggle_tag 'ins', $& # insert
|
508
|
-
when str =~ /\A\^/
|
509
|
-
toggle_tag 'sup', $& # ^{}
|
510
|
-
when str =~ /\A,,/
|
511
|
-
toggle_tag 'sub', $& # _{}
|
512
|
-
when str =~ /\A!(\{\{|[^\s])/
|
513
|
-
@tree.add($1) # !neco !{{
|
514
|
-
when str =~ /./
|
515
|
-
@tree.add($&) # ordinal char
|
459
|
+
str = $'
|
460
|
+
offset += $&.size
|
516
461
|
end
|
517
|
-
return
|
462
|
+
return offset
|
518
463
|
end
|
519
464
|
|
520
465
|
#################################################################
|
521
466
|
# macro {{ }}
|
522
467
|
# convetntion {{!cmd}} {{template}} {{$var}} {{# comment}} {{!}} (pipe)
|
523
468
|
|
524
|
-
# r: expanded macro
|
469
|
+
# r: expanded macro , rest of str, count lines taken from str
|
525
470
|
# sideefect: parse result of macro
|
526
|
-
def parse_macro(macro_name, str)
|
471
|
+
def parse_macro(macro_name, str, offset, macro_name_size)
|
472
|
+
raise "offset is nil" if offset.nil?
|
473
|
+
raise "offset is nil" if macro_name_size.nil?
|
527
474
|
@env = Env.new(self) if @env.nil?
|
475
|
+
@env.atput('offset', offset)
|
476
|
+
@env.atput('lineno', @line_no)
|
528
477
|
begin
|
529
|
-
mac_out, rest, lines = @env.parse_macro_all(macro_name, str)
|
478
|
+
mac_out, rest, lines, rest_offset = @env.parse_macro_all(macro_name, str, macro_name_size)
|
479
|
+
raise "lines is nil" if lines.nil?
|
530
480
|
#print "mac: '#{mac_out}' rest: '#{rest}'\n"
|
531
|
-
|
481
|
+
#print "mac: ro #{rest_offset}, of#{offset}, lines: #{lines} ms: #{macro_name_size} strlen#{str.size}, str'#{str}' rest:'#{rest}'\n"
|
482
|
+
rest_offset += offset + macro_name_size if lines == 0
|
483
|
+
#print "ro#{rest_offset}\n"
|
484
|
+
return mac_out, rest, lines, rest_offset
|
532
485
|
rescue TooLongException => e
|
533
|
-
return "TOO_LONG_EXPANSION_OF_MACRO(#{macro_name})QUIT", 0
|
486
|
+
return '', "TOO_LONG_EXPANSION_OF_MACRO(#{macro_name})QUIT", 0, 0
|
487
|
+
rescue Exception => e
|
488
|
+
#@tree.tag(:span, {:title => "#{e}\", :class=>'parse-error'}, "!!!")
|
489
|
+
@tree.tag(:span, {:title => "#{e}\n#{e.backtrace}", :class=>'parse-error'}, "!!!")
|
490
|
+
print "tace#{e.backtrace.to_s}\n"
|
491
|
+
return '', '', 0, 0
|
534
492
|
end
|
535
493
|
end
|
536
494
|
|
495
|
+
#################################################################
|
537
496
|
|
497
|
+
def make_link(link, content, whole, offset, not_make_link = false )
|
498
|
+
# was '!' before url?
|
499
|
+
return @tree.add(whole) if not_make_link
|
538
500
|
|
539
|
-
|
501
|
+
# specail "link" [[BR]]:
|
502
|
+
return @tree.tag(:br) if link =~ /^br$/i
|
540
503
|
|
504
|
+
uri = make_explicit_link(link)
|
505
|
+
return @tree.add(whole) if not uri
|
506
|
+
return @tree.add(whole) if no_link? && uri !~ /^(ftp|https?):/
|
507
|
+
|
508
|
+
@tree.tag_beg(:a, {href:uri})
|
509
|
+
if content
|
510
|
+
parse_inline(content, offset)
|
511
|
+
else
|
512
|
+
@tree.add(link)
|
513
|
+
end
|
514
|
+
@tree.tag_end(:a)
|
515
|
+
end
|
516
|
+
|
517
|
+
#################################################################
|
541
518
|
|
542
519
|
def parse_table_row(str)
|
520
|
+
offset = 0;
|
543
521
|
start_tag('tr') if !@stack.include?('tr')
|
544
522
|
str.sub!(/\r/, '')
|
545
523
|
colspan = 1
|
@@ -548,7 +526,8 @@ module TracWiki
|
|
548
526
|
last_txt = ''
|
549
527
|
str.scan(/(=?)(\s*)(.*?)\1?($ | \|\|\\\s*$ | \|\| )/x) do
|
550
528
|
tdth = $1.empty? ? 'td' : 'th'
|
551
|
-
|
529
|
+
tdth_size = $1.size
|
530
|
+
le, txt, tail, cell_size = $2.size, $3, $4, $&.size
|
552
531
|
|
553
532
|
# do not end row, continue on next line
|
554
533
|
print_tr = false if tail =~ /^\|\|\\/
|
@@ -571,19 +550,21 @@ module TracWiki
|
|
571
550
|
start_tag(tdth, { style:style, colspan: colspan});
|
572
551
|
colspan = 1
|
573
552
|
|
574
|
-
parse_inline(txt.strip) if txt
|
553
|
+
parse_inline(txt.strip, offset + tdth_size + le + 2) if txt
|
575
554
|
end_tag while @stack.last != 'tr'
|
555
|
+
offset += cell_size
|
576
556
|
end
|
577
557
|
if print_tr
|
578
558
|
end_tag
|
579
559
|
end
|
560
|
+
return offset
|
580
561
|
end
|
581
562
|
|
582
563
|
def make_nowikiblock(input)
|
583
564
|
input.gsub(/^ (?=\}\}\})/, '')
|
584
565
|
end
|
585
566
|
|
586
|
-
def parse_li_line(spc_size, bullet
|
567
|
+
def parse_li_line(spc_size, bullet)
|
587
568
|
|
588
569
|
while !@stacki.empty? && @stacki.last > spc_size
|
589
570
|
end_tag
|
@@ -623,7 +604,6 @@ module TracWiki
|
|
623
604
|
end
|
624
605
|
|
625
606
|
start_tag('li')
|
626
|
-
parse_inline(text)
|
627
607
|
|
628
608
|
end
|
629
609
|
|
@@ -698,12 +678,12 @@ module TracWiki
|
|
698
678
|
@tree.tag(:hr)
|
699
679
|
end
|
700
680
|
|
701
|
-
def do_heading(level, title, aname)
|
681
|
+
def do_heading(level, title, aname, title_offset)
|
702
682
|
aname= aname_nice(aname, title)
|
703
683
|
@headings.last[:eline] = @line_no - 1
|
704
684
|
@headings.push({ :title => title, :sline => @line_no, :aname => aname, :level => level, })
|
705
685
|
end_paragraph
|
706
|
-
make_headline(level, title, aname)
|
686
|
+
make_headline(level, title, aname, title_offset)
|
707
687
|
end
|
708
688
|
def do_table_row(text)
|
709
689
|
if !@stack.include?('table')
|
@@ -720,43 +700,48 @@ module TracWiki
|
|
720
700
|
start_tag('dd')
|
721
701
|
end
|
722
702
|
|
723
|
-
def do_citation(level
|
703
|
+
def do_citation(level)
|
724
704
|
start_paragraph if !@stack.include? 'p'
|
725
705
|
blockquote_level_to(level)
|
726
|
-
parse_inline(quote.strip)
|
727
706
|
end
|
728
707
|
|
729
|
-
def do_ord_line(spc_size
|
730
|
-
text.rstrip!
|
708
|
+
def do_ord_line(spc_size)
|
731
709
|
|
732
710
|
if @stack.include?('li') || @stack.include?('dl')
|
733
711
|
|
734
712
|
# dl, li continuation
|
735
|
-
parse_inline(' ')
|
736
|
-
parse_inline(text)
|
713
|
+
parse_inline(' ', 0)
|
737
714
|
|
738
715
|
elsif spc_size > 0
|
739
716
|
# quote continuation
|
740
717
|
start_paragraph if !@stack.include? 'p'
|
741
718
|
blockquote_level_to(1)
|
742
|
-
parse_inline(text)
|
743
719
|
|
744
720
|
else
|
745
721
|
# real ordinary line
|
746
722
|
start_paragraph
|
747
|
-
parse_inline(text)
|
748
723
|
end
|
749
724
|
end
|
750
725
|
|
751
|
-
def parse_block(str)
|
726
|
+
def parse_block(str, want_end_paragraph = true)
|
752
727
|
#print "BLOCK.str(#{str})\n"
|
753
728
|
until str.empty?
|
754
729
|
case
|
755
730
|
# macro
|
756
|
-
when str =~ MACRO_BEG_REX
|
757
|
-
str, lines = parse_macro($1, $')
|
758
|
-
|
759
|
-
|
731
|
+
when macros? && str =~ MACRO_BEG_REX
|
732
|
+
mac, str, lines, offset = parse_macro($1, $', 0, $&.size)
|
733
|
+
raise 'lines is nil' if lines.nil?
|
734
|
+
raise 'offset is nil' if offset.nil?
|
735
|
+
#print "MACRO.lines(#{$1})lines:#{lines}, str:'#{str}'\n"
|
736
|
+
add_line_no(lines)
|
737
|
+
@count_lines_level +=1
|
738
|
+
parse_block(mac, false)
|
739
|
+
@count_lines_level -=1
|
740
|
+
if mac.size > 0 && str =~ /^(.*)(\r?\n)?/
|
741
|
+
line, str = $1 , $'
|
742
|
+
add_line_no($&.count("\n"))
|
743
|
+
parse_inline(line, offset)
|
744
|
+
end
|
760
745
|
next
|
761
746
|
# display math $$
|
762
747
|
when math? && str =~ /\A\$\$(.*?)\$\$/m
|
@@ -772,8 +757,8 @@ module TracWiki
|
|
772
757
|
do_hr()
|
773
758
|
# heading == Wiki Ruless ==
|
774
759
|
# heading == Wiki Ruless == #tag
|
775
|
-
when str =~ /\A[[:blank:]]*(={1,6})\s*(.*?)\s*=*\s*(#(\S*))?\s*$(\r?\n)?/
|
776
|
-
do_heading($
|
760
|
+
when str =~ /\A([[:blank:]]*(={1,6})\s*)(.*?)\s*=*\s*(#(\S*))?\s*$(\r?\n)?/
|
761
|
+
do_heading($2.size, $3, $5, $1.size)
|
777
762
|
# table row ||
|
778
763
|
when str =~ /\A[ \t]*\|\|(.*)$(\r?\n)?/
|
779
764
|
do_table_row($1)
|
@@ -783,31 +768,32 @@ module TracWiki
|
|
783
768
|
when str =~ /\A([:\w\s]+)::(\s+|\r?\n)/
|
784
769
|
do_term($1)
|
785
770
|
# li
|
786
|
-
when str =~ /\A(\s*)([*-]|[aAIi\d]\.)\s+(.*?)$(\r?\n)?/
|
787
|
-
parse_li_line($
|
771
|
+
when str =~ /\A((\s*)([*-]|[aAIi\d]\.)\s+)(.*?)$(\r?\n)?/
|
772
|
+
parse_li_line($2.size, $3)
|
773
|
+
parse_inline($4, $1.size)
|
788
774
|
# citation
|
789
775
|
when str =~ /\A(>[>\s]*)(.*?)$(\r?\n)?/
|
790
|
-
do_citation($1.count('>')
|
776
|
+
do_citation($1.count('>'))
|
777
|
+
parse_inline($2, $1.size)
|
791
778
|
# ordinary line
|
792
779
|
when str =~ /\A(\s*)(\S+.*?)$(\r?\n)?/
|
793
|
-
|
780
|
+
text = $2
|
781
|
+
do_ord_line($1.size)
|
782
|
+
parse_inline(text.rstrip, $1.size)
|
794
783
|
else # case str
|
795
784
|
raise "Parse error at #{str[0,30].inspect}"
|
796
785
|
end
|
797
|
-
|
786
|
+
add_line_no(($`).count("\n")+($&).count("\n"))
|
798
787
|
str = $'
|
799
788
|
end
|
800
|
-
end_paragraph
|
789
|
+
end_paragraph if want_end_paragraph
|
801
790
|
@headings.last[:eline] = @line_no - 1
|
802
791
|
end
|
803
|
-
|
804
792
|
def aname_nice(aname, title)
|
805
793
|
|
806
794
|
if aname.nil? && id_from_heading?
|
807
795
|
aname = title.gsub /\s+/, '_'
|
808
|
-
if id_translit?
|
809
|
-
aname = Iconv.iconv('ascii//translit', 'utf-8', aname).join
|
810
|
-
end
|
796
|
+
aname = _translit(aname) if id_translit?
|
811
797
|
end
|
812
798
|
return nil if aname.nil?
|
813
799
|
aname_ori = aname
|
@@ -819,5 +805,13 @@ module TracWiki
|
|
819
805
|
@anames[aname] = true
|
820
806
|
aname
|
821
807
|
end
|
808
|
+
def _translit(text)
|
809
|
+
# iconv is obsolete, but translit funcionality was not replaced
|
810
|
+
# see http://stackoverflow.com/questions/20224915/iconv-will-be-deprecated-in-the-future-transliterate
|
811
|
+
# return Iconv.iconv('ascii//translit', 'utf-8', text).join
|
812
|
+
|
813
|
+
# http://unicode-utils.rubyforge.org/UnicodeUtils.html#method-c-compatibility_decomposition
|
814
|
+
return UnicodeUtils.compatibility_decomposition(text).chars.grep(/\p{^Mn}/).join('')
|
815
|
+
end
|
822
816
|
end
|
823
817
|
end
|