codekingpro/portable-devtools
114k
1"""Parse link title"""2 3from ..common.utils import charCodeAt, unescapeAll4 5 6class _State:7 __slots__ = ("can_continue", "marker", "ok", "pos", "str")8 9 def __init__(self) -> None:10 self.ok = False11 """if `true`, this is a valid link title"""12 self.can_continue = False13 """if `true`, this link can be continued on the next line"""14 self.pos = 015 """if `ok`, it's the position of the first character after the closing marker"""16 self.str = ""17 """if `ok`, it's the unescaped title"""18 self.marker = 019 """expected closing marker character code"""20 21 def __str__(self) -> str:22 return self.str23 24 25def parseLinkTitle(26 string: str, start: int, maximum: int, prev_state: _State | None = None27) -> _State:28 """Parse link title within `str` in [start, max] range,29 or continue previous parsing if `prev_state` is defined (equal to result of last execution).30 """31 pos = start32 state = _State()33 34 if prev_state is not None:35 # this is a continuation of a previous parseLinkTitle call on the next line,36 # used in reference links only37 state.str = prev_state.str38 state.marker = prev_state.marker39 else:40 if pos >= maximum:41 return state42 43 marker = charCodeAt(string, pos)44 45 # /* " */ /* ' */ /* ( */46 if marker != 0x22 and marker != 0x27 and marker != 0x28:47 return state48 49 start += 150 pos += 151 52 # if opening marker is "(", switch it to closing marker ")"53 if marker == 0x28:54 marker = 0x2955 56 state.marker = marker57 58 while pos < maximum:59 code = charCodeAt(string, pos)60 if code == state.marker:61 state.pos = pos + 162 state.str += unescapeAll(string[start:pos])63 state.ok = True64 return state65 elif code == 0x28 and state.marker == 0x29: # /* ( */ /* ) */66 return state67 elif code == 0x5C and pos + 1 < maximum: # /* \ */68 pos += 169 70 pos += 171 72 # no closing marker found, but this link title may continue on the next line (for references)73 state.can_continue = True74 state.str += unescapeAll(string[start:pos])75 return state76 