using System.Collections.ObjectModel; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using ClaudeDo.Data.Git; namespace ClaudeDo.Ui.ViewModels.Modals; public sealed partial class WorktreeNodeViewModel : ViewModelBase { public required string Name { get; init; } public string? Status { get; init; } public bool IsDirectory { get; init; } public ObservableCollection Children { get; } = new(); } public sealed partial class WorktreeModalViewModel : ViewModelBase { private readonly GitService _git; public ObservableCollection Root { get; } = new(); [ObservableProperty] private string _worktreePath = ""; // Set by the view (same pattern as DiffModalViewModel.CloseAction) public Action? CloseAction { get; set; } public WorktreeModalViewModel(GitService git) { _git = git; } [RelayCommand] private void Close() => CloseAction?.Invoke(); public async Task LoadAsync(CancellationToken ct = default) { Root.Clear(); string stdout; try { stdout = await _git.GetStatusPorcelainAsync(WorktreePath, ct); } catch { return; } if (string.IsNullOrWhiteSpace(stdout)) return; var dirs = new Dictionary(StringComparer.Ordinal); foreach (var line in stdout.Split('\n', StringSplitOptions.RemoveEmptyEntries)) { if (line.Length < 4) continue; // porcelain format: XYpath (XY = two-char status) var xy = line[..2]; // Pick staged char first, fall back to unstaged var statusChar = xy[0] != ' ' ? xy[0] : xy[1]; var status = statusChar != ' ' ? statusChar.ToString() : null; var path = line[3..].Trim().Replace('\\', '/'); var segments = path.Split('/', StringSplitOptions.RemoveEmptyEntries); if (segments.Length == 0) continue; WorktreeNodeViewModel? parent = null; var accumulated = ""; for (var i = 0; i < segments.Length - 1; i++) { accumulated = accumulated.Length == 0 ? segments[i] : accumulated + "/" + segments[i]; if (!dirs.TryGetValue(accumulated, out var dir)) { dir = new WorktreeNodeViewModel { Name = segments[i], IsDirectory = true }; dirs[accumulated] = dir; if (parent == null) Root.Add(dir); else parent.Children.Add(dir); } parent = dir; } var leaf = new WorktreeNodeViewModel { Name = segments[^1], Status = status, IsDirectory = false }; if (parent == null) Root.Add(leaf); else parent.Children.Add(leaf); } } }