trac-wiki 0.2.16 → 0.2.20
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/trac-wiki.rb +1 -0
- data/lib/trac-wiki/env.rb +256 -0
- data/lib/trac-wiki/parser.rb +80 -95
- data/lib/trac-wiki/tree.rb +3 -1
- data/lib/trac-wiki/version.rb +1 -1
- data/test/parser_test.rb +89 -11
- metadata +3 -2
data/lib/trac-wiki.rb
CHANGED
@@ -0,0 +1,256 @@
|
|
1
|
+
module TracWiki
|
2
|
+
|
3
|
+
class Env
|
4
|
+
def initialize(parser, env = {})
|
5
|
+
@parser = parser
|
6
|
+
@env = env
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse_macro_all(macro_name, str)
|
10
|
+
#print "macro_all: #{macro_name}, str:#{str}.\n"
|
11
|
+
if macro_name =~ /\A!/
|
12
|
+
# {{!cmd}}
|
13
|
+
mac_out, rest, lines = parse_macro_cmd(macro_name, str)
|
14
|
+
else
|
15
|
+
# {{$cmd}}, {{template}}, ...
|
16
|
+
mac_out, rest, lines = parse_macro_vartempl(macro_name, str)
|
17
|
+
end
|
18
|
+
return mac_out || '', rest, lines
|
19
|
+
end
|
20
|
+
|
21
|
+
# read to args to }} (while balancing {{ and }})
|
22
|
+
# ret: (arg, rest, lines)
|
23
|
+
# mac_out -- string to }} (macros inside expanded)
|
24
|
+
# rest -- str aftrer }}
|
25
|
+
# lines -- howmany \n eaten from str (from begining to }})
|
26
|
+
def parse_macro_vartempl(macro_name, str)
|
27
|
+
str_orig = str
|
28
|
+
lines = 0
|
29
|
+
arg = ''
|
30
|
+
# FIXME: MACRO_REX
|
31
|
+
# prefix }}... {{macro_name
|
32
|
+
while str =~ TracWiki::Parser::MACRO_END_REX
|
33
|
+
prefix, bracket, sub_macro_name, str = $1, $2, $3, $'
|
34
|
+
arg << prefix
|
35
|
+
lines += prefix.count("\n")
|
36
|
+
if bracket == '}}'
|
37
|
+
#print "prefix: #{prefix}\n"
|
38
|
+
return do_macro_var($1, arg), str, lines if macro_name =~ /^\$(.*)/
|
39
|
+
return do_macro_templ(macro_name, arg), str, lines
|
40
|
+
end
|
41
|
+
|
42
|
+
# we need to go deeper!
|
43
|
+
mac_out, str, l = parse_macro_all(sub_macro_name, str)
|
44
|
+
arg << mac_out
|
45
|
+
lines += l
|
46
|
+
end
|
47
|
+
print "Error parsing macro(#{macro_name}) near '#{str}'(#{str_orig}) (arg:#{arg}, lines=#{lines})\n"
|
48
|
+
raise "Error parsing macro near '#{str}' (arg:#{arg}, lines=#{lines})"
|
49
|
+
end
|
50
|
+
|
51
|
+
# parse to next }} (with balanced {{..}})
|
52
|
+
# like parse_macro_vartempl but not expand content
|
53
|
+
# r: [expansion, rest_of_str, count_of_consumed_lines]
|
54
|
+
def parse_macro_cmd(macro_name, str)
|
55
|
+
str.sub!(/\A\s*\|?/, '')
|
56
|
+
return do_macro_cmd(macro_name, []), $', 0 if str =~ /\A}}/
|
57
|
+
#print "parse_macro_cmd: #{macro_name}, str#{str}\n"
|
58
|
+
dep = 0
|
59
|
+
lines = 0
|
60
|
+
args = ['']
|
61
|
+
while str =~ /{{|}}|\|/
|
62
|
+
prefix, match, str = $`, $&, $'
|
63
|
+
args[-1] += prefix
|
64
|
+
lines += prefix.count("\n")
|
65
|
+
if match == '{{'
|
66
|
+
dep += 1
|
67
|
+
args[-1] += $&
|
68
|
+
elsif match == '}}'
|
69
|
+
dep -= 1
|
70
|
+
return do_macro_cmd(macro_name, args), str, lines if dep < 0
|
71
|
+
args[-1] += $&
|
72
|
+
elsif match == '|' && dep == 0
|
73
|
+
args.push('')
|
74
|
+
else
|
75
|
+
args[-1] += $&
|
76
|
+
end
|
77
|
+
end
|
78
|
+
raise "eol in parsing macro params"
|
79
|
+
end
|
80
|
+
|
81
|
+
# calls {{!cmd}} (if exists
|
82
|
+
# r: result of {{!cmd}}
|
83
|
+
def do_macro_cmd(macro_name, args)
|
84
|
+
return '|' if macro_name == '!'
|
85
|
+
if @parser.plugins.key?(macro_name)
|
86
|
+
@env['args'] = args
|
87
|
+
@env['arg0'] = macro_name
|
88
|
+
#print "mac: #{macro_name} env:" ; pp (@env)
|
89
|
+
ret = @parser.plugins[macro_name].call(self)
|
90
|
+
return ret
|
91
|
+
end
|
92
|
+
"UCMD(#{macro_name}|#{@env['arg']})"
|
93
|
+
end
|
94
|
+
def arg(idx)
|
95
|
+
@env['args'][idx] || ''
|
96
|
+
end
|
97
|
+
|
98
|
+
def prepare_y
|
99
|
+
#print "prepare_y\n"
|
100
|
+
return if @env.key? 'y'
|
101
|
+
arg = @env['arg']
|
102
|
+
return if arg.nil?
|
103
|
+
begin
|
104
|
+
@env['y'] = YAML.load(arg)
|
105
|
+
#print "y"
|
106
|
+
#pp @env['y']
|
107
|
+
rescue
|
108
|
+
@env['y'] = nil
|
109
|
+
#print "y:nil\n"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def at(key, default = nil, to_str = true)
|
114
|
+
#print "at(#{key}), env:"
|
115
|
+
#pp @env
|
116
|
+
return @env[key] || default if key.is_a? Symbol
|
117
|
+
prepare_y if key =~ /^y\./
|
118
|
+
cur = @env
|
119
|
+
key.split(/\./).each do |subkey|
|
120
|
+
subkey = at($1, '') if subkey =~ /\A\$(.*)/
|
121
|
+
#print "at:subkey: #{subkey}\n"
|
122
|
+
if cur.is_a? Hash
|
123
|
+
cur = cur[subkey]
|
124
|
+
elsif cur.is_a? Array
|
125
|
+
cur = cur[subkey.to_i]
|
126
|
+
else
|
127
|
+
#print "at(#{key})->: default"
|
128
|
+
return default
|
129
|
+
end
|
130
|
+
#print "at(#{key}) -> default\n" if cur.nil?
|
131
|
+
return default if cur.nil?
|
132
|
+
end
|
133
|
+
#print "at(#{key})->#{cur}\n"
|
134
|
+
to_str ? cur.to_s : cur
|
135
|
+
end
|
136
|
+
def atput(key, val = nil)
|
137
|
+
#print "atput: #{key}, #{val} env:"
|
138
|
+
#pp @env
|
139
|
+
cur = @env
|
140
|
+
if val.is_a? Symbol
|
141
|
+
@env[key] = val
|
142
|
+
return
|
143
|
+
end
|
144
|
+
keys = key.split(/\./)
|
145
|
+
lastkey = keys.pop
|
146
|
+
keys.each do |subkey|
|
147
|
+
if cur.is_a? Hash
|
148
|
+
cur = cur[subkey]
|
149
|
+
elsif cur.is_a? Array
|
150
|
+
cur = cur[subkey.to_i]
|
151
|
+
else
|
152
|
+
return
|
153
|
+
end
|
154
|
+
end
|
155
|
+
if cur.is_a? Hash
|
156
|
+
cur[lastkey] = val
|
157
|
+
elsif cur.is_a? Array
|
158
|
+
cur[lastkey.to_i] = val
|
159
|
+
end
|
160
|
+
#print "atput:env:"
|
161
|
+
#pp @env
|
162
|
+
end
|
163
|
+
|
164
|
+
def [](key)
|
165
|
+
at(key)
|
166
|
+
end
|
167
|
+
|
168
|
+
def []=(key,val)
|
169
|
+
#print "set #{key} to #{val}\n"
|
170
|
+
atput(key,val)
|
171
|
+
end
|
172
|
+
|
173
|
+
# expand macro `macro_name` with `args`
|
174
|
+
# afer expansion all {{macros}} will be expanded recursively
|
175
|
+
# r: expanded string
|
176
|
+
def do_macro_templ(macro_name, arg)
|
177
|
+
return "!{{toc}}" if macro_name == 'toc'
|
178
|
+
return arg.strip if macro_name == '#echo'
|
179
|
+
return '' if macro_name == '#'
|
180
|
+
|
181
|
+
env = do_macro_arg_to_env(arg, @env[:depth])
|
182
|
+
|
183
|
+
#print "templ:#{macro_name}env:"
|
184
|
+
#pp(env)
|
185
|
+
|
186
|
+
if ! @parser.template_handler.nil?
|
187
|
+
str = @parser.template_handler.call(macro_name, env)
|
188
|
+
if !str.nil?
|
189
|
+
#print "dep:#{env[:depth]}(#{macro_name}, #{str})\n"
|
190
|
+
if env[:depth] > 32
|
191
|
+
return "TOO_DEEP_RECURSION(`#{str}`)\n"
|
192
|
+
#return "TOO_DEEP_RECURSION"
|
193
|
+
end
|
194
|
+
# FIXME: melo by nahlasit jestli to chce expandovat | wiki expadnovat |raw html
|
195
|
+
#print "temp(#{macro_name}) --> : #{str}\n"
|
196
|
+
#print "bf ex: [#{str}]\n"
|
197
|
+
str = env.expand(str)
|
198
|
+
#print "af ex: [#{str}]\n"
|
199
|
+
return str
|
200
|
+
end
|
201
|
+
end
|
202
|
+
#print "UMACRO(#{macro_name}|#{arg})\n"
|
203
|
+
"UMACRO(#{macro_name}|#{arg})"
|
204
|
+
end
|
205
|
+
|
206
|
+
def do_macro_arg_to_env(arg, depth)
|
207
|
+
arg.sub!(/\A\s*\|?/, '')
|
208
|
+
env = { 'arg' => arg , depth: (depth||0) + 1 }
|
209
|
+
idx = 1
|
210
|
+
arg.split(/\|/).each do |val|
|
211
|
+
if val =~ /\A\s*(\w+)\s*=\s*(.*)/s
|
212
|
+
env[$1] = $2
|
213
|
+
else
|
214
|
+
env[idx.to_s] = val
|
215
|
+
idx+=1
|
216
|
+
end
|
217
|
+
end
|
218
|
+
return Env.new(@parser, env)
|
219
|
+
end
|
220
|
+
|
221
|
+
def do_macro_var(var_name, arg)
|
222
|
+
#print "var(#{var_name})env:"
|
223
|
+
#pp(@env)
|
224
|
+
ret = at(var_name, nil)
|
225
|
+
return ret if !ret.nil?
|
226
|
+
return arg.sub(/\A\s*\|?/, '') if arg
|
227
|
+
"UVAR(#{macro_name}|#{@env['arg']})"
|
228
|
+
end
|
229
|
+
|
230
|
+
# template expand
|
231
|
+
def expand_arg(idx)
|
232
|
+
expand(@env['args'][idx])
|
233
|
+
end
|
234
|
+
|
235
|
+
def pp_env
|
236
|
+
pp(@env)
|
237
|
+
end
|
238
|
+
def expand(str)
|
239
|
+
ret = ''
|
240
|
+
return '' if str.nil?
|
241
|
+
while str =~ TracWiki::Parser::MACRO_BEG_INSIDE_REX
|
242
|
+
prefix, macro_name2, str = $1, $2, $'
|
243
|
+
ret << prefix
|
244
|
+
# FIXME if macro_name2 =~ /^!/
|
245
|
+
mac_out, str, lines = parse_macro_all(macro_name2, str)
|
246
|
+
ret << mac_out
|
247
|
+
#print "Too long macro expadion" if ret.size > 1_000_000
|
248
|
+
raise TooLongException if ret.size > 1_000_000
|
249
|
+
end
|
250
|
+
#print "text: #{text.nil?}\n"
|
251
|
+
#print "ret: #{ret.nil?}\n"
|
252
|
+
return ret + str
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
data/lib/trac-wiki/parser.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'cgi'
|
2
2
|
require 'uri'
|
3
3
|
require 'iconv'
|
4
|
+
require 'yaml'
|
4
5
|
|
5
6
|
# :main: TracWiki
|
6
7
|
|
@@ -38,6 +39,9 @@ require 'iconv'
|
|
38
39
|
# Inherit this to provide custom handling of links. The overrideable
|
39
40
|
# methods are: make_local_link
|
40
41
|
module TracWiki
|
42
|
+
class TooLongException < Exception
|
43
|
+
end
|
44
|
+
|
41
45
|
class Parser
|
42
46
|
|
43
47
|
# Allowed url schemes
|
@@ -85,18 +89,23 @@ module TracWiki
|
|
85
89
|
|
86
90
|
# when id_from_heading, non ascii char are transliterated to ascii
|
87
91
|
attr_writer :id_translit
|
92
|
+
attr_accessor :plugins
|
93
|
+
@plugins = {}
|
88
94
|
|
89
95
|
# string begins with macro
|
90
|
-
MACRO_BEG_REX = /\A\{\{ ( [
|
91
|
-
MACRO_BEG_INSIDE_REX =
|
96
|
+
MACRO_BEG_REX = /\A\{\{ ( \$[\$\.\w]+ | [\#!]\w* |\w+ ) /x
|
97
|
+
MACRO_BEG_INSIDE_REX = /\A(.*?)(?<!\{)\{\{ ( \$[\$\.\w]+ | [\#!]\w* | \w+ ) /xm
|
92
98
|
# find end of marcro or begin of inner macro
|
93
|
-
MACRO_END_REX = /\A(.*?) ( \}\} | \{\{ (
|
99
|
+
MACRO_END_REX = /\A(.*?) ( \}\} | \{\{ ( \$[\$\.\w]+ | [\#!]\w* | \w+) )/mx
|
94
100
|
def id_translit?; @id_translit; end
|
95
101
|
|
96
102
|
# Create a new Parser instance.
|
97
103
|
def initialize(text, options = {})
|
104
|
+
init_plugins
|
98
105
|
@allowed_schemes = %w(http https ftp ftps)
|
99
106
|
@anames = {}
|
107
|
+
plugins = options.delete :plugins
|
108
|
+
@plugins.merge! plugins if ! plugins.nil?
|
100
109
|
@text = text
|
101
110
|
@no_escape = nil
|
102
111
|
@base = ''
|
@@ -104,8 +113,47 @@ module TracWiki
|
|
104
113
|
@base += '/' if !@base.empty? && @base[-1] != '/'
|
105
114
|
end
|
106
115
|
|
116
|
+
def init_plugins
|
117
|
+
@plugins = {
|
118
|
+
'!ifeq' => proc { |env| env.expand_arg(0) == env.expand_arg(1) ? env.expand_arg(2) : env.expand_arg(3) },
|
119
|
+
'!ifdef' => proc { |env| env.at(env.expand_arg(0), nil, false).nil? ? env.expand_arg(2) : env.expand_arg(1) },
|
120
|
+
'!set' => proc { |env| env[env.expand_arg(0)] = env.expand_arg(1); '' },
|
121
|
+
'!yset' => proc { |env| env[env.expand_arg(0)] = YAML.load(env.arg(1)); '' },
|
122
|
+
|
123
|
+
'!html' => proc { |env| "\n{{{!\n#{env.arg(0)}\n}}}\n" },
|
124
|
+
'!sub' => proc { |env| pat = env.expand_arg(1)
|
125
|
+
pat = Regexp.new(pat[1..-2]) if pat =~ /\A\/.*\/\Z/
|
126
|
+
env.expand_arg(0).gsub(pat, env.expand_arg(2))
|
127
|
+
},
|
128
|
+
'!for' => proc { |env| i_name = env.arg(0)
|
129
|
+
top = env.arg(1)
|
130
|
+
tmpl = env.arg(2)
|
131
|
+
#print "top#{top}\n"
|
132
|
+
if top =~ /^\d+/
|
133
|
+
set = (0..(top.to_i-1))
|
134
|
+
else
|
135
|
+
set = env.at(top, nil, false)
|
136
|
+
if set.is_a?(Hash)
|
137
|
+
set = set.keys.sort
|
138
|
+
elsif set.is_a?(Array)
|
139
|
+
set = (0 .. set.size-1)
|
140
|
+
else
|
141
|
+
print "error top(#{top}), set#{set} #{set.class}\n"
|
142
|
+
env.pp_env
|
143
|
+
raise "Error in {{!for #{i_name}|#{top}|#{tmpl}}}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
set.map do |i|
|
147
|
+
env[i_name] = i.to_s
|
148
|
+
env.expand(tmpl)
|
149
|
+
end.join('')
|
150
|
+
},
|
151
|
+
}
|
152
|
+
|
153
|
+
end
|
154
|
+
|
107
155
|
# th(macroname) -> template_text
|
108
|
-
|
156
|
+
attr_accessor :template_handler
|
109
157
|
|
110
158
|
@was_math = false
|
111
159
|
def was_math?; @was_math; end
|
@@ -138,6 +186,12 @@ module TracWiki
|
|
138
186
|
@tree.to_html
|
139
187
|
end
|
140
188
|
|
189
|
+
def add_plugin(name, &block)
|
190
|
+
@plugins[name] = block
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
|
141
195
|
protected
|
142
196
|
|
143
197
|
# Escape any characters with special meaning in HTML using HTML
|
@@ -407,11 +461,13 @@ module TracWiki
|
|
407
461
|
|
408
462
|
def parse_inline_tag(str)
|
409
463
|
case
|
410
|
-
when str =~ /\A\{\{\{(.*?\}*)\}\}\}/ # inline
|
464
|
+
when raw_html? && str =~ /\A\{\{\{!(.*?\}*)\}\}\}/ # inline {{{! raw html }}}
|
465
|
+
do_raw_html($1, true)
|
466
|
+
when str =~ /\A\{\{\{(.*?\}*)\}\}\}/ # inline {{{ }}} pre (tt)
|
411
467
|
@tree.tag(:tt, $1)
|
412
468
|
when str =~ MACRO_BEG_REX # macro {{
|
413
469
|
str, lines = parse_macro($1, $')
|
414
|
-
#print "MACRO.inline(#{$1})"
|
470
|
+
#print "MACRO.inline(#{$1}), next:#{str}"
|
415
471
|
return str
|
416
472
|
when str =~ /\A`(.*?)`/ # inline pre (tt)
|
417
473
|
@tree.tag(:tt, $1)
|
@@ -421,7 +477,7 @@ module TracWiki
|
|
421
477
|
#@tree.tag(:span, {class:'math'}, $1)
|
422
478
|
@was_math = true
|
423
479
|
when str =~ /\A(\&\w*;)/ # html entity
|
424
|
-
print "add html ent: #{$1}\n"
|
480
|
+
#print "add html ent: #{$1}\n"
|
425
481
|
@tree.add_raw($1)
|
426
482
|
when str =~ /\A([:alpha:]|[:digit:])+/
|
427
483
|
@tree.add($&) # word
|
@@ -455,103 +511,31 @@ module TracWiki
|
|
455
511
|
return $'
|
456
512
|
end
|
457
513
|
|
514
|
+
#################################################################
|
515
|
+
# macro {{ }}
|
516
|
+
# convetntion {{!cmd}} {{template}} {{$var}} {{# comment}} {{!}} (pipe)
|
517
|
+
|
458
518
|
# r: expanded macro + rest of str, count lines taken from str
|
459
519
|
# sideefect: parse result of macro
|
460
520
|
def parse_macro(macro_name, str)
|
521
|
+
@env = Env.new(self) if @env.nil?
|
461
522
|
begin
|
462
|
-
mac_out, rest, lines =
|
463
|
-
#
|
464
|
-
#@tree.add(mac)
|
465
|
-
#print "MACOUT:'#{mac_out}'\n"
|
523
|
+
mac_out, rest, lines = @env.parse_macro_all(macro_name, str)
|
524
|
+
#print "mac: '#{mac_out}' rest: '#{rest}'\n"
|
466
525
|
return mac_out + rest, lines
|
467
|
-
rescue
|
468
|
-
return "TOO_LONG_EXPANSION_OF_MACRO(#{macro_name})QUIT"
|
469
|
-
end
|
470
|
-
end
|
471
|
-
|
472
|
-
# read to args to }} (while balancing {{ and }})
|
473
|
-
# ret: (arg, rest, lines)
|
474
|
-
# mac_out -- string to }} (macros inside expanded)
|
475
|
-
# rest -- str aftrer }}
|
476
|
-
# lines -- howmany \n eaten from str (from begining to }})
|
477
|
-
def parse_macro_arg(macro_name, str, env)
|
478
|
-
|
479
|
-
lines = 0
|
480
|
-
arg = ''
|
481
|
-
# FIXME: MACRO_REX
|
482
|
-
# prefix }}... {{macro_name
|
483
|
-
while str =~ MACRO_END_REX
|
484
|
-
prefix, bracket, sub_macro_name, str = $1, $2, $3, $'
|
485
|
-
arg << prefix
|
486
|
-
lines += prefix.count("\n")
|
487
|
-
if bracket == '}}'
|
488
|
-
#print "prefix: #{prefix}\n"
|
489
|
-
env = do_macro_arg_to_env(arg, env[:depth])
|
490
|
-
return do_macro(macro_name, env), str, lines
|
491
|
-
end
|
492
|
-
|
493
|
-
# we need to go deeper!
|
494
|
-
mac_out, str, l = parse_macro_arg(sub_macro_name, str, env)
|
495
|
-
arg << mac_out
|
496
|
-
lines += l
|
526
|
+
rescue TooLongException => e
|
527
|
+
return "TOO_LONG_EXPANSION_OF_MACRO(#{macro_name})QUIT", 0
|
497
528
|
end
|
498
|
-
raise "Error parsing macro near '#{str}' (arg:#{arg}, lines=#{lines})"
|
499
529
|
end
|
500
530
|
|
501
|
-
# expand macro `macro_name` with `args`
|
502
|
-
# afer expansion all {{macros}} will be expanded recursively
|
503
|
-
# r: expanded string
|
504
|
-
def do_macro(macro_name, env)
|
505
|
-
return "!{{toc}}" if macro_name == 'toc'
|
506
|
-
return env[:arg].strip if macro_name == '#echo'
|
507
|
-
return '' if macro_name == '#'
|
508
531
|
|
509
|
-
return do_macro_var(macro_name, env) if macro_name =~ /^\$/
|
510
532
|
|
511
|
-
|
512
|
-
if ! @template_handler.nil?
|
513
|
-
text = @template_handler.call(macro_name, env)
|
514
|
-
if !text.nil?
|
515
|
-
#print "dep:#{env[:depth]}(#{macro_name}, #{text})\n"
|
516
|
-
if env[:depth] > 32
|
517
|
-
return "TOO_DEEP_RECURSION(`#{text}`)\n"
|
518
|
-
#return "TOO_DEEP_RECURSION"
|
519
|
-
end
|
520
|
-
# FIXME: melo by nahlasit jestli to chce expandovat | wiki expadnovat |raw html
|
521
|
-
#print "temp(#{macro_name}) --> : #{text}\n"
|
522
|
-
text = do_macro_expand_result(text, env)
|
523
|
-
#print "af expand:#{text}\n"
|
524
|
-
|
525
|
-
return text
|
526
|
-
end
|
527
|
-
end
|
528
|
-
"UMACRO(#{macro_name}#{env[:arg]})"
|
529
|
-
end
|
530
|
-
|
531
|
-
def do_macro_var(macro_name, env)
|
532
|
-
"VAR(#{macro_name})"
|
533
|
-
end
|
534
|
-
|
535
|
-
def do_macro_arg_to_env(arg, depth)
|
536
|
-
{ arg: arg , depth: (depth||0) + 1 }
|
537
|
-
end
|
538
|
-
|
539
|
-
# template expand
|
540
|
-
def do_macro_expand_result(text, env)
|
541
|
-
ret = ''
|
542
|
-
while text =~ MACRO_BEG_INSIDE_REX
|
543
|
-
prefix, macro_name2, text = $1, $2, $'
|
544
|
-
ret << prefix
|
545
|
-
mac_out, text, lines = parse_macro_arg(macro_name2, text, env)
|
546
|
-
ret << mac_out
|
547
|
-
raise "Too long macro expadion" if ret.size > 1_000_000
|
548
|
-
end
|
549
|
-
return ret + text
|
550
|
-
end
|
533
|
+
#################################################################
|
551
534
|
|
552
535
|
|
553
536
|
def parse_table_row(str)
|
554
537
|
start_tag('tr') if !@stack.include?('tr')
|
538
|
+
str.sub!(/\r/, '')
|
555
539
|
colspan = 1
|
556
540
|
print_tr = true
|
557
541
|
last_tail = ''
|
@@ -674,8 +658,8 @@ module TracWiki
|
|
674
658
|
@tree.tag(:pre, nowikiblock)
|
675
659
|
end
|
676
660
|
|
677
|
-
def do_raw_html(text)
|
678
|
-
end_paragraph
|
661
|
+
def do_raw_html(text, inline=false)
|
662
|
+
end_paragraph if !inline
|
679
663
|
@tree.add_raw(text)
|
680
664
|
end
|
681
665
|
|
@@ -741,7 +725,8 @@ module TracWiki
|
|
741
725
|
# macro
|
742
726
|
when str =~ MACRO_BEG_REX
|
743
727
|
str, lines = parse_macro($1, $')
|
744
|
-
#print "MACRO.block(#{$1})\n"
|
728
|
+
#print "MACRO.block(#{$1})next:#{str}\n"
|
729
|
+
@line_no += lines
|
745
730
|
next
|
746
731
|
# display math $$
|
747
732
|
when math? && str =~ /\A\$\$(.*?)\$\$/m
|
@@ -778,7 +763,7 @@ module TracWiki
|
|
778
763
|
do_citation($1.count('>'), $2)
|
779
764
|
# ordinary line
|
780
765
|
when str =~ /\A(\s*)(\S+.*?)$(\r?\n)?/
|
781
|
-
do_ord_line($1.size, $2)
|
766
|
+
do_ord_line($1.size, $2)
|
782
767
|
else # case str
|
783
768
|
raise "Parse error at #{str[0,30].inspect}"
|
784
769
|
end
|
@@ -786,7 +771,7 @@ module TracWiki
|
|
786
771
|
str = $'
|
787
772
|
end
|
788
773
|
end_paragraph
|
789
|
-
@headings.last[:eline] = @line_no - 1
|
774
|
+
@headings.last[:eline] = @line_no - 1
|
790
775
|
end
|
791
776
|
|
792
777
|
def aname_nice(aname, title)
|
data/lib/trac-wiki/tree.rb
CHANGED
@@ -145,9 +145,11 @@ module TracWiki
|
|
145
145
|
|
146
146
|
def san_conf
|
147
147
|
return @san_conf if @san_conf
|
148
|
-
conf = { elements: ['form', 'input'],
|
148
|
+
conf = { elements: ['form', 'input', 'span', 'div'],
|
149
149
|
attributes: { 'form' => ['action', 'meth'],
|
150
150
|
'input' => ['type', 'value'],
|
151
|
+
'span' => ['class'],
|
152
|
+
'div' => ['class'],
|
151
153
|
},
|
152
154
|
}
|
153
155
|
|
data/lib/trac-wiki/version.rb
CHANGED
data/test/parser_test.rb
CHANGED
@@ -5,13 +5,26 @@ require 'pp'
|
|
5
5
|
|
6
6
|
class Bacon::Context
|
7
7
|
def tc(html, wiki, options = {})
|
8
|
-
|
8
|
+
options[:plugins] = { '!print' => proc { |env| env.arg(0) + '! ' },
|
9
|
+
}
|
9
10
|
options[:template_handler] = self.method(:template_handler)
|
10
|
-
|
11
|
+
|
12
|
+
parser = TracWiki.parser(wiki, options)
|
13
|
+
parser.to_html.should.equal html
|
11
14
|
end
|
12
15
|
|
13
16
|
def template_handler(tname, env)
|
14
17
|
case tname
|
18
|
+
when 'ifeqtest'
|
19
|
+
"{{!ifeq {{$1}}|{{$2}}|TRUE|FALSE}}"
|
20
|
+
when 'vartest2'
|
21
|
+
"{{vartest {{$1}}|{{$dva}}|p={{$p}}|{{$3 |tridef}}}}"
|
22
|
+
when 'ytest'
|
23
|
+
"{{$y.ahoj}},{{$y.bhoj.1}}"
|
24
|
+
when 'ytest2'
|
25
|
+
"{{!set i|ahoj}}{{$y.$i}},{{$y.bhoj.1}}"
|
26
|
+
when 'vartest'
|
27
|
+
"jedna:{{$1}},dve:{{$2}},p:{{$p}},arg:{{$arg}}"
|
15
28
|
when 'test'
|
16
29
|
"{{west}}"
|
17
30
|
when 'west'
|
@@ -20,6 +33,8 @@ class Bacon::Context
|
|
20
33
|
"{{deep}}"
|
21
34
|
when 'wide'
|
22
35
|
"0123456789{{wide}}" * 10
|
36
|
+
when 'fortest'
|
37
|
+
"{{$y.data.a}},({{!for i|y.data|AHOJ({{$i}})\n{{$y.data.$i}};\n}}),{{$y.data.a}}"
|
23
38
|
else
|
24
39
|
nil
|
25
40
|
#"UNK_TEMPL(#{tname})"
|
@@ -574,6 +589,8 @@ describe TracWiki::Parser do
|
|
574
589
|
|
575
590
|
it 'should parse table' do
|
576
591
|
tc "<table><tr><td>Hello</td><td>World!</td></tr></table>", "||Hello||World!||"
|
592
|
+
tc "<table><tr><td>Hello</td><td>World!</td></tr><tr><td>Hello</td><td>World!</td></tr></table>", "||Hello||World!||\n||Hello||World!||\n\n"
|
593
|
+
tc "<table><tr><td>Hello</td><td>World!</td></tr><tr><td>Hello</td><td>World!</td></tr></table>", "||Hello||World!||\r\n||Hello||World!||\r\n\n"
|
577
594
|
tc "<table><tr><td>Hello</td><td>World!</td></tr></table>", "||Hello||\\\n||World!||"
|
578
595
|
tc "<table><tr><td>He</td><td>llo</td><td>World!</td></tr></table>", "||He||llo||\\\n||World!||"
|
579
596
|
tc "<table><tr><td>Hello</td><td colspan=\"2\">World!</td></tr></table>", "||Hello||||World!||"
|
@@ -893,12 +910,12 @@ eos
|
|
893
910
|
|
894
911
|
tc "<h1>h1</h1>" , "{{# co{{HUU}}mment }}\n\n\n= h1 =\n{{# Comment2}}\n"
|
895
912
|
|
896
|
-
tc "<p>UMACRO(macr
|
897
|
-
tc "<p>ahoj UMACRO(
|
898
|
-
tc "<p>ahoj UMACRO(macro)</p>\n" , "ahoj {{macro}}"
|
899
|
-
tc "<p>ahoj {{%macrUMACRO(o)}}</p>\n" , "ahoj {{%macr{{o}}}}"
|
900
|
-
tc "<p>ahoj UMACRO(
|
901
|
-
tc "<p>ahoj
|
913
|
+
tc "<p>UMACRO(macr|ahoj )</p>\n" , "{{macr\nahoj\n}}"
|
914
|
+
tc "<p>ahoj UMACRO(macr|UMACRO(o|))</p>\n" , "ahoj {{macr{{o}}}}"
|
915
|
+
tc "<p>ahoj UMACRO(macro|)</p>\n" , "ahoj {{macro}}"
|
916
|
+
tc "<p>ahoj {{%macrUMACRO(o|)}}</p>\n" , "ahoj {{%macr{{o}}}}"
|
917
|
+
tc "<p>ahoj UMACRO(macr|UMACRO(mac|<strong>o</strong>))</p>\n" , "ahoj {{macr{{mac **o**}}}}"
|
918
|
+
tc "<p>ahoj ahoj</p>\n" , "ahoj {{$mac|ahoj}}"
|
902
919
|
end
|
903
920
|
|
904
921
|
it 'should do temlate' do
|
@@ -908,23 +925,84 @@ eos
|
|
908
925
|
# macro errors:
|
909
926
|
tc "<p>TOO_DEEP_RECURSION(<tt>{{deep}}</tt>) 3</p>\n", "{{deep}}3"
|
910
927
|
tc "<p>TOO_LONG_EXPANSION_OF_MACRO(wide)QUIT</p>\n", "{{wide}}3"
|
911
|
-
tc "<p>UMACRO(unknown)3</p>\n", "{{unknown}}3"
|
928
|
+
tc "<p>UMACRO(unknown|)3</p>\n", "{{unknown}}3"
|
929
|
+
end
|
930
|
+
it 'should do temlate with args' do
|
931
|
+
tc "<p>jedna:VARTESTPARAM,dve:,p:DVE,arg:VARTESTPARAM|p=DVE</p>\n", "{{vartest VARTESTPARAM|p=DVE}}"
|
932
|
+
tc "<p>jedna:VARTESTPARAM,dve:TRI,p:DVE,arg:VARTESTPARAM|p=DVE|TRI</p>\n", "{{vartest VARTESTPARAM|p=DVE|TRI}}"
|
933
|
+
tc "<p>jedna:VARTESTPARAM,dve:TRI,p:DVE,arg:VARTESTPARAM|TRI|p=DVE|tridef</p>\n", "{{vartest2 VARTESTPARAM|p=DVE|dva=TRI}}"
|
934
|
+
tc "<p>ahoj |</p>\n", "ahoj {{!}}"
|
935
|
+
#FIXME: should be: '... jedna:be||no to be,dve: ..'
|
936
|
+
tc "<p>jedna:be,dve:,p:,arg:be||not to be</p>\n", "{{vartest be{{!}}{{!}}not to be}}"
|
912
937
|
end
|
913
938
|
it 'should support options' do
|
914
939
|
tc "<h3>h1<a class=\"editheading\" href=\"?edit=1\">edit</a></h3>", "=== h1 ==", edit_heading: true
|
915
940
|
end
|
916
941
|
it 'should not html' do
|
917
|
-
tc "<p>{{{! <a></a> }}}</p>\n", "{{{!\n<a></a>\n}}}\n"
|
942
|
+
#tc "<p>{{{! <a></a> }}}</p>\n", "{{{!\n<a></a>\n}}}\n"
|
918
943
|
tc '<a></a>', "{{{!\n<a></a>\n}}}\n", raw_html: true
|
919
944
|
tc '<a></a>', "{{{!\n<a></a>\n}}}\n", raw_html: true
|
920
945
|
tc "<form meth=\"POST\" action=\"http://www.example.com\"><input type=\"hidden\" value=\"VAL\"></form>",
|
921
946
|
"{{{!\n<form meth=\"POST\" action=\"http://www.example.com\"><input type=\"hidden\" value=\"VAL\"/></form>\n}}}\n", raw_html: true
|
922
947
|
tc 'alert(444);', "{{{!\n<script>alert(444);</script>\n}}}\n", raw_html: true
|
923
948
|
end
|
924
|
-
it 'should
|
949
|
+
it 'should entity' do
|
925
950
|
tc "<p>\u00a0</p>\n", " "
|
926
951
|
tc "<p>„text“</p>\n", "„text“"
|
927
952
|
end
|
953
|
+
it 'should plugin' do
|
954
|
+
tc "<p>AHOJTE!</p>\n", "{{!print AHOJTE}}"
|
955
|
+
tc "<p>test:AHOJTE! AHOJTE! </p>\n", "test:{{!print AHOJTE}}{{!print AHOJTE}}"
|
956
|
+
tc "<p>FALSE</p>\n", "{{ifeqtest JEDNA|DVE}}"
|
957
|
+
tc "<p>TRUE</p>\n", "{{ifeqtest JEDNA|JEDNA}}"
|
958
|
+
tc "<p>AHOJ</p>\n", "{{!set ahoj|AHOJ}}{{$ahoj}}"
|
959
|
+
tc "<p>BHOJ</p>\n", "{{!ifeq a|b|{{!set ahoj|AHOJ}}|{{!set ahoj|BHOJ}}}}{{$ahoj}}"
|
960
|
+
tc "<p>AHOJ</p>\n", "{{!ifeq a|a|{{!set ahoj|AHOJ}}|{{!set ahoj|BHOJ}}}}{{$ahoj}}"
|
961
|
+
tc "<p>TRUE</p>\n", "{{!set a|a}}{{!ifeq {{$a}}|a|TRUE|FALSE}}"
|
962
|
+
tc "<p>FALSE</p>\n", "{{!set a|a}}{{!ifeq {{$a}}|b|TRUE|FALSE}}"
|
963
|
+
tc "<p>,AHOJ! ,FALSE</p>\n", "{{!set a|a}},{{!print AHOJ}},{{!ifeq {{$a}}|b|TRUE|FALSE}}"
|
964
|
+
tc "", "{{!ifeq a|b|TRUE}}"
|
965
|
+
tc "<p>AHOJ,dve</p>\n", "{{ytest \nahoj: AHOJ\nbhoj: [ jedna, dve ]\n}}"
|
966
|
+
tc "<p>,malo</p>\n", "{{!yset ahoj|data: [1,2]\ndesc: malo}},{{$ahoj.desc}}"
|
967
|
+
tc "<p>,BETA</p>\n", "{{!yset ahoj|data: [ALFA,BETA]\ndesc: malo}},{{$ahoj.data.1}}"
|
968
|
+
tc "<p>,GAMA</p>\n", "{{!yset ahoj|data: [ALFA,BETA]\ndesc: malo}},{{!set ahoj.data.3|GAMA}}{{$ahoj.data.3}}"
|
969
|
+
tc "<p>,2</p>\n", "{{!yset ahoj|data: [1,2]\ndesc: malo}},{{$ahoj.data.1}}"
|
970
|
+
tc "<p>AHOJ,dve</p>\n", "{{ytest2 \nahoj: AHOJ\nbhoj: [ jedna, dve ]\n}}"
|
971
|
+
tc "<p>,,BHOJ</p>\n", "{{!set ahoj|AHOJ}},{{!set AHOJ|BHOJ}},{{$$ahoj}}"
|
972
|
+
tc "<p>(0),(1),(2),</p>\n", "{{!for i|3|({{$i}}),}}", raw_html: true
|
973
|
+
tc "<p>(0),(1),(2),(3),</p>\n", "{{!for i|4|({{$i}}),}}", raw_html: true
|
974
|
+
tc "<p>,(ALFA),(BETA),</p>\n", "{{!yset data|[ALFA,BETA]}},{{!for i|data|({{$data.$i}}),}}"
|
975
|
+
tc "<p>,(1),(2),</p>\n", "{{!yset data|[1,2]}},{{!for i|data|({{$data.$i}}),}}"
|
976
|
+
tc "<p>,(alfa:ALFA),(beta:BETA),</p>\n", "{{!yset data|beta: BETA\nalfa: ALFA\n}},{{!for i|data|({{$i}}:{{$data.$i}}),}}"
|
977
|
+
|
978
|
+
tc "<p>,FALSE</p>\n", "{{!yset data|[1,2]}},{{!ifdef data.55|TRUE|FALSE}}"
|
979
|
+
tc "<p>,TRUE</p>\n", "{{!yset data|[1,2]}},{{!ifdef data.1|TRUE|FALSE}}"
|
980
|
+
tc "<p>,TRUE</p>\n", "{{!yset data|{a: 1, b: 2} }},{{!ifdef data.a|TRUE|FALSE}}"
|
981
|
+
tc "<p>,FALSE</p>\n", "{{!yset data|{a: 1, b: 2} }},{{!ifdef data.q|TRUE|FALSE}}"
|
982
|
+
tc "<p>,1,(1;2;),1</p>\n", "{{!yset data|{a: 1, b: 2} }},{{$data.a}},({{!for i|data|{{$data.$i}};}}),{{$data.a}}"
|
983
|
+
tc "<p>1,(AHOJ(a) 1; AHOJ(b) 2; ),1</p>\n", "{{fortest data:\n a: 1\n b: 2 }}"
|
984
|
+
end
|
985
|
+
|
986
|
+
it 'should {{!sub}}' do
|
987
|
+
tc "<p>ahoj_you_one</p>\n", "{{!sub ahoj you one| |_}}"
|
988
|
+
tc "<p>-h-j --- -n-</p>\n", "{{!sub ahoj you one|/[aeiouy]/|-}}"
|
989
|
+
tc "<p>ahoj MATCH(you) one</p>\n", "{{!sub ahoj you one|/(y.u)/|MATCH(\\1)}}"
|
990
|
+
end
|
991
|
+
|
992
|
+
it 'should {{!html}}' do
|
993
|
+
tc "alert(666)", "{{!html <script>alert(666)</script>}}", raw_html: true
|
994
|
+
tc "<p><b>T</b>E</p>", "{{!html <p><b>T</b>E</p>}}\n", raw_html: true
|
995
|
+
tc "<span>Span</span>", "{{!html <span>Span</span>}}\n", raw_html: true
|
996
|
+
#tc "<span>Span</span>", "**{{!html <span>Span</span>}}**\n", raw_html: true
|
997
|
+
tc "<div class=\"ahoj\">Div</div>", "{{!html <div class=\"ahoj\">Div</div>}}\n", raw_html: true
|
998
|
+
tc "<span>Span</span><span>Span</span>", "{{!html <span>Span</span>}}{{!html <span>Span</span>}}\n", raw_html: true
|
999
|
+
tc "<p>ahoj <span class=\"spanclass\">span</span> bhoj dhoj choj</p>\n", "ahoj {{{!<span class=\"spanclass\">span</span> bhoj}}} dhoj \nchoj\n", raw_html: true
|
1000
|
+
tc "<p>ahoj Q<span class=\"spanclass\">span</span> bhojQ dhoj choj</p>\n", "ahoj Q{{{!<span class=\"spanclass\">span</span> bhoj}}}Q dhoj \nchoj\n", raw_html: true
|
1001
|
+
end
|
1002
|
+
# it 'last test' do
|
1003
|
+
# #tc "<p>1,(AHOJ(a) 1; AHOJ(b) 2; ),1</p>\n", "{{fortest data:\n a: 1\n b: 2 }}"
|
1004
|
+
#
|
1005
|
+
# end
|
928
1006
|
end
|
929
1007
|
end
|
930
1008
|
# vim: tw=0
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trac-wiki
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.20
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-01-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bacon
|
@@ -60,6 +60,7 @@ files:
|
|
60
60
|
- Rakefile
|
61
61
|
- bin/trac-wiki.rb
|
62
62
|
- lib/trac-wiki.rb
|
63
|
+
- lib/trac-wiki/env.rb
|
63
64
|
- lib/trac-wiki/parser.rb
|
64
65
|
- lib/trac-wiki/tree.rb
|
65
66
|
- lib/trac-wiki/version.rb
|