|
24 | 24 | MessageEntityCode as Code, |
25 | 25 | MessageEntityTextUrl as Url, |
26 | 26 | MessageEntityPre as Pre, |
| 27 | + MessageEntityMentionName as MentionInvalid, |
27 | 28 | InputMessageEntityMentionName as Mention |
28 | 29 | ) |
29 | 30 | from . import utils |
30 | 31 |
|
31 | 32 |
|
32 | 33 | class Markdown: |
33 | | - INLINE_DELIMITERS = { |
34 | | - "**": Bold, |
35 | | - "__": Italic, |
36 | | - "`": Code |
37 | | - } |
| 34 | + BOLD_DELIMITER = "**" |
| 35 | + ITALIC_DELIMITER = "__" |
| 36 | + CODE_DELIMITER = "`" |
| 37 | + PRE_DELIMITER = "```" |
38 | 38 |
|
39 | | - # ``` python |
40 | | - # for i in range(10): |
41 | | - # print(i) |
42 | | - # ``` |
43 | | - PRE_RE = r"(?P<pre>```(?P<lang>.*)\n(?P<code>(.|\n)*)\n```)" |
44 | | - |
45 | | - # [url](github.com) |
46 | | - URL_RE = r"(?P<url>(\[(?P<url_text>.+?)\]\((?P<url_path>.+?)\)))" |
47 | | - |
48 | | - # [name](tg://user?id=123456789) |
49 | | - MENTION_RE = r"(?P<mention>(\[(?P<mention_text>.+?)\]\(tg:\/\/user\?id=(?P<user_id>\d+?)\)))" |
50 | | - |
51 | | - # **bold** |
52 | | - # __italic__ |
53 | | - # `code` |
54 | | - INLINE_RE = r"(?P<inline>(?P<start_delimiter>{d})(?P<body>.+?)(?P<end_delimiter>{d}))".format( |
| 39 | + MARKDOWN_RE = re.compile(r"```([\w ]*)\n([\w\W]*)(?:\n|)```|\[([^[(]+)\]\(([^])]+)\)|({d})(.+?)\5".format( |
55 | 40 | d="|".join( |
56 | 41 | ["".join(i) for i in [ |
57 | 42 | ["\{}".format(j) for j in i] |
58 | | - for i in sorted( # Sort delimiters by length |
59 | | - INLINE_DELIMITERS.keys(), |
60 | | - key=lambda k: len(k), # Or: key=len |
61 | | - reverse=True |
62 | | - ) |
| 43 | + for i in [ |
| 44 | + PRE_DELIMITER, |
| 45 | + CODE_DELIMITER, |
| 46 | + ITALIC_DELIMITER, |
| 47 | + BOLD_DELIMITER |
| 48 | + ] |
63 | 49 | ]] |
64 | 50 | ) |
65 | | - ) |
66 | | - |
67 | | - MARKDOWN_RE = re.compile("|".join([PRE_RE, MENTION_RE, URL_RE, INLINE_RE])) |
| 51 | + )) |
| 52 | + MENTION_RE = re.compile(r"tg://user\?id=(\d+)") |
68 | 53 |
|
69 | | - def __init__(self, peers_by_id): |
| 54 | + def __init__(self, peers_by_id: dict): |
70 | 55 | self.peers_by_id = peers_by_id |
71 | 56 |
|
72 | | - def parse(self, text): |
| 57 | + def parse(self, message: str): |
73 | 58 | entities = [] |
74 | | - text = utils.add_surrogates(text) |
| 59 | + message = utils.add_surrogates(message).strip() |
75 | 60 | offset = 0 |
76 | 61 |
|
77 | | - for match in self.MARKDOWN_RE.finditer(text): |
| 62 | + for match in self.MARKDOWN_RE.finditer(message): |
78 | 63 | start = match.start() - offset |
79 | | - |
80 | | - if match.group("pre"): |
81 | | - pattern = match.group("pre") |
82 | | - lang = match.group("lang") |
83 | | - replace = match.group("code") |
84 | | - entity = Pre(start, len(replace), lang.strip()) |
85 | | - offset += len(lang) + 8 |
86 | | - elif match.group("url"): |
87 | | - pattern = match.group("url") |
88 | | - replace = match.group("url_text") |
89 | | - path = match.group("url_path") |
90 | | - entity = Url(start, len(replace), path) |
91 | | - offset += len(path) + 4 |
92 | | - elif match.group("mention"): |
93 | | - pattern = match.group("mention") |
94 | | - replace = match.group("mention_text") |
95 | | - user_id = match.group("user_id") |
96 | | - entity = Mention(start, len(replace), self.peers_by_id[int(user_id)]) |
97 | | - offset += len(user_id) + 17 |
98 | | - elif match.group("inline"): |
99 | | - pattern = match.group("inline") |
100 | | - replace = match.group("body") |
101 | | - start_delimiter = match.group("start_delimiter") |
102 | | - end_delimiter = match.group("end_delimiter") |
103 | | - |
104 | | - if start_delimiter != end_delimiter: |
| 64 | + lang, pre, text, url, style, body = match.groups() |
| 65 | + |
| 66 | + if pre: |
| 67 | + body = pre = pre.strip() |
| 68 | + entity = Pre(start, len(pre), lang.strip() or "") |
| 69 | + offset += len(lang) + len(self.PRE_DELIMITER) * 2 |
| 70 | + elif url: |
| 71 | + mention = self.MENTION_RE.match(url) |
| 72 | + |
| 73 | + if mention: |
| 74 | + user_id = int(mention.group(1)) |
| 75 | + input_user = self.peers_by_id.get(user_id, None) |
| 76 | + |
| 77 | + entity = ( |
| 78 | + Mention(start, len(text), input_user) |
| 79 | + if input_user |
| 80 | + else MentionInvalid(start, len(text), user_id) |
| 81 | + ) |
| 82 | + else: |
| 83 | + entity = Url(start, len(text), url) |
| 84 | + |
| 85 | + body = text |
| 86 | + offset += len(url) + 4 |
| 87 | + else: |
| 88 | + if style == self.BOLD_DELIMITER: |
| 89 | + entity = Bold(start, len(body)) |
| 90 | + elif style == self.ITALIC_DELIMITER: |
| 91 | + entity = Italic(start, len(body)) |
| 92 | + elif style == self.CODE_DELIMITER: |
| 93 | + entity = Code(start, len(body)) |
| 94 | + elif style == self.PRE_DELIMITER: |
| 95 | + entity = Pre(start, len(body), "") |
| 96 | + else: |
105 | 97 | continue |
106 | 98 |
|
107 | | - entity = self.INLINE_DELIMITERS[start_delimiter](start, len(replace)) |
108 | | - offset += len(start_delimiter) * 2 |
109 | | - else: |
110 | | - continue |
| 99 | + offset += len(style) * 2 |
111 | 100 |
|
112 | 101 | entities.append(entity) |
113 | | - text = text.replace(pattern, replace) |
| 102 | + message = message.replace(match.group(), body) |
114 | 103 |
|
115 | 104 | return dict( |
116 | | - message=utils.remove_surrogates(text), |
| 105 | + message=utils.remove_surrogates(message), |
117 | 106 | entities=entities |
118 | 107 | ) |
0 commit comments