diff --git a/src/vs/base/common/htmlParser.ts b/src/vs/base/common/htmlParser.ts index 138436afa17..96ca88aaab1 100644 --- a/src/vs/base/common/htmlParser.ts +++ b/src/vs/base/common/htmlParser.ts @@ -84,6 +84,18 @@ const voidElements: Record = { 'wbr': true }; +/** + * Quick lookup table for table elements. + */ +const tableElements: Record = { + 'table': true, + 'thead': true, + 'tbody': true, + 'tfoot': true, + 'tr': true, + 'colgroup': true +}; + /** * Checks if a node is nested inside a
 element.
  * In 
 elements, whitespace must be preserved per HTML spec.
@@ -107,6 +119,19 @@ function isInsidePreElement(node: HtmlNode | undefined): boolean {
 	return false;
 }
 
+/**
+ * Checks if a node is a table elemen
+ *
+ * @param node The node to check (typically parent of a text node)
+ * @returns true if node is a table element
+ */
+function isTableElement(node: HtmlNode | undefined): boolean {
+	if (!node || !node.name) {
+		return false;
+	}
+	return tableElements[node.name] === true;
+}
+
 /**
  * Parses a single HTML tag.
  *
@@ -321,14 +346,22 @@ export function parseHtml(html: string): Array {
 				nextChar &&
 				nextChar !== '<'
 			) {
-				// This is a text node; add it as a child node
-				if (current.children === undefined) {
-					current.children = [];
+				const textContent = html.slice(start, html.indexOf('<', start));
+				const isWhitespace = whitespaceRE.test(textContent);
+				// Check if we are in a table element context with whitespace-only text node
+				const whitespaceInTable = isWhitespace && isTableElement(current);
+
+				// Don't add whitespace-only text nodes if they are inside table elements
+				if (!whitespaceInTable) {
+					// This is a text node; add it as a child node
+					if (current.children === undefined) {
+						current.children = [];
+					}
+					current.children.push({
+						type: 'text',
+						content: decode(textContent),
+					});
 				}
-				current.children.push({
-					type: 'text',
-					content: decode(html.slice(start, html.indexOf('<', start))),
-				});
 			}
 
 			// if we're at root, push new base node
@@ -383,11 +416,14 @@ export function parseHtml(html: string): Array {
 					content = ' ';
 				}
 
-				// Don't add whitespace-only text nodes if they would be trailing text nodes
-				// or if they would be leading whitespace-only text nodes:
+				// Check if we are in a table element context with whitespace-only text node
+				const whitespaceInTable = whitespaceRE.test(content) && isTableElement(current);
+
+				// Don't add whitespace-only text nodes if they would be: trailing text nodes
+				// leading whitespace-only text nodes, or inside table elements:
 				//  * end > -1 indicates this is not a trailing text node
 				//  * leading node is when level is -1 and parent has length 0
-				if ((end > -1 && level + parent.length >= 0) || content !== ' ') {
+				if (!whitespaceInTable && ((end > -1 && level + parent.length >= 0) || content !== ' ')) {
 					parent.push({
 						type: 'text',
 						parent: current,
diff --git a/src/vs/workbench/contrib/positronNotebook/browser/markdownRenderer.ts b/src/vs/workbench/contrib/positronNotebook/browser/markdownRenderer.ts
index 05a86394987..d0634ba2a87 100644
--- a/src/vs/workbench/contrib/positronNotebook/browser/markdownRenderer.ts
+++ b/src/vs/workbench/contrib/positronNotebook/browser/markdownRenderer.ts
@@ -108,7 +108,10 @@ function markedHighlight(options: marked.MarkedOptions & {
 			code({ text, lang, escaped }: marked.Tokens.Code) {
 				const classAttr = lang ? ` class="language-${escape(lang)}"` : '';
 				text = text.replace(/\n$/, '');
-				return `
${escaped ? text : escape(text)}\n
`; + // Note: We intentionally omit the trailing \n that marked-highlight includes. + // The \n is preserved by
's default white-space:pre behavior
+				// this causes visible whitespace at the bottom of code blocks in Positron notebooks.
+				return `
${escaped ? text : escape(text)}
`; }, }, }; diff --git a/src/vs/workbench/contrib/positronNotebook/browser/notebookCells/Markdown.css b/src/vs/workbench/contrib/positronNotebook/browser/notebookCells/Markdown.css index c7206821720..e8e09ae8b35 100644 --- a/src/vs/workbench/contrib/positronNotebook/browser/notebookCells/Markdown.css +++ b/src/vs/workbench/contrib/positronNotebook/browser/notebookCells/Markdown.css @@ -101,6 +101,7 @@ table { border-collapse: collapse; border-spacing: 0; + margin-bottom: 0.7em; } table th, @@ -125,21 +126,35 @@ } blockquote { - margin: 0 7px 0 5px; + margin: 0 7px 0 0; padding: 0 16px 0 10px; border-left-width: 5px; border-left-style: solid; + border-left-color: var(--vscode-textBlockQuote-border); + background-color: var(--vscode-textBlockQuote-background); } + /* inline code styling */ code { font-size: 1em; font-family: var(--vscode-repl-font-family); + background-color: var(--vscode-textPreformat-background); + padding: 1px 3px; + border-radius: 4px; + } + + /** code block styling */ + pre { + background-color: var(--vscode-textCodeBlock-background); + padding: 16px; + border-radius: 4px; } pre code { line-height: 1.357em; white-space: pre-wrap; padding: 0; + background-color: transparent; /* override inline code style */ } li p {