• R/O
  • HTTP
  • SSH
  • HTTPS

提交

标签
No Tags

Frequently used words (click to add to your profile)

javaandroidc++linuxc#objective-ccocoa誰得qtrubypythongamewindowsbathyscaphephpguic翻訳omegattwitterframeworktestbtronarduinovb.net計画中(planning stage)directxpreviewerゲームエンジンdom

generic text markup tools


Commit MetaInfo

修订版41d3b74ac0626b1059cd1871a0f68dfa6d4f4082 (tree)
时间2013-04-08 22:21:38
作者hylom <hylom@hylo...>
Commiterhylom

Log Message

implement 'extends' property

更改概述

差异

--- a/jarkup.json
+++ b/jarkup.json
@@ -44,10 +44,10 @@
4444 "begin": "^・",
4545 "end": "^\\s*$",
4646 "onStart": {
47- "insert": "<ul>"
47+ "insert": "<ul>\n"
4848 },
4949 "onFinished": {
50- "insert": "</ul>"
50+ "insert": "</ul>\n"
5151 }
5252 },
5353 "table": {
@@ -55,7 +55,7 @@
5555 "tableRow": {
5656 "priority": 102,
5757 "regexp": "^(.*)$",
58- "replace": "<tr>\\n <td>\\1</td>\\n</tr>"
58+ "replace": "<tr>\n <td>\\1</td>\n</tr>"
5959 },
6060 "caption": {
6161 "priority": 110,
@@ -65,16 +65,16 @@
6565 "ref",
6666 "caption"
6767 ],
68- "replace": "<div class=\"table\"><table>\\n<caption>表\\1 \\2</caption>"
68+ "replace": "<div class=\"table\"><table>\n<caption>表\\1 \\2</caption>"
6969 },
7070 "tableHeaderRow": {
71- "priority": 103,
71+ "priority": 104,
7272 "regexp": "^〓(.*)$",
7373 "set": [
7474 "isHeader",
7575 "yes"
7676 ],
77- "replace": "<tr>\\n <th>\\1</th>\\n</tr>"
77+ "replace": "<tr>\n <th>\\1</th>\n</tr>"
7878 },
7979 "tableCell": {
8080 "priority": 103,
@@ -93,7 +93,7 @@
9393 "begin": "^☆表.*",
9494 "end": "^\\s*$",
9595 "onFinished": {
96- "insert": "</table></div>"
96+ "insert": "</table></div>\n"
9797 }
9898 },
9999 "fontDecoration": {
@@ -122,28 +122,6 @@
122122 },
123123 "code": {
124124 "extends": "fontDecoration",
125- "rules": {
126- "red1": {
127- "priority": 102,
128- "regexp": "\\*g\\[(.*?)]",
129- "replace": "<strong class=\"red\">\\1</strong>"
130- },
131- "bold2": {
132- "priority": 103,
133- "regexp": "\\*b\\{(.*?)}",
134- "replace": "<strong>\\1</strong>"
135- },
136- "red2": {
137- "priority": 104,
138- "regexp": "\\*g\\{(.*?)}",
139- "replace": "<strong class=\"red-text\">\\1</strong>"
140- },
141- "bold1": {
142- "priority": 105,
143- "regexp": "\\*b\\[(.*?)]",
144- "replace": "<strong>\\1</strong>"
145- }
146- },
147125 "begin": "^☆\\+---\\s*$",
148126 "end": "^☆\\+---\\s*$",
149127 "onStart": {
@@ -178,7 +156,7 @@
178156 "begin": "^☆図.*$",
179157 "end": "^\\s*$",
180158 "onFinished": {
181- "insert": "</div>"
159+ "insert": "</div>\n"
182160 }
183161 },
184162 "note": {
@@ -190,7 +168,7 @@
190168 "replace": ""
191169 },
192170 "onFinished": {
193- "insert": "</div>",
171+ "insert": "</div>\n",
194172 "replace": ""
195173 }
196174 },
@@ -220,4 +198,4 @@
220198 "image_dir",
221199 "."
222200 ]
223-}
\ No newline at end of file
201+}
--- a/test/test.txt
+++ b/test/test.txt
@@ -43,6 +43,7 @@
4343 ☆+---
4444 実行例/リストなどは
4545 このようにして
46+うめこめます
4647 ☆+---
4748
4849 ☆表1 表のキャプション
--- a/textparser.py
+++ b/textparser.py
@@ -2,21 +2,29 @@
22 # -*- coding:utf-8 -*-
33
44 import re
5-
6-def CreateMode(lexi, mode_name):
7- return Mode(lexi, mode_name)
8-
9-
10-class Mode(dict):
11- def __init__(self, lexi, mode_name):
12- self.lexi = lexi
13- modes = lexi.get("modes")
14- self.update(modes[mode_name])
15- self.mode_name = mode_name
5+import sys
6+
7+def _debug_print(*args):
8+ print >> sys.stderr, args
9+
10+def create_mode(lexi, mode_name):
11+ modes = lexi.get("modes")
12+ return Mode(lexi, modes[mode_name], mode_name)
13+
14+class Mode(object):
15+ def __init__(self, lexi, attrs, mode_name):
16+ self._lexi = lexi
17+ self._attrs = attrs
18+ self.name = mode_name
19+ base_mode = attrs.get("extends", False)
20+ if base_mode:
21+ self._base = create_mode(self._lexi, base_mode)
22+ else:
23+ self._base = None
1624
1725 def test(self, attr_name, text):
1826 '''test attr_name matches text'''
19- rex = self.get(attr_name, False)
27+ rex = self.attr(attr_name, False)
2028 if rex and re.search(rex, text):
2129 return True
2230 else:
@@ -24,28 +32,44 @@ class Mode(dict):
2432
2533 def has_attr(self, attr_name):
2634 '''if attr_name exists, return True'''
27- return (attr_name in self)
35+ if attr_name in self._attrs:
36+ return True
37+ if self._base:
38+ return self._base.has_attr(attr_name)
39+ return False
2840
2941 def attr(self, attr_name, default=None):
3042 '''return value of attr_name'''
31- return self.get(attr_name, default)
43+ if attr_name in self._attrs:
44+ return self._attrs.get(attr_name)
45+ if self._base:
46+ return self._base.attr(attr_name, default)
47+ return default
3248
3349 def is_true(self, attr_name):
3450 '''if attr_name is True, return True'''
35- return self.get_attr(attr_name, False)
51+ return self.attr(attr_name, False)
3652
3753 def is_false(self, attr_name):
3854 '''if attr_name is False, return True'''
39- return not self.get_attr(attr_name, True)
55+ return not self.attr(attr_name, True)
4056
4157 def has_rule(self, rule_name):
4258 '''if rule_name exists, return True'''
4359 rules = self.get("rules", {})
4460 return rule_name in rules
4561
62+ def _rules(self):
63+ if self._base:
64+ rules = self._base._rules()
65+ rules.update(self._attrs.get('rules', {}))
66+ else:
67+ rules = self._attrs.get('rules', {})
68+ return rules
69+
4670 def rules(self):
4771 '''return list include sorted rule names'''
48- rules = self.get('rules', {})
72+ rules = self._rules()
4973 rule_keys = rules.keys()
5074 sort_fn = lambda x,y:-cmp(rules[x].get("priority",0), rules[y].get("priority", 0))
5175 rule_keys.sort(sort_fn)
@@ -53,8 +77,12 @@ class Mode(dict):
5377
5478 def rule(self, rule_name):
5579 '''return rule dict corresponds rule_name'''
56- rules = self.get('rules', {})
57- return rules.get(rule_name, None)
80+ rules = self.attr('rules', {})
81+ if rule_name in rules:
82+ return rules.get(rule_name)
83+ if self._base:
84+ return self._base.rule(rule_name)
85+ return None
5886
5987 def on_start(self, writer, text):
6088 '''action when mode started'''
@@ -140,20 +168,20 @@ class Store(dict):
140168 self.global_store[key] = value
141169
142170 def save(self, mode, key, value):
143- modekey = mode.mode_name
171+ modekey = mode.name
144172 if not modekey in self.mode_stores:
145173 self.mode_stores[modekey] = {}
146174 self.mode_stores[modekey][key] = value
147175
148176 def load(self, mode, key, default=None):
149- modekey = mode.mode_name
177+ modekey = mode.name
150178 if (modekey in self.mode_stores) and (key in self.mode_stores[modekey]):
151179 return self.mode_stores[modekey][key]
152180 else:
153181 return self.global_store.get(key, default)
154182
155183 def delete(self, mode, key):
156- modekey = mode.mode_name
184+ modekey = mode.name
157185 if not modekey in self.mode_stores:
158186 return
159187 if not key in self.mode_stores[modekey]:
@@ -161,7 +189,7 @@ class Store(dict):
161189 del self.mode_stores[modekey][key]
162190
163191 def clear(self, mode):
164- modekey = mode.mode_name
192+ modekey = mode.name
165193 if modekey in self.mode_stores:
166194 del self.mode_stores[modekey]
167195
@@ -184,7 +212,7 @@ class Parser(object):
184212 }
185213
186214 def _get_mode(self, mode_name):
187- return Mode(self.lexi, mode_name)
215+ return create_mode(self.lexi, mode_name)
188216
189217 def current_mode(self):
190218 mode_name = self.mode_stack.current()
@@ -202,12 +230,12 @@ class Parser(object):
202230 l = iter_in.next().strip('\r\n')
203231 out = self._markup(l)
204232 self.write(out)
233+ self.write('\n')
205234 except StopIteration:
206235 return
207236
208237 def write(self, text):
209238 self.stream_out.write(text)
210- self.stream_out.write('\n')
211239
212240 def _expand_variable(self, text):
213241 mode = self.current_mode()
@@ -229,7 +257,6 @@ class Parser(object):
229257 return ''
230258
231259 mode = self.current_mode()
232-
233260 if mode.test("end", text):
234261 text = mode.on_exit(self, text)
235262 self.mode_stack.pop()
@@ -241,8 +268,8 @@ class Parser(object):
241268
242269 if mode.has_attr('transitions'):
243270 for candidate in mode.attr('transitions'):
244- mode = self._get_mode(candidate)
245- if mode and mode.test('begin', text):
271+ sub_mode = self._get_mode(candidate)
272+ if sub_mode and sub_mode.test('begin', text):
246273 self.mode_stack.push(candidate)
247274 next_mode = self.current_mode()
248275 text = next_mode.on_start(self, text)
@@ -254,7 +281,6 @@ class Parser(object):
254281 if is_finish:
255282 break
256283
257-
258284 return text
259285
260286 def apply_rule(self, rule, text):
@@ -279,7 +305,7 @@ class Parser(object):
279305 if value not in rule['switch'][key]:
280306 continue
281307 new_rule = rule['switch'][key][value]
282- return self.apply_rule(new_rule, text)
308+ (cont, text) = self.apply_rule(new_rule, text)
283309
284310 if 'store' in rule:
285311 arg = rule['store']