diff --git a/media/main.css b/media/main.css
index bfbff34..a5e3a99 100644
--- a/media/main.css
+++ b/media/main.css
@@ -889,3 +889,69 @@ kbd {
.thought-content {
padding: 10px 12px;
}
+
+/* Diff Display Styles */
+.diff-container {
+ margin: 8px 0;
+ border-radius: 4px;
+ overflow: hidden;
+ border: 1px solid var(--vscode-panel-border);
+}
+
+.diff-header {
+ font-weight: bold;
+ padding: 6px 10px;
+ background: var(--vscode-editor-lineHighlightBackground);
+ border-bottom: 1px solid var(--vscode-panel-border);
+ font-family: var(--vscode-editor-font-family);
+ font-size: var(--vscode-editor-font-size);
+}
+
+.diff-content {
+ font-family: var(--vscode-editor-font-family);
+ font-size: var(--vscode-editor-font-size);
+ margin: 0;
+ padding: 0;
+ overflow-x: auto;
+}
+
+.diff-line {
+ padding: 1px 10px;
+ white-space: pre;
+ line-height: 1.4;
+}
+
+.diff-add {
+ background-color: var(--vscode-diffEditor-insertedTextBackground);
+ color: var(
+ --vscode-diffEditor-insertedTextForeground,
+ var(--vscode-editor-foreground)
+ );
+}
+
+.diff-remove {
+ background-color: var(--vscode-diffEditor-removedTextBackground);
+ color: var(
+ --vscode-diffEditor-removedTextForeground,
+ var(--vscode-editor-foreground)
+ );
+}
+
+.diff-context {
+ color: var(--vscode-descriptionForeground);
+}
+
+.diff-empty {
+ padding: 10px;
+ color: var(--vscode-descriptionForeground);
+ font-style: italic;
+ text-align: center;
+}
+
+.diff-truncated {
+ padding: 6px 10px;
+ color: var(--vscode-descriptionForeground);
+ font-style: italic;
+ background: var(--vscode-editor-lineHighlightBackground);
+ border-top: 1px solid var(--vscode-panel-border);
+}
diff --git a/src/test/webview.test.ts b/src/test/webview.test.ts
index ab98738..6a31f6b 100644
--- a/src/test/webview.test.ts
+++ b/src/test/webview.test.ts
@@ -10,6 +10,8 @@ import {
ansiToHtml,
hasAnsiCodes,
getToolKindIcon,
+ computeLineDiff,
+ renderDiff,
type VsCodeApi,
type Tool,
type WebviewElements,
@@ -1261,4 +1263,79 @@ suite("Webview", () => {
assert.ok(html.includes('title="edit"'));
});
});
+
+ suite("computeLineDiff", () => {
+ test("returns empty array for empty inputs", () => {
+ const result = computeLineDiff("", "");
+ assert.strictEqual(result.length, 0);
+ });
+
+ test("marks all lines as add for new file", () => {
+ const result = computeLineDiff(null, "line1\nline2");
+ assert.strictEqual(result.length, 2);
+ assert.strictEqual(result[0].type, "add");
+ assert.strictEqual(result[0].line, "line1");
+ assert.strictEqual(result[1].type, "add");
+ assert.strictEqual(result[1].line, "line2");
+ });
+
+ test("marks all lines as remove for deleted file", () => {
+ const result = computeLineDiff("line1\nline2", null);
+ assert.strictEqual(result.length, 2);
+ assert.strictEqual(result[0].type, "remove");
+ assert.strictEqual(result[1].type, "remove");
+ });
+
+ test("marks old as remove and new as add for modified file", () => {
+ const result = computeLineDiff("old", "new");
+ assert.strictEqual(result.length, 2);
+ assert.strictEqual(result[0].type, "remove");
+ assert.strictEqual(result[0].line, "old");
+ assert.strictEqual(result[1].type, "add");
+ assert.strictEqual(result[1].line, "new");
+ });
+ });
+
+ suite("renderDiff", () => {
+ test("returns no changes message for empty diff", () => {
+ const result = renderDiff(undefined, "", "");
+ assert.ok(result.includes("diff-container"));
+ assert.ok(result.includes("No changes"));
+ });
+
+ test("renders file path header when provided", () => {
+ const result = renderDiff("/path/to/file.ts", null, "new content");
+ assert.ok(result.includes("diff-header"));
+ assert.ok(result.includes("/path/to/file.ts"));
+ });
+
+ test("renders additions with diff-add class", () => {
+ const result = renderDiff(undefined, null, "added line");
+ assert.ok(result.includes("diff-add"));
+ assert.ok(result.includes("+ added line"));
+ });
+
+ test("renders deletions with diff-remove class", () => {
+ const result = renderDiff(undefined, "removed line", null);
+ assert.ok(result.includes("diff-remove"));
+ assert.ok(result.includes("- removed line"));
+ });
+
+ test("escapes HTML in diff content", () => {
+ const result = renderDiff(
+ undefined,
+ null,
+ ""
+ );
+ assert.ok(result.includes("<script>"));
+ assert.ok(!result.includes("