Skip to content

Commit 5c0d2f4

Browse files
authored
Incomplete markdown patching for codeblocks with >3 backticks (microsoft#203925)
* Fix incomplete markdown handling of links with codespans * Incomplete markdown patching for codeblocks with >3 backticks
1 parent 790e20c commit 5c0d2f4

File tree

2 files changed

+55
-5
lines changed

2 files changed

+55
-5
lines changed

src/vs/base/browser/markdownRenderer.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,9 @@ function completeSingleLinePattern(token: marked.Tokens.ListItem | marked.Tokens
605605
return completeLinkTargetArg(token);
606606
}
607607
return completeLinkTarget(token);
608-
} else if (lastLine.match(/(^|\s)\[\w/)) {
608+
} else if (hasStartOfLinkTarget(lastLine)) {
609+
return completeLinkTarget(token);
610+
} else if (lastLine.match(/(^|\s)\[\w/) && !token.tokens.slice(i + 1).some(t => hasStartOfLinkTarget(t.raw))) {
609611
return completeLinkText(token);
610612
}
611613
}
@@ -614,6 +616,10 @@ function completeSingleLinePattern(token: marked.Tokens.ListItem | marked.Tokens
614616
return undefined;
615617
}
616618

619+
function hasStartOfLinkTarget(str: string): boolean {
620+
return !!str.match(/^[^\[]*\]\([^\)]*$/);
621+
}
622+
617623
// function completeListItemPattern(token: marked.Tokens.List): marked.Tokens.List | undefined {
618624
// // Patch up this one list item
619625
// const lastItem = token.items[token.items.length - 1];
@@ -639,9 +645,11 @@ export function fillInIncompleteTokens(tokens: marked.TokensList): marked.Tokens
639645
let newTokens: marked.Token[] | undefined;
640646
for (i = 0; i < tokens.length; i++) {
641647
const token = tokens[i];
642-
if (token.type === 'paragraph' && token.raw.match(/(\n|^)```/)) {
648+
let codeblockStart: RegExpMatchArray | null;
649+
if (token.type === 'paragraph' && (codeblockStart = token.raw.match(/(\n|^)(````*)/))) {
650+
const codeblockLead = codeblockStart[2];
643651
// If the code block was complete, it would be in a type='code'
644-
newTokens = completeCodeBlock(tokens.slice(i));
652+
newTokens = completeCodeBlock(tokens.slice(i), codeblockLead);
645653
break;
646654
}
647655

@@ -680,9 +688,9 @@ export function fillInIncompleteTokens(tokens: marked.TokensList): marked.Tokens
680688
return tokens;
681689
}
682690

683-
function completeCodeBlock(tokens: marked.Token[]): marked.Token[] {
691+
function completeCodeBlock(tokens: marked.Token[], leader: string): marked.Token[] {
684692
const mergedRawText = mergeRawTokenText(tokens);
685-
return marked.lexer(mergedRawText + '\n```');
693+
return marked.lexer(mergedRawText + `\n${leader}`);
686694
}
687695

688696
function completeCodespan(token: marked.Token): marked.Token {

src/vs/base/test/browser/markdownRenderer.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,30 @@ suite('MarkdownRenderer', () => {
513513
const completeCodeblockTokens = marked.lexer(incompleteCodeblock + '\n```');
514514
assert.deepStrictEqual(newTokens, completeCodeblockTokens);
515515
});
516+
517+
test('code block header with more backticks', () => {
518+
const incompleteCodeblock = 'some text\n`````js\nconst';
519+
const tokens = marked.lexer(incompleteCodeblock);
520+
const newTokens = fillInIncompleteTokens(tokens);
521+
522+
const completeCodeblockTokens = marked.lexer(incompleteCodeblock + '\n`````');
523+
assert.deepStrictEqual(newTokens, completeCodeblockTokens);
524+
});
525+
526+
test('code block header containing codeblock', () => {
527+
const incompleteCodeblock = `some text
528+
\`\`\`\`\`js
529+
const x = 1;
530+
\`\`\`
531+
const y = 2;
532+
\`\`\`
533+
// foo`;
534+
const tokens = marked.lexer(incompleteCodeblock);
535+
const newTokens = fillInIncompleteTokens(tokens);
536+
537+
const completeCodeblockTokens = marked.lexer(incompleteCodeblock + '\n`````');
538+
assert.deepStrictEqual(newTokens, completeCodeblockTokens);
539+
});
516540
});
517541

518542
function simpleMarkdownTestSuite(name: string, delimiter: string): void {
@@ -687,6 +711,24 @@ suite('MarkdownRenderer', () => {
687711
assert.deepStrictEqual(newTokens, completeTokens);
688712
});
689713

714+
test('incomplete link target with extra stuff', () => {
715+
const incomplete = '[before `text` after](http://microsoft.com';
716+
const tokens = marked.lexer(incomplete);
717+
const newTokens = fillInIncompleteTokens(tokens);
718+
719+
const completeTokens = marked.lexer(incomplete + ')');
720+
assert.deepStrictEqual(newTokens, completeTokens);
721+
});
722+
723+
test('incomplete link target with extra stuff and arg', () => {
724+
const incomplete = '[before `text` after](http://microsoft.com "more text ';
725+
const tokens = marked.lexer(incomplete);
726+
const newTokens = fillInIncompleteTokens(tokens);
727+
728+
const completeTokens = marked.lexer(incomplete + ')');
729+
assert.deepStrictEqual(newTokens, completeTokens);
730+
});
731+
690732
test('incomplete link target with arg', () => {
691733
const incomplete = 'foo [text](http://microsoft.com "more text here ';
692734
const tokens = marked.lexer(incomplete);

0 commit comments

Comments
 (0)