generated from nhcarrigan/template
feat: fix git window and add pretty diff viewer (#178)
## Summary - **Fix git window "Not a git repository" error** — The working directory received from Claude Code is a WSL Linux path (e.g. `/home/naomi/...`), but git commands were being run as native Windows processes with `.current_dir()`. Windows can't resolve WSL paths, causing `git rev-parse --git-dir` to fail. Fixed by routing git commands through `wsl -- git -C <path>` when the working directory starts with `/`. - **Add syntax highlighting and line numbers to diff view** — Replaced the raw `<pre>` block with a proper `DiffViewer` component featuring: - Old/new line number columns with correct tracking across hunks - Colour-coded gutter (`+`/`-`) with green/red row backgrounds - Syntax highlighting via `highlight.js` using the detected file language, respecting all app themes via `--hljs-*` CSS variables - Styled hunk headers and file headers ## New files - `src/lib/utils/diffParser.ts` — pure diff parsing logic - `src/lib/utils/diffParser.test.ts` — 30 tests covering all line types, line number tracking, and language detection - `src/lib/components/DiffViewer.svelte` — the pretty diff viewer component ✨ This pull request was created with help from Hikari~ 🌸 Reviewed-on: #178 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
This commit was merged in pull request #178.
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
export type DiffLineType =
|
||||
| "file-header"
|
||||
| "hunk-header"
|
||||
| "added"
|
||||
| "removed"
|
||||
| "context"
|
||||
| "no-newline";
|
||||
|
||||
export interface ParsedDiffLine {
|
||||
type: DiffLineType;
|
||||
content: string;
|
||||
oldLineNumber: number | null;
|
||||
newLineNumber: number | null;
|
||||
}
|
||||
|
||||
const FILE_HEADER_PREFIXES = [
|
||||
"diff ",
|
||||
"index ",
|
||||
"--- ",
|
||||
"+++ ",
|
||||
"new file",
|
||||
"deleted file",
|
||||
"old mode",
|
||||
"new mode",
|
||||
"rename ",
|
||||
"similarity ",
|
||||
];
|
||||
|
||||
export function parseDiff(diffContent: string): ParsedDiffLine[] {
|
||||
const result: ParsedDiffLine[] = [];
|
||||
let oldLine = 0;
|
||||
let newLine = 0;
|
||||
|
||||
for (const line of diffContent.split("\n")) {
|
||||
if (FILE_HEADER_PREFIXES.some((prefix) => line.startsWith(prefix))) {
|
||||
result.push({ type: "file-header", content: line, oldLineNumber: null, newLineNumber: null });
|
||||
} else if (line.startsWith("@@")) {
|
||||
const match = line.match(/@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
|
||||
if (match) {
|
||||
oldLine = parseInt(match[1], 10);
|
||||
newLine = parseInt(match[2], 10);
|
||||
}
|
||||
result.push({ type: "hunk-header", content: line, oldLineNumber: null, newLineNumber: null });
|
||||
} else if (line.startsWith("+")) {
|
||||
result.push({
|
||||
type: "added",
|
||||
content: line.slice(1),
|
||||
oldLineNumber: null,
|
||||
newLineNumber: newLine++,
|
||||
});
|
||||
} else if (line.startsWith("-")) {
|
||||
result.push({
|
||||
type: "removed",
|
||||
content: line.slice(1),
|
||||
oldLineNumber: oldLine++,
|
||||
newLineNumber: null,
|
||||
});
|
||||
} else if (line.startsWith(" ")) {
|
||||
result.push({
|
||||
type: "context",
|
||||
content: line.slice(1),
|
||||
oldLineNumber: oldLine++,
|
||||
newLineNumber: newLine++,
|
||||
});
|
||||
} else if (line === "\\ No newline at end of file") {
|
||||
result.push({ type: "no-newline", content: line, oldLineNumber: null, newLineNumber: null });
|
||||
}
|
||||
// Skip empty trailing lines
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const EXTENSION_MAP: Record<string, string> = {
|
||||
ts: "typescript",
|
||||
tsx: "typescript",
|
||||
js: "javascript",
|
||||
jsx: "javascript",
|
||||
rs: "rust",
|
||||
py: "python",
|
||||
svelte: "xml",
|
||||
css: "css",
|
||||
scss: "scss",
|
||||
less: "less",
|
||||
html: "html",
|
||||
json: "json",
|
||||
md: "markdown",
|
||||
toml: "ini",
|
||||
yaml: "yaml",
|
||||
yml: "yaml",
|
||||
sh: "bash",
|
||||
bash: "bash",
|
||||
go: "go",
|
||||
java: "java",
|
||||
cpp: "cpp",
|
||||
c: "c",
|
||||
rb: "ruby",
|
||||
php: "php",
|
||||
sql: "sql",
|
||||
kt: "kotlin",
|
||||
swift: "swift",
|
||||
cs: "csharp",
|
||||
r: "r",
|
||||
lua: "lua",
|
||||
xml: "xml",
|
||||
};
|
||||
|
||||
export function detectLanguage(filePath: string): string {
|
||||
const ext = filePath.split(".").pop()?.toLowerCase() ?? "";
|
||||
return EXTENSION_MAP[ext] ?? "plaintext";
|
||||
}
|
||||
Reference in New Issue
Block a user