Skip to content

Commit e9f1d6a

Browse files
authored
Fix some markdown streaming issues (microsoft#252816)
* Fix incomplete markdown rendering issue with trailing spaces * Fix issue with trailing dash
1 parent d80d107 commit e9f1d6a

File tree

2 files changed

+38
-9
lines changed

2 files changed

+38
-9
lines changed

src/vs/base/browser/markdownRenderer.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -827,9 +827,9 @@ function completeListItemPattern(list: marked.Tokens.List): marked.Tokens.List |
827827
return newList;
828828
}
829829

830-
function completeHeading(token: marked.Tokens.Heading): marked.TokensList | void {
830+
function completeHeading(token: marked.Tokens.Heading, fullRawText: string): marked.TokensList | void {
831831
if (token.raw.match(/-\s*$/)) {
832-
return marked.lexer(token.raw + '  ');
832+
return marked.lexer(fullRawText + '  ');
833833
}
834834
}
835835

@@ -887,7 +887,7 @@ function fillInIncompleteTokensOnce(tokens: marked.TokensList): marked.TokensLis
887887
}
888888

889889
if (lastToken?.type === 'heading') {
890-
const completeTokens = completeHeading(lastToken as marked.Tokens.Heading);
890+
const completeTokens = completeHeading(lastToken as marked.Tokens.Heading, mergeRawTokenText(tokens));
891891
if (completeTokens) {
892892
return completeTokens;
893893
}
@@ -910,15 +910,15 @@ function completeUnderscore(tokens: marked.Token): marked.Token {
910910
}
911911

912912
function completeLinkTarget(tokens: marked.Token): marked.Token {
913-
return completeWithString(tokens, ')');
913+
return completeWithString(tokens, ')', false);
914914
}
915915

916916
function completeLinkTargetArg(tokens: marked.Token): marked.Token {
917-
return completeWithString(tokens, '")');
917+
return completeWithString(tokens, '")', false);
918918
}
919919

920920
function completeLinkText(tokens: marked.Token): marked.Token {
921-
return completeWithString(tokens, '](https://microsoft.com)');
921+
return completeWithString(tokens, '](https://microsoft.com)', false);
922922
}
923923

924924
function completeDoublestar(tokens: marked.Token): marked.Token {
@@ -929,12 +929,13 @@ function completeDoubleUnderscore(tokens: marked.Token): marked.Token {
929929
return completeWithString(tokens, '__');
930930
}
931931

932-
function completeWithString(tokens: marked.Token[] | marked.Token, closingString: string): marked.Token {
932+
function completeWithString(tokens: marked.Token[] | marked.Token, closingString: string, shouldTrim = true): marked.Token {
933933
const mergedRawText = mergeRawTokenText(Array.isArray(tokens) ? tokens : [tokens]);
934934

935935
// If it was completed correctly, this should be a single token.
936936
// Expecting either a Paragraph or a List
937-
return marked.lexer(mergedRawText + closingString)[0] as marked.Token;
937+
const trimmedRawText = shouldTrim ? mergedRawText.trimEnd() : mergedRawText;
938+
return marked.lexer(trimmedRawText + closingString)[0] as marked.Token;
938939
}
939940

940941
function completeTable(tokens: marked.Token[]): marked.Token[] | undefined {

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

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,15 @@ suite('MarkdownRenderer', () => {
511511
assert.deepStrictEqual(newTokens, completeTokens);
512512
});
513513

514+
test(`${name} with trailing space`, () => {
515+
const incomplete = `some text and ${delimiter}some code `;
516+
const tokens = marked.marked.lexer(incomplete);
517+
const newTokens = fillInIncompleteTokens(tokens);
518+
519+
const completeTokens = marked.marked.lexer(incomplete.trimEnd() + delimiter);
520+
assert.deepStrictEqual(newTokens, completeTokens);
521+
});
522+
514523
test(`single loose "${delimiter}"`, () => {
515524
const text = `some text and ${delimiter}by itself\nmore text here`;
516525
const tokens = marked.marked.lexer(text);
@@ -714,14 +723,23 @@ suite('MarkdownRenderer', () => {
714723
assert.deepStrictEqual(newTokens, completeTokens);
715724
});
716725

717-
test('text with start of list', () => {
726+
test('text with start of list is not a heading', () => {
718727
const incomplete = `hello\n- `;
719728
const tokens = marked.marked.lexer(incomplete);
720729
const newTokens = fillInIncompleteTokens(tokens);
721730

722731
const completeTokens = marked.marked.lexer(incomplete + '  ');
723732
assert.deepStrictEqual(newTokens, completeTokens);
724733
});
734+
735+
test('even more text with start of list is not a heading', () => {
736+
const incomplete = `# hello\n\ntext\n-`;
737+
const tokens = marked.marked.lexer(incomplete);
738+
const newTokens = fillInIncompleteTokens(tokens);
739+
740+
const completeTokens = marked.marked.lexer(incomplete + '  ');
741+
assert.deepStrictEqual(newTokens, completeTokens);
742+
});
725743
});
726744

727745
suite('codespan', () => {
@@ -779,6 +797,16 @@ suite('MarkdownRenderer', () => {
779797
const completeTokens = marked.marked.lexer(text + '**');
780798
assert.deepStrictEqual(newTokens, completeTokens);
781799
});
800+
801+
// TODO trim these patterns from end
802+
test.skip(`ending in doublestar`, () => {
803+
const incomplete = `some text and **`;
804+
const tokens = marked.marked.lexer(incomplete);
805+
const newTokens = fillInIncompleteTokens(tokens);
806+
807+
const completeTokens = marked.marked.lexer(incomplete.trimEnd() + '**');
808+
assert.deepStrictEqual(newTokens, completeTokens);
809+
});
782810
});
783811

784812
suite('underscore', () => {

0 commit comments

Comments
 (0)