tdrpa.tdworker 1.2.13.2__py312-none-win_amd64.whl
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.
- tdrpa/_tdxlwings/__init__.py +193 -0
- tdrpa/_tdxlwings/__pycache__/__init__.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/__init__.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_win32patch.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_win32patch.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_xlwindows.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_xlwindows.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/apps.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/apps.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/base_classes.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/base_classes.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/com_server.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/com_server.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/constants.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/constants.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/expansion.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/expansion.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/main.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/main.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/udfs.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/udfs.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/utils.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/utils.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/_win32patch.py +90 -0
- tdrpa/_tdxlwings/_xlmac.py +2240 -0
- tdrpa/_tdxlwings/_xlwindows.py +2518 -0
- tdrpa/_tdxlwings/addin/Dictionary.cls +474 -0
- tdrpa/_tdxlwings/addin/IWebAuthenticator.cls +71 -0
- tdrpa/_tdxlwings/addin/WebClient.cls +772 -0
- tdrpa/_tdxlwings/addin/WebHelpers.bas +3203 -0
- tdrpa/_tdxlwings/addin/WebRequest.cls +875 -0
- tdrpa/_tdxlwings/addin/WebResponse.cls +453 -0
- tdrpa/_tdxlwings/addin/xlwings.xlam +0 -0
- tdrpa/_tdxlwings/apps.py +35 -0
- tdrpa/_tdxlwings/base_classes.py +1092 -0
- tdrpa/_tdxlwings/cli.py +1306 -0
- tdrpa/_tdxlwings/com_server.py +385 -0
- tdrpa/_tdxlwings/constants.py +3080 -0
- tdrpa/_tdxlwings/conversion/__init__.py +103 -0
- tdrpa/_tdxlwings/conversion/framework.py +147 -0
- tdrpa/_tdxlwings/conversion/numpy_conv.py +34 -0
- tdrpa/_tdxlwings/conversion/pandas_conv.py +184 -0
- tdrpa/_tdxlwings/conversion/standard.py +321 -0
- tdrpa/_tdxlwings/expansion.py +83 -0
- tdrpa/_tdxlwings/ext/__init__.py +3 -0
- tdrpa/_tdxlwings/ext/sql.py +73 -0
- tdrpa/_tdxlwings/html/xlwings-alert.html +71 -0
- tdrpa/_tdxlwings/js/xlwings.js +577 -0
- tdrpa/_tdxlwings/js/xlwings.ts +729 -0
- tdrpa/_tdxlwings/mac_dict.py +6399 -0
- tdrpa/_tdxlwings/main.py +5205 -0
- tdrpa/_tdxlwings/mistune/__init__.py +63 -0
- tdrpa/_tdxlwings/mistune/block_parser.py +366 -0
- tdrpa/_tdxlwings/mistune/inline_parser.py +216 -0
- tdrpa/_tdxlwings/mistune/markdown.py +84 -0
- tdrpa/_tdxlwings/mistune/renderers.py +220 -0
- tdrpa/_tdxlwings/mistune/scanner.py +121 -0
- tdrpa/_tdxlwings/mistune/util.py +41 -0
- tdrpa/_tdxlwings/pro/__init__.py +40 -0
- tdrpa/_tdxlwings/pro/_xlcalamine.py +536 -0
- tdrpa/_tdxlwings/pro/_xlofficejs.py +146 -0
- tdrpa/_tdxlwings/pro/_xlremote.py +1293 -0
- tdrpa/_tdxlwings/pro/custom_functions_code.js +150 -0
- tdrpa/_tdxlwings/pro/embedded_code.py +60 -0
- tdrpa/_tdxlwings/pro/udfs_officejs.py +549 -0
- tdrpa/_tdxlwings/pro/utils.py +199 -0
- tdrpa/_tdxlwings/quickstart.xlsm +0 -0
- tdrpa/_tdxlwings/quickstart_addin.xlam +0 -0
- tdrpa/_tdxlwings/quickstart_addin_ribbon.xlam +0 -0
- tdrpa/_tdxlwings/quickstart_fastapi/main.py +47 -0
- tdrpa/_tdxlwings/quickstart_fastapi/requirements.txt +3 -0
- tdrpa/_tdxlwings/quickstart_standalone.xlsm +0 -0
- tdrpa/_tdxlwings/reports.py +12 -0
- tdrpa/_tdxlwings/rest/__init__.py +1 -0
- tdrpa/_tdxlwings/rest/api.py +368 -0
- tdrpa/_tdxlwings/rest/serializers.py +103 -0
- tdrpa/_tdxlwings/server.py +14 -0
- tdrpa/_tdxlwings/udfs.py +775 -0
- tdrpa/_tdxlwings/utils.py +777 -0
- tdrpa/_tdxlwings/xlwings-0.31.6.applescript +30 -0
- tdrpa/_tdxlwings/xlwings.bas +2061 -0
- tdrpa/_tdxlwings/xlwings_custom_addin.bas +2042 -0
- tdrpa/_tdxlwings/xlwingslib.cp38-win_amd64.pyd +0 -0
- tdrpa/tdworker/__init__.pyi +12 -0
- tdrpa/tdworker/_clip.pyi +50 -0
- tdrpa/tdworker/_excel.pyi +743 -0
- tdrpa/tdworker/_file.pyi +77 -0
- tdrpa/tdworker/_img.pyi +226 -0
- tdrpa/tdworker/_network.pyi +94 -0
- tdrpa/tdworker/_os.pyi +47 -0
- tdrpa/tdworker/_sp.pyi +21 -0
- tdrpa/tdworker/_w.pyi +129 -0
- tdrpa/tdworker/_web.pyi +995 -0
- tdrpa/tdworker/_winE.pyi +228 -0
- tdrpa/tdworker/_winK.pyi +74 -0
- tdrpa/tdworker/_winM.pyi +117 -0
- tdrpa/tdworker.cp312-win_amd64.pyd +0 -0
- tdrpa_tdworker-1.2.13.2.dist-info/METADATA +38 -0
- tdrpa_tdworker-1.2.13.2.dist-info/RECORD +101 -0
- tdrpa_tdworker-1.2.13.2.dist-info/WHEEL +5 -0
- tdrpa_tdworker-1.2.13.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
from .markdown import Markdown
|
2
|
+
from .block_parser import BlockParser
|
3
|
+
from .inline_parser import InlineParser
|
4
|
+
from .renderers import AstRenderer, HTMLRenderer
|
5
|
+
from .plugins import PLUGINS
|
6
|
+
from .util import escape, escape_url, escape_html, unikey
|
7
|
+
|
8
|
+
|
9
|
+
def create_markdown(escape=True, hard_wrap=False, renderer=None, plugins=None):
|
10
|
+
"""Create a Markdown instance based on the given condition.
|
11
|
+
|
12
|
+
:param escape: Boolean. If using html renderer, escape html.
|
13
|
+
:param hard_wrap: Boolean. Break every new line into ``<br>``.
|
14
|
+
:param renderer: renderer instance or string of ``html`` and ``ast``.
|
15
|
+
:param plugins: List of plugins, string or callable.
|
16
|
+
|
17
|
+
This method is used when you want to re-use a Markdown instance::
|
18
|
+
|
19
|
+
markdown = create_markdown(
|
20
|
+
escape=False,
|
21
|
+
renderer='html',
|
22
|
+
plugins=['url', 'strikethrough', 'footnotes', 'table'],
|
23
|
+
)
|
24
|
+
# re-use markdown function
|
25
|
+
markdown('.... your text ...')
|
26
|
+
"""
|
27
|
+
if renderer is None or renderer == 'html':
|
28
|
+
renderer = HTMLRenderer(escape=escape)
|
29
|
+
elif renderer == 'ast':
|
30
|
+
renderer = AstRenderer()
|
31
|
+
|
32
|
+
if plugins:
|
33
|
+
_plugins = []
|
34
|
+
for p in plugins:
|
35
|
+
if isinstance(p, str):
|
36
|
+
_plugins.append(PLUGINS[p])
|
37
|
+
else:
|
38
|
+
_plugins.append(p)
|
39
|
+
plugins = _plugins
|
40
|
+
|
41
|
+
return Markdown(renderer, inline=InlineParser(renderer, hard_wrap=hard_wrap), plugins=plugins)
|
42
|
+
|
43
|
+
|
44
|
+
html = create_markdown(
|
45
|
+
escape=False,
|
46
|
+
renderer='html',
|
47
|
+
plugins=['strikethrough', 'footnotes', 'table'],
|
48
|
+
)
|
49
|
+
|
50
|
+
|
51
|
+
def markdown(text, escape=True, renderer=None, plugins=None):
|
52
|
+
md = create_markdown(escape=escape, renderer=renderer, plugins=plugins)
|
53
|
+
return md(text)
|
54
|
+
|
55
|
+
|
56
|
+
__all__ = [
|
57
|
+
'Markdown', 'AstRenderer', 'HTMLRenderer',
|
58
|
+
'BlockParser', 'InlineParser',
|
59
|
+
'escape', 'escape_url', 'escape_html', 'unikey',
|
60
|
+
'html', 'create_markdown', 'markdown'
|
61
|
+
]
|
62
|
+
|
63
|
+
__version__ = '2.0.2'
|
@@ -0,0 +1,366 @@
|
|
1
|
+
import re
|
2
|
+
from .scanner import ScannerParser, Matcher
|
3
|
+
from .inline_parser import ESCAPE_CHAR, LINK_LABEL
|
4
|
+
from .util import unikey
|
5
|
+
|
6
|
+
_NEW_LINES = re.compile(r'\r\n|\r')
|
7
|
+
_BLANK_LINES = re.compile(r'^ +$', re.M)
|
8
|
+
|
9
|
+
_TRIM_4 = re.compile(r'^ {1,4}')
|
10
|
+
_EXPAND_TAB = re.compile(r'^( {0,3})\t', flags=re.M)
|
11
|
+
_INDENT_CODE_TRIM = re.compile(r'^ {1,4}', flags=re.M)
|
12
|
+
_BLOCK_QUOTE_TRIM = re.compile(r'^ {0,1}', flags=re.M)
|
13
|
+
_BLOCK_QUOTE_LEADING = re.compile(r'^ *>', flags=re.M)
|
14
|
+
_BLOCK_TAGS = {
|
15
|
+
'address', 'article', 'aside', 'base', 'basefont', 'blockquote',
|
16
|
+
'body', 'caption', 'center', 'col', 'colgroup', 'dd', 'details',
|
17
|
+
'dialog', 'dir', 'div', 'dl', 'dt', 'fieldset', 'figcaption',
|
18
|
+
'figure', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3',
|
19
|
+
'h4', 'h5', 'h6', 'head', 'header', 'hr', 'html', 'iframe',
|
20
|
+
'legend', 'li', 'link', 'main', 'menu', 'menuitem', 'meta', 'nav',
|
21
|
+
'noframes', 'ol', 'optgroup', 'option', 'p', 'param', 'section',
|
22
|
+
'source', 'summary', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead',
|
23
|
+
'title', 'tr', 'track', 'ul'
|
24
|
+
}
|
25
|
+
_BLOCK_HTML_RULE6 = (
|
26
|
+
r'</?(?:' + '|'.join(_BLOCK_TAGS) + r')'
|
27
|
+
r'(?: +|\n|/?>)[\s\S]*?'
|
28
|
+
r'(?:\n{2,}|\n*$)'
|
29
|
+
)
|
30
|
+
_BLOCK_HTML_RULE7 = (
|
31
|
+
# open tag
|
32
|
+
r'<(?!script|pre|style)([a-z][\w-]*)(?:'
|
33
|
+
r' +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"|'
|
34
|
+
r''' *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?'''
|
35
|
+
r')*? */?>(?=\s*\n)[\s\S]*?(?:\n{2,}|\n*$)|'
|
36
|
+
# close tag
|
37
|
+
r'</(?!script|pre|style)[a-z][\w-]*\s*>(?=\s*\n)[\s\S]*?(?:\n{2,}|\n*$)'
|
38
|
+
)
|
39
|
+
|
40
|
+
_PARAGRAPH_SPLIT = re.compile(r'\n{2,}')
|
41
|
+
_LIST_BULLET = re.compile(r'^ *([\*\+-]|\d+[.)])')
|
42
|
+
|
43
|
+
|
44
|
+
class BlockParser(ScannerParser):
|
45
|
+
scanner_cls = Matcher
|
46
|
+
|
47
|
+
NEWLINE = re.compile(r'\n+')
|
48
|
+
DEF_LINK = re.compile(
|
49
|
+
r' {0,3}\[(' + LINK_LABEL + r')\]:(?:[ \t]*\n)?[ \t]*'
|
50
|
+
r'<?([^\s>]+)>?(?:[ \t]*\n)?'
|
51
|
+
r'(?: +["(]([^\n]+)[")])? *\n+'
|
52
|
+
)
|
53
|
+
|
54
|
+
AXT_HEADING = re.compile(
|
55
|
+
r' {0,3}(#{1,6})(?!#+)(?: *\n+|'
|
56
|
+
r'\s+([^\n]*?)(?:\n+|\s+?#+\s*\n+))'
|
57
|
+
)
|
58
|
+
SETEX_HEADING = re.compile(r'([^\n]+)\n *(=|-){2,}[ \t]*\n+')
|
59
|
+
THEMATIC_BREAK = re.compile(
|
60
|
+
r' {0,3}((?:-[ \t]*){3,}|'
|
61
|
+
r'(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})\n+'
|
62
|
+
)
|
63
|
+
|
64
|
+
INDENT_CODE = re.compile(r'(?:\n*)(?:(?: {4}| *\t)[^\n]+\n*)+')
|
65
|
+
|
66
|
+
FENCED_CODE = re.compile(
|
67
|
+
r'( {0,3})(`{3,}|~{3,})([^`\n]*)\n'
|
68
|
+
r'(?:|([\s\S]*?)\n)'
|
69
|
+
r'(?: {0,3}\2[~`]* *\n+|$)'
|
70
|
+
)
|
71
|
+
BLOCK_QUOTE = re.compile(
|
72
|
+
r'(?: {0,3}>[^\n]*\n)+'
|
73
|
+
)
|
74
|
+
LIST_START = re.compile(
|
75
|
+
r'( {0,3})([\*\+-]|\d{1,9}[.)])(?:[ \t]*|[ \t][^\n]+)\n+'
|
76
|
+
)
|
77
|
+
|
78
|
+
BLOCK_HTML = re.compile((
|
79
|
+
r' {0,3}(?:'
|
80
|
+
r'<(script|pre|style)[\s>][\s\S]*?(?:</\1>[^\n]*\n+|$)|'
|
81
|
+
r'<!--(?!-?>)[\s\S]*?-->[^\n]*\n+|'
|
82
|
+
r'<\?[\s\S]*?\?>[^\n]*\n+|'
|
83
|
+
r'<![A-Z][\s\S]*?>[^\n]*\n+|'
|
84
|
+
r'<!\[CDATA\[[\s\S]*?\]\]>[^\n]*\n+'
|
85
|
+
r'|' + _BLOCK_HTML_RULE6 + '|' + _BLOCK_HTML_RULE7 + ')'
|
86
|
+
), re.I)
|
87
|
+
|
88
|
+
LIST_MAX_DEPTH = 6
|
89
|
+
BLOCK_QUOTE_MAX_DEPTH = 6
|
90
|
+
RULE_NAMES = (
|
91
|
+
'newline', 'thematic_break',
|
92
|
+
'fenced_code', 'indent_code',
|
93
|
+
'block_quote', 'block_html',
|
94
|
+
'list_start',
|
95
|
+
'axt_heading', 'setex_heading',
|
96
|
+
'def_link',
|
97
|
+
)
|
98
|
+
|
99
|
+
def __init__(self):
|
100
|
+
super(BlockParser, self).__init__()
|
101
|
+
self.block_quote_rules = list(self.RULE_NAMES)
|
102
|
+
self.list_rules = list(self.RULE_NAMES)
|
103
|
+
|
104
|
+
def parse_newline(self, m, state):
|
105
|
+
return {'type': 'newline', 'blank': True}
|
106
|
+
|
107
|
+
def parse_thematic_break(self, m, state):
|
108
|
+
return {'type': 'thematic_break', 'blank': True}
|
109
|
+
|
110
|
+
def parse_indent_code(self, m, state):
|
111
|
+
text = expand_leading_tab(m.group(0))
|
112
|
+
code = _INDENT_CODE_TRIM.sub('', text)
|
113
|
+
code = code.lstrip('\n')
|
114
|
+
return self.tokenize_block_code(code, None, state)
|
115
|
+
|
116
|
+
def parse_fenced_code(self, m, state):
|
117
|
+
info = ESCAPE_CHAR.sub(r'\1', m.group(3))
|
118
|
+
spaces = m.group(1)
|
119
|
+
code = m.group(4) or ''
|
120
|
+
if spaces and code:
|
121
|
+
_trim_pattern = re.compile('^' + spaces, re.M)
|
122
|
+
code = _trim_pattern.sub('', code)
|
123
|
+
return self.tokenize_block_code(code + '\n', info, state)
|
124
|
+
|
125
|
+
def tokenize_block_code(self, code, info, state):
|
126
|
+
token = {'type': 'block_code', 'raw': code}
|
127
|
+
if info:
|
128
|
+
token['params'] = (info, )
|
129
|
+
return token
|
130
|
+
|
131
|
+
def parse_axt_heading(self, m, state):
|
132
|
+
level = len(m.group(1))
|
133
|
+
text = m.group(2) or ''
|
134
|
+
text = text.strip()
|
135
|
+
if set(text) == {'#'}:
|
136
|
+
text = ''
|
137
|
+
return self.tokenize_heading(text, level, state)
|
138
|
+
|
139
|
+
def parse_setex_heading(self, m, state):
|
140
|
+
level = 1 if m.group(2) == '=' else 2
|
141
|
+
text = m.group(1)
|
142
|
+
text = text.strip()
|
143
|
+
return self.tokenize_heading(text, level, state)
|
144
|
+
|
145
|
+
def tokenize_heading(self, text, level, state):
|
146
|
+
return {'type': 'heading', 'text': text, 'params': (level,)}
|
147
|
+
|
148
|
+
def get_block_quote_rules(self, depth):
|
149
|
+
if depth > self.BLOCK_QUOTE_MAX_DEPTH - 1:
|
150
|
+
rules = list(self.block_quote_rules)
|
151
|
+
rules.remove('block_quote')
|
152
|
+
return rules
|
153
|
+
return self.block_quote_rules
|
154
|
+
|
155
|
+
def parse_block_quote(self, m, state):
|
156
|
+
depth = state.get('block_quote_depth', 0) + 1
|
157
|
+
state['block_quote_depth'] = depth
|
158
|
+
|
159
|
+
# normalize block quote text
|
160
|
+
text = _BLOCK_QUOTE_LEADING.sub('', m.group(0))
|
161
|
+
text = expand_leading_tab(text)
|
162
|
+
text = _BLOCK_QUOTE_TRIM.sub('', text)
|
163
|
+
text = cleanup_lines(text)
|
164
|
+
|
165
|
+
rules = self.get_block_quote_rules(depth)
|
166
|
+
children = self.parse(text, state, rules)
|
167
|
+
state['block_quote_depth'] = depth - 1
|
168
|
+
return {'type': 'block_quote', 'children': children}
|
169
|
+
|
170
|
+
def get_list_rules(self, depth):
|
171
|
+
if depth > self.LIST_MAX_DEPTH - 1:
|
172
|
+
rules = list(self.list_rules)
|
173
|
+
rules.remove('list_start')
|
174
|
+
return rules
|
175
|
+
return self.list_rules
|
176
|
+
|
177
|
+
def parse_list_start(self, m, state, string):
|
178
|
+
items = []
|
179
|
+
spaces = m.group(1)
|
180
|
+
marker = m.group(2)
|
181
|
+
items, pos = _find_list_items(string, m.start(), spaces, marker)
|
182
|
+
tight = '\n\n' not in ''.join(items).strip()
|
183
|
+
|
184
|
+
ordered = len(marker) != 1
|
185
|
+
if ordered:
|
186
|
+
start = int(marker[:-1])
|
187
|
+
if start == 1:
|
188
|
+
start = None
|
189
|
+
else:
|
190
|
+
start = None
|
191
|
+
|
192
|
+
list_tights = state.get('list_tights', [])
|
193
|
+
list_tights.append(tight)
|
194
|
+
state['list_tights'] = list_tights
|
195
|
+
|
196
|
+
depth = len(list_tights)
|
197
|
+
rules = self.get_list_rules(depth)
|
198
|
+
children = [
|
199
|
+
self.parse_list_item(item, depth, state, rules)
|
200
|
+
for item in items
|
201
|
+
]
|
202
|
+
list_tights.pop()
|
203
|
+
params = (ordered, depth, start)
|
204
|
+
token = {'type': 'list', 'children': children, 'params': params}
|
205
|
+
return token, pos
|
206
|
+
|
207
|
+
def parse_list_item(self, text, depth, state, rules):
|
208
|
+
text = self.normalize_list_item_text(text)
|
209
|
+
if not text:
|
210
|
+
children = [{'type': 'block_text', 'text': ''}]
|
211
|
+
else:
|
212
|
+
children = self.parse(text, state, rules)
|
213
|
+
return {
|
214
|
+
'type': 'list_item',
|
215
|
+
'params': (depth,),
|
216
|
+
'children': children,
|
217
|
+
}
|
218
|
+
|
219
|
+
@staticmethod
|
220
|
+
def normalize_list_item_text(text):
|
221
|
+
text_length = len(text)
|
222
|
+
text = _LIST_BULLET.sub('', text)
|
223
|
+
|
224
|
+
if not text.strip():
|
225
|
+
return ''
|
226
|
+
|
227
|
+
space = text_length - len(text)
|
228
|
+
text = expand_leading_tab(text)
|
229
|
+
if text.startswith(' '):
|
230
|
+
text = text[1:]
|
231
|
+
space += 1
|
232
|
+
else:
|
233
|
+
text_length = len(text)
|
234
|
+
text = _TRIM_4.sub('', text)
|
235
|
+
space += max(text_length - len(text), 1)
|
236
|
+
|
237
|
+
# outdent
|
238
|
+
if '\n ' in text:
|
239
|
+
pattern = re.compile(r'\n {1,' + str(space) + r'}')
|
240
|
+
text = pattern.sub(r'\n', text)
|
241
|
+
return text
|
242
|
+
|
243
|
+
def parse_block_html(self, m, state):
|
244
|
+
html = m.group(0).rstrip()
|
245
|
+
return {'type': 'block_html', 'raw': html}
|
246
|
+
|
247
|
+
def parse_def_link(self, m, state):
|
248
|
+
key = unikey(m.group(1))
|
249
|
+
link = m.group(2)
|
250
|
+
title = m.group(3)
|
251
|
+
if key not in state['def_links']:
|
252
|
+
state['def_links'][key] = (link, title)
|
253
|
+
|
254
|
+
def parse_text(self, text, state):
|
255
|
+
list_tights = state.get('list_tights')
|
256
|
+
if list_tights and list_tights[-1]:
|
257
|
+
return {'type': 'block_text', 'text': text.strip()}
|
258
|
+
|
259
|
+
tokens = []
|
260
|
+
for s in _PARAGRAPH_SPLIT.split(text):
|
261
|
+
s = s.strip()
|
262
|
+
if s:
|
263
|
+
tokens.append({'type': 'paragraph', 'text': s})
|
264
|
+
return tokens
|
265
|
+
|
266
|
+
def parse(self, s, state, rules=None):
|
267
|
+
if rules is None:
|
268
|
+
rules = self.rules
|
269
|
+
|
270
|
+
return list(self._scan(s, state, rules))
|
271
|
+
|
272
|
+
def render(self, tokens, inline, state):
|
273
|
+
data = self._iter_render(tokens, inline, state)
|
274
|
+
return inline.renderer.finalize(data)
|
275
|
+
|
276
|
+
def _iter_render(self, tokens, inline, state):
|
277
|
+
for tok in tokens:
|
278
|
+
method = inline.renderer._get_method(tok['type'])
|
279
|
+
if 'blank' in tok:
|
280
|
+
yield method()
|
281
|
+
continue
|
282
|
+
|
283
|
+
if 'children' in tok:
|
284
|
+
children = self.render(tok['children'], inline, state)
|
285
|
+
elif 'raw' in tok:
|
286
|
+
children = tok['raw']
|
287
|
+
else:
|
288
|
+
children = inline(tok['text'], state)
|
289
|
+
params = tok.get('params')
|
290
|
+
if params:
|
291
|
+
yield method(children, *params)
|
292
|
+
else:
|
293
|
+
yield method(children)
|
294
|
+
|
295
|
+
|
296
|
+
def cleanup_lines(s):
|
297
|
+
s = _NEW_LINES.sub('\n', s)
|
298
|
+
s = _BLANK_LINES.sub('', s)
|
299
|
+
return s
|
300
|
+
|
301
|
+
|
302
|
+
def expand_leading_tab(text):
|
303
|
+
return _EXPAND_TAB.sub(_expand_tab_repl, text)
|
304
|
+
|
305
|
+
|
306
|
+
def _expand_tab_repl(m):
|
307
|
+
s = m.group(1)
|
308
|
+
return s + ' ' * (4 - len(s))
|
309
|
+
|
310
|
+
|
311
|
+
def _create_list_item_pattern(spaces, marker):
|
312
|
+
prefix = r'( {0,' + str(len(spaces) + len(marker)) + r'})'
|
313
|
+
|
314
|
+
if len(marker) > 1:
|
315
|
+
if marker[-1] == '.':
|
316
|
+
prefix = prefix + r'\d{0,9}\.'
|
317
|
+
else:
|
318
|
+
prefix = prefix + r'\d{0,9}\)'
|
319
|
+
else:
|
320
|
+
if marker == '*':
|
321
|
+
prefix = prefix + r'\*'
|
322
|
+
elif marker == '+':
|
323
|
+
prefix = prefix + r'\+'
|
324
|
+
else:
|
325
|
+
prefix = prefix + r'-'
|
326
|
+
|
327
|
+
s1 = ' {' + str(len(marker) + 1) + ',}'
|
328
|
+
if len(marker) > 4:
|
329
|
+
s2 = ' {' + str(len(marker) - 4) + r',}\t'
|
330
|
+
else:
|
331
|
+
s2 = r' *\t'
|
332
|
+
return re.compile(
|
333
|
+
prefix + r'(?:[ \t]*|[ \t]+[^\n]+)\n+'
|
334
|
+
r'(?:\1(?:' + s1 + '|' + s2 + ')'
|
335
|
+
r'[^\n]+\n+)*'
|
336
|
+
)
|
337
|
+
|
338
|
+
|
339
|
+
def _find_list_items(string, pos, spaces, marker):
|
340
|
+
items = []
|
341
|
+
|
342
|
+
if marker in {'*', '-'}:
|
343
|
+
is_hr = re.compile(
|
344
|
+
r' *((?:-[ \t]*){3,}|(?:\*[ \t]*){3,})\n+'
|
345
|
+
)
|
346
|
+
else:
|
347
|
+
is_hr = None
|
348
|
+
|
349
|
+
pattern = _create_list_item_pattern(spaces, marker)
|
350
|
+
while 1:
|
351
|
+
m = pattern.match(string, pos)
|
352
|
+
if not m:
|
353
|
+
break
|
354
|
+
|
355
|
+
text = m.group(0)
|
356
|
+
if is_hr and is_hr.match(text):
|
357
|
+
break
|
358
|
+
|
359
|
+
new_spaces = m.group(1)
|
360
|
+
if new_spaces != spaces:
|
361
|
+
spaces = new_spaces
|
362
|
+
pattern = _create_list_item_pattern(spaces, marker)
|
363
|
+
|
364
|
+
items.append(text)
|
365
|
+
pos = m.end()
|
366
|
+
return items, pos
|
@@ -0,0 +1,216 @@
|
|
1
|
+
import re
|
2
|
+
from .scanner import ScannerParser
|
3
|
+
from .util import PUNCTUATION, ESCAPE_TEXT, escape_url, unikey
|
4
|
+
|
5
|
+
HTML_TAGNAME = r'[A-Za-z][A-Za-z0-9-]*'
|
6
|
+
HTML_ATTRIBUTES = (
|
7
|
+
r'(?:\s+[A-Za-z_:][A-Za-z0-9_.:-]*'
|
8
|
+
r'(?:\s*=\s*(?:[^ "\'=<>`]+|\'[^\']*?\'|"[^\"]*?"))?)*'
|
9
|
+
)
|
10
|
+
ESCAPE_CHAR = re.compile(r'\\([' + PUNCTUATION + r'])')
|
11
|
+
LINK_TEXT = r'(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?'
|
12
|
+
LINK_LABEL = r'(?:[^\\\[\]]|' + ESCAPE_TEXT + r'){0,1000}'
|
13
|
+
|
14
|
+
|
15
|
+
class InlineParser(ScannerParser):
|
16
|
+
ESCAPE = ESCAPE_TEXT
|
17
|
+
|
18
|
+
#: link or email syntax::
|
19
|
+
#:
|
20
|
+
#: <https://example.com>
|
21
|
+
AUTO_LINK = (
|
22
|
+
r'(?<!\\)(?:\\\\)*<([A-Za-z][A-Za-z0-9+.-]{1,31}:'
|
23
|
+
r"[^ <>]*?|[A-Za-z0-9.!#$%&'*+/=?^_`{|}~-]+@[A-Za-z0-9]"
|
24
|
+
r'(?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?'
|
25
|
+
r'(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*)>'
|
26
|
+
)
|
27
|
+
|
28
|
+
#: link or image syntax::
|
29
|
+
#:
|
30
|
+
#: [text](/link "title")
|
31
|
+
#: 
|
32
|
+
STD_LINK = (
|
33
|
+
r'!?\[(' + LINK_TEXT + r')\]\(\s*'
|
34
|
+
|
35
|
+
r'(<(?:\\[<>]?|[^\s<>\\])*>|'
|
36
|
+
r'(?:\\[()]?|\([^\s\x00-\x1f\\]*\)|[^\s\x00-\x1f()\\])*?)'
|
37
|
+
|
38
|
+
r'(?:\s+('
|
39
|
+
r'''"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)'''
|
40
|
+
r'))?\s*\)'
|
41
|
+
)
|
42
|
+
|
43
|
+
#: Get link from references. References are defined in DEF_LINK in blocks.
|
44
|
+
#: The syntax looks like::
|
45
|
+
#:
|
46
|
+
#: [an example][id]
|
47
|
+
#:
|
48
|
+
#: [id]: https://example.com "optional title"
|
49
|
+
REF_LINK = (
|
50
|
+
r'!?\[(' + LINK_TEXT + r')\]'
|
51
|
+
r'\[(' + LINK_LABEL + r')\]'
|
52
|
+
)
|
53
|
+
|
54
|
+
#: Simple form of reference link::
|
55
|
+
#:
|
56
|
+
#: [an example]
|
57
|
+
#:
|
58
|
+
#: [an example]: https://example.com "optional title"
|
59
|
+
REF_LINK2 = r'!?\[(' + LINK_LABEL + r')\]'
|
60
|
+
|
61
|
+
#: emphasis and strong * or _::
|
62
|
+
#:
|
63
|
+
#: *emphasis* **strong**
|
64
|
+
#: _emphasis_ __strong__
|
65
|
+
ASTERISK_EMPHASIS = (
|
66
|
+
r'(\*{1,2})(?=[^\s*])('
|
67
|
+
r'(?:\\[\\*]|[^*])*'
|
68
|
+
r'(?:' + ESCAPE_TEXT + r'|[^\s*]))\1'
|
69
|
+
)
|
70
|
+
UNDERSCORE_EMPHASIS = (
|
71
|
+
r'\b(_{1,2})(?=[^\s_])([\s\S]*?'
|
72
|
+
r'(?:' + ESCAPE_TEXT + r'|[^\s_]))\1'
|
73
|
+
r'(?!_|[^\s' + PUNCTUATION + r'])\b'
|
74
|
+
)
|
75
|
+
|
76
|
+
#: codespan with `::
|
77
|
+
#:
|
78
|
+
#: `code`
|
79
|
+
CODESPAN = (
|
80
|
+
r'(?<!\\|`)(?:\\\\)*(`+)(?!`)([\s\S]+?)(?<!`)\1(?!`)'
|
81
|
+
)
|
82
|
+
|
83
|
+
#: linebreak leaves two spaces at the end of line
|
84
|
+
LINEBREAK = r'(?:\\| {2,})\n(?!\s*$)'
|
85
|
+
|
86
|
+
INLINE_HTML = (
|
87
|
+
r'(?<!\\)<' + HTML_TAGNAME + HTML_ATTRIBUTES + r'\s*/?>|' # open tag
|
88
|
+
r'(?<!\\)</' + HTML_TAGNAME + r'\s*>|' # close tag
|
89
|
+
r'(?<!\\)<!--(?!>|->)(?:(?!--)[\s\S])+?(?<!-)-->|' # comment
|
90
|
+
r'(?<!\\)<\?[\s\S]+?\?>|'
|
91
|
+
r'(?<!\\)<![A-Z][\s\S]+?>|' # doctype
|
92
|
+
r'(?<!\\)<!\[CDATA[\s\S]+?\]\]>' # cdata
|
93
|
+
)
|
94
|
+
|
95
|
+
RULE_NAMES = (
|
96
|
+
'escape', 'inline_html', 'auto_link',
|
97
|
+
'std_link', 'ref_link', 'ref_link2',
|
98
|
+
'asterisk_emphasis', 'underscore_emphasis',
|
99
|
+
'codespan', 'linebreak',
|
100
|
+
)
|
101
|
+
|
102
|
+
def __init__(self, renderer, hard_wrap=False):
|
103
|
+
super(InlineParser, self).__init__()
|
104
|
+
if hard_wrap:
|
105
|
+
#: every new line becomes <br>
|
106
|
+
self.LINEBREAK = r' *\n(?!\s*$)'
|
107
|
+
self.renderer = renderer
|
108
|
+
rules = list(self.RULE_NAMES)
|
109
|
+
rules.remove('ref_link')
|
110
|
+
rules.remove('ref_link2')
|
111
|
+
self.ref_link_rules = rules
|
112
|
+
|
113
|
+
def parse_escape(self, m, state):
|
114
|
+
text = m.group(0)[1:]
|
115
|
+
return 'text', text
|
116
|
+
|
117
|
+
def parse_auto_link(self, m, state):
|
118
|
+
if state.get('_in_link'):
|
119
|
+
return 'text', m.group(0)
|
120
|
+
|
121
|
+
text = m.group(1)
|
122
|
+
schemes = ('mailto:', 'http://', 'https://')
|
123
|
+
if '@' in text and not text.lower().startswith(schemes):
|
124
|
+
link = 'mailto:' + text
|
125
|
+
else:
|
126
|
+
link = text
|
127
|
+
return 'link', escape_url(link), text
|
128
|
+
|
129
|
+
def parse_std_link(self, m, state):
|
130
|
+
line = m.group(0)
|
131
|
+
text = m.group(1)
|
132
|
+
link = ESCAPE_CHAR.sub(r'\1', m.group(2))
|
133
|
+
if link.startswith('<') and link.endswith('>'):
|
134
|
+
link = link[1:-1]
|
135
|
+
|
136
|
+
title = m.group(3)
|
137
|
+
if title:
|
138
|
+
title = ESCAPE_CHAR.sub(r'\1', title[1:-1])
|
139
|
+
|
140
|
+
if line[0] == '!':
|
141
|
+
return 'image', escape_url(link), text, title
|
142
|
+
|
143
|
+
return self.tokenize_link(line, link, text, title, state)
|
144
|
+
|
145
|
+
def parse_ref_link(self, m, state):
|
146
|
+
line = m.group(0)
|
147
|
+
text = m.group(1)
|
148
|
+
key = unikey(m.group(2) or text)
|
149
|
+
def_links = state.get('def_links')
|
150
|
+
if not def_links or key not in def_links:
|
151
|
+
return list(self._scan(line, state, self.ref_link_rules))
|
152
|
+
|
153
|
+
link, title = def_links.get(key)
|
154
|
+
link = ESCAPE_CHAR.sub(r'\1', link)
|
155
|
+
if title:
|
156
|
+
title = ESCAPE_CHAR.sub(r'\1', title)
|
157
|
+
|
158
|
+
if line[0] == '!':
|
159
|
+
return 'image', escape_url(link), text, title
|
160
|
+
|
161
|
+
return self.tokenize_link(line, link, text, title, state)
|
162
|
+
|
163
|
+
def parse_ref_link2(self, m, state):
|
164
|
+
return self.parse_ref_link(m, state)
|
165
|
+
|
166
|
+
def tokenize_link(self, line, link, text, title, state):
|
167
|
+
if state.get('_in_link'):
|
168
|
+
return 'text', line
|
169
|
+
state['_in_link'] = True
|
170
|
+
text = self.render(text, state)
|
171
|
+
state['_in_link'] = False
|
172
|
+
return 'link', escape_url(link), text, title
|
173
|
+
|
174
|
+
def parse_asterisk_emphasis(self, m, state):
|
175
|
+
return self.tokenize_emphasis(m, state)
|
176
|
+
|
177
|
+
def parse_underscore_emphasis(self, m, state):
|
178
|
+
return self.tokenize_emphasis(m, state)
|
179
|
+
|
180
|
+
def tokenize_emphasis(self, m, state):
|
181
|
+
marker = m.group(1)
|
182
|
+
text = m.group(2)
|
183
|
+
if len(marker) == 1:
|
184
|
+
return 'emphasis', self.render(text, state)
|
185
|
+
return 'strong', self.render(text, state)
|
186
|
+
|
187
|
+
def parse_codespan(self, m, state):
|
188
|
+
code = re.sub(r'[ \n]+', ' ', m.group(2).strip())
|
189
|
+
return 'codespan', code
|
190
|
+
|
191
|
+
def parse_linebreak(self, m, state):
|
192
|
+
return 'linebreak',
|
193
|
+
|
194
|
+
def parse_inline_html(self, m, state):
|
195
|
+
html = m.group(0)
|
196
|
+
return 'inline_html', html
|
197
|
+
|
198
|
+
def parse_text(self, text, state):
|
199
|
+
return 'text', text
|
200
|
+
|
201
|
+
def parse(self, s, state, rules=None):
|
202
|
+
if rules is None:
|
203
|
+
rules = self.rules
|
204
|
+
|
205
|
+
tokens = (
|
206
|
+
self.renderer._get_method(t[0])(*t[1:])
|
207
|
+
for t in self._scan(s, state, rules)
|
208
|
+
)
|
209
|
+
return tokens
|
210
|
+
|
211
|
+
def render(self, s, state, rules=None):
|
212
|
+
tokens = self.parse(s, state, rules)
|
213
|
+
return self.renderer.finalize(tokens)
|
214
|
+
|
215
|
+
def __call__(self, s, state):
|
216
|
+
return self.render(s, state)
|