| ... | @@ -35,6 +35,7 @@ interface TailState { | ... | @@ -35,6 +35,7 @@ interface TailState { |
| 35 | delims: DelimState[]; | 35 | delims: DelimState[]; |
| 36 | exclusive: ExclusiveState | null; | 36 | exclusive: ExclusiveState | null; |
| 37 | links: LinkState[]; | 37 | links: LinkState[]; |
| | 38 | pendingDelim: DelimState | null; |
| 38 | } | 39 | } |
| 39 | | 40 | |
| 40 | const NESTABLE_DELIMS = new Set<DelimToken>(["*", "**", "_", "__"]); | 41 | const NESTABLE_DELIMS = new Set<DelimToken>(["*", "**", "_", "__"]); |
| ... | @@ -45,6 +46,7 @@ function parseTail(tail: string): TailState { | ... | @@ -45,6 +46,7 @@ function parseTail(tail: string): TailState { |
| 45 | delims: [], | 46 | delims: [], |
| 46 | exclusive: null, | 47 | exclusive: null, |
| 47 | links: [], | 48 | links: [], |
| | 49 | pendingDelim: null, |
| 48 | }; | 50 | }; |
| 49 | | 51 | |
| 50 | for (let i = 0; i < tail.length; i++) { | 52 | for (let i = 0; i < tail.length; i++) { |
| ... | @@ -179,6 +181,11 @@ function consumeDelim(state: TailState, tail: string, start: number) { | ... | @@ -179,6 +181,11 @@ function consumeDelim(state: TailState, tail: string, start: number) { |
| 179 | return start + token.length; | 181 | return start + token.length; |
| 180 | } | 182 | } |
| 181 | | 183 | |
| | 184 | if (start + token.length === tail.length) { |
| | 185 | state.pendingDelim = { start, token }; |
| | 186 | return start + token.length; |
| | 187 | } |
| | 188 | |
| 182 | if (!canOpenDelim(tail, start, token)) return start + token.length; | 189 | if (!canOpenDelim(tail, start, token)) return start + token.length; |
| 183 | | 190 | |
| 184 | state.delims.push({ start, token }); | 191 | state.delims.push({ start, token }); |
| ... | @@ -277,14 +284,16 @@ function renderTail(tail: string, state: TailState) { | ... | @@ -277,14 +284,16 @@ function renderTail(tail: string, state: TailState) { |
| 277 | if (nestedClosers) return appendCloser(tail, nestedClosers); | 284 | if (nestedClosers) return appendCloser(tail, nestedClosers); |
| 278 | | 285 | |
| 279 | const open = findLastOpen(state); | 286 | const open = findLastOpen(state); |
| 280 | if (!open) return tail; | 287 | if (!open) return state.pendingDelim ? tail.slice(0, state.pendingDelim.start) : tail; |
| 281 | | 288 | |
| 282 | if (open.kind === "delim") { | 289 | if (open.kind === "delim") { |
| 283 | if (!hasContentAfter(tail, open.start, open.token.length)) return tail; | 290 | if (!hasContentAfter(tail, open.start, open.token.length)) return tail.slice(0, open.start); |
| 284 | return appendCloserBeforeTrailingInlineWhitespace(tail, open.token); | 291 | return appendCloserBeforeTrailingInlineWhitespace(tail, open.token); |
| 285 | } | 292 | } |
| 286 | | 293 | |
| 287 | if (!hasContentAfter(tail, open.start, open.token.length)) return tail; | 294 | if (!hasContentAfter(tail, open.start, open.token.length)) { |
| | 295 | return open.kind === "fence" ? tail : tail.slice(0, open.start); |
| | 296 | } |
| 288 | if (open.kind === "fence") return tail; | 297 | if (open.kind === "fence") return tail; |
| 289 | if (open.kind === "code") return appendCloser(tail, open.token); | 298 | if (open.kind === "code") return appendCloser(tail, open.token); |
| 290 | if (open.token === "$$") return appendCloser(tail, (tail.endsWith("\n") ? "" : "\n") + "$$"); | 299 | if (open.token === "$$") return appendCloser(tail, (tail.endsWith("\n") ? "" : "\n") + "$$"); |
| ... | @@ -296,7 +305,7 @@ function renderOpenLink(tail: string, state: LinkState) { | ... | @@ -296,7 +305,7 @@ function renderOpenLink(tail: string, state: LinkState) { |
| 296 | const before = tail.slice(0, state.start); | 305 | const before = tail.slice(0, state.start); |
| 297 | | 306 | |
| 298 | if (state.phase === "text") { | 307 | if (state.phase === "text") { |
| 299 | if (!hasContentAfter(tail, state.start, 1)) return tail; | 308 | if (!hasContentAfter(tail, state.start, 1)) return before; |
| 300 | return before + tail.slice(state.start + 1); | 309 | return before + tail.slice(state.start + 1); |
| 301 | } | 310 | } |
| 302 | | 311 | |