feat: fix git window and add pretty diff viewer (#178)
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 58s
CI / Lint & Test (push) Successful in 16m33s
CI / Build Linux (push) Successful in 20m56s
CI / Build Windows (cross-compile) (push) Successful in 31m1s

## 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:
2026-03-06 09:19:16 -08:00
committed by Naomi Carrigan
parent 9af61a4a29
commit 1ae440659c
5 changed files with 668 additions and 7 deletions
+51 -1
View File
@@ -1,6 +1,7 @@
use serde::{Deserialize, Serialize};
use std::process::Command;
#[cfg(target_os = "windows")]
use crate::process_ext::HideWindow;
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -37,9 +38,38 @@ pub struct GitLogEntry {
pub message: String,
}
/// Builds the WSL argument list for running a git command at a Linux path.
/// Extracted for testability without requiring WSL to be available.
#[cfg(any(target_os = "windows", test))]
fn build_wsl_git_args<'a>(working_dir: &'a str, args: &[&'a str]) -> Vec<&'a str> {
let mut wsl_args = vec!["--", "git", "-C", working_dir];
wsl_args.extend_from_slice(args);
wsl_args
}
fn run_git_command(working_dir: &str, args: &[&str]) -> Result<String, String> {
#[cfg(target_os = "windows")]
let output = {
if working_dir.starts_with('/') {
// WSL/Linux path — run git through WSL so it can resolve the path correctly.
let wsl_args = build_wsl_git_args(working_dir, args);
Command::new("wsl")
.hide_window()
.args(&wsl_args)
.output()
.map_err(|e| format!("Failed to execute git via WSL: {}", e))?
} else {
Command::new("git")
.hide_window()
.args(args)
.current_dir(working_dir)
.output()
.map_err(|e| format!("Failed to execute git: {}", e))?
}
};
#[cfg(not(target_os = "windows"))]
let output = Command::new("git")
.hide_window()
.args(args)
.current_dir(working_dir)
.output()
@@ -297,6 +327,26 @@ mod tests {
use std::io::Write;
use tempfile::TempDir;
// ==================== build_wsl_git_args tests ====================
#[test]
fn test_build_wsl_git_args_structure() {
let args = build_wsl_git_args("/home/naomi/code/project", &["status", "--porcelain=v1"]);
assert_eq!(args[0], "--");
assert_eq!(args[1], "git");
assert_eq!(args[2], "-C");
assert_eq!(args[3], "/home/naomi/code/project");
assert_eq!(args[4], "status");
assert_eq!(args[5], "--porcelain=v1");
assert_eq!(args.len(), 6);
}
#[test]
fn test_build_wsl_git_args_no_extra_args() {
let args = build_wsl_git_args("/home/user/repo", &["init"]);
assert_eq!(args, vec!["--", "git", "-C", "/home/user/repo", "init"]);
}
// Helper to create a git repository in a temp directory
fn create_test_repo() -> TempDir {
let temp_dir = TempDir::new().unwrap();