diff --git a/src/interactive-window/editor-integration/cellFactory.unit.test.ts b/src/interactive-window/editor-integration/cellFactory.unit.test.ts index 473c32ae64d..dbb92d8fb76 100644 --- a/src/interactive-window/editor-integration/cellFactory.unit.test.ts +++ b/src/interactive-window/editor-integration/cellFactory.unit.test.ts @@ -25,11 +25,13 @@ suite('CellFactory', () => { cells = generateCells(undefined, "#%% [markdown]\n'''\n# a\nb\n'''", true); assert.equal(cells.length, 1, 'Markdown cell multline failed'); assert.equal(cells[0].languageId, 'markdown', 'Markdown cell not generated'); - assert.equal(splitMarkdown(cells[0].value).length, 3, 'Lines for markdown not emitted'); + assert.equal(splitMarkdown(cells[0].value).length, 2, 'Lines for markdown not emitted'); cells = generateCells(undefined, '#%% [markdown]\n"""\n# a\nb\n"""', true); assert.equal(cells.length, 1, 'Markdown cell multline failed'); assert.equal(cells[0].languageId, 'markdown', 'Markdown cell not generated'); - assert.equal(splitMarkdown(cells[0].value).length, 3, 'Lines for markdown not emitted'); + assert.equal(splitMarkdown(cells[0].value).length, 2, 'Lines for markdown not emitted'); + // Test that line breaks are preserved correctly - no empty line between # a and b in the input + assert.equal(cells[0].value, '# a\nb', 'Markdown content should not add extra line breaks'); cells = generateCells(undefined, '#%% \n"""\n# a\nb\n"""', true); assert.equal(cells.length, 1, 'Code cell multline failed'); assert.equal(cells[0].languageId, 'python', 'Code cell not generated'); @@ -151,6 +153,31 @@ class Pizza(object): assert.equal(splitCode(cells[1].value).length, 7, 'Lines for code not emitted'); assert.equal(splitCode(cells[1].value)[3], ' self.toppings = toppings', 'Lines for cell not emitted'); + // Test for issue #9620 - line breaks in multi-line comments should be preserved + // eslint-disable-next-line no-multi-str + const multilineMarkdownWithBreaks = `#%% [markdown] + +""" +# H1 Title + +description 1 + +- item 1 + - item 2 +- item 3 + +description 2 + +- item 4 + - item 5 +- item 6 +"""`; + cells = generateCells(undefined, multilineMarkdownWithBreaks, true); + assert.equal(cells.length, 1, 'Markdown cell with line breaks failed'); + assert.equal(cells[0].languageId, 'markdown', 'Markdown cell not generated'); + const expectedContent = '# H1 Title\n\ndescription 1\n\n- item 1\n - item 2\n- item 3\n\ndescription 2\n\n- item 4\n - item 5\n- item 6'; + assert.equal(cells[0].value, expectedContent, 'Markdown content should preserve line breaks and indentation correctly'); + // Non comments tests let nonComments = stripComments(multilineCode); assert.ok(nonComments.startsWith('myvar = """ # Lorem Ipsum'), 'Variable set to multiline string not working'); diff --git a/src/platform/common/utils.ts b/src/platform/common/utils.ts index 612644e7f4e..c0bdffb6545 100644 --- a/src/platform/common/utils.ts +++ b/src/platform/common/utils.ts @@ -381,7 +381,7 @@ function extractComments(lines: string[]): string[] { export function generateMarkdownFromCodeLines(lines: string[]) { // Generate markdown by stripping out the comments and markdown header - return appendLineFeed(extractComments(lines.slice(lines.length > 1 ? 1 : 0))); + return extractComments(lines.slice(lines.length > 1 ? 1 : 0)); } export function removeLinesFromFrontAndBackNoConcat(lines: string[]): string[] { diff --git a/src/platform/common/utils.unit.test.ts b/src/platform/common/utils.unit.test.ts index 9d5a87b6aee..2420fdc003a 100644 --- a/src/platform/common/utils.unit.test.ts +++ b/src/platform/common/utils.unit.test.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. import { assert } from 'chai'; -import { formatStreamText } from './utils'; +import { formatStreamText, generateMarkdownFromCodeLines } from './utils'; suite('Common Tests', () => { test('formatting stream text', async () => { @@ -15,4 +15,59 @@ suite('Common Tests', () => { assert.equal(formatStreamText('\rExecute\rExecute\nExecute 8\rExecute 9\r\r'), 'Execute\nExecute 9'); assert.equal(formatStreamText('\rExecute\rExecute\nExecute 10\rExecute 11\r\n'), 'Execute\nExecute 11\n'); }); + + test('generateMarkdownFromCodeLines preserves line breaks correctly', () => { + // Test multi-line markdown with empty lines + const lines1 = [ + '#%% [markdown]', + '', + '"""', + '# H1 Title', + '', + 'description 1', + '', + '- item 1', + ' - item 2', + '- item 3', + '"""' + ]; + + const result1 = generateMarkdownFromCodeLines(lines1); + const markdown1 = result1.join('\n'); + const expected1 = '# H1 Title\n\ndescription 1\n\n- item 1\n - item 2\n- item 3'; + assert.equal(markdown1, expected1, 'Multi-line markdown with empty lines should preserve line breaks'); + + // Test code block in markdown + const lines2 = [ + '#%% [markdown]', + '', + '"""', + 'Writing code blocks in markdown:', + '', + '```shell', + '# Comment 1', + '$ ls ', + '', + '# Comment 2', + '$ ls -lh', + '```', + '"""' + ]; + + const result2 = generateMarkdownFromCodeLines(lines2); + const markdown2 = result2.join('\n'); + const expected2 = 'Writing code blocks in markdown:\n\n```shell\n# Comment 1\n$ ls \n\n# Comment 2\n$ ls -lh\n```'; + assert.equal(markdown2, expected2, 'Code blocks in markdown should preserve line breaks'); + + // Test single line markdown + const lines3 = [ + '#%% [markdown]', + '"""Single line markdown"""' + ]; + + const result3 = generateMarkdownFromCodeLines(lines3); + const markdown3 = result3.join('\n'); + const expected3 = 'Single line markdown'; + assert.equal(markdown3, expected3, 'Single line markdown should work correctly'); + }); });