diff --git a/doc/history/2026-09-17-10차.md b/doc/history/2026-09-17-10차.md index 7689984..27fd615 100644 --- a/doc/history/2026-09-17-10차.md +++ b/doc/history/2026-09-17-10차.md @@ -224,3 +224,52 @@ - **느린 디스크(HDD · SATA SSD)에서는 재 보지 않았다.** 이 PC 는 NVMe 뿐이다. 한 갈래 1.8초가 여러 갈래로 0.3초가 된 것은 NVMe 가 동시 읽기에 강해서이고, HDD 에서는 여러 갈래 읽기가 오히려 느릴 수 있다. 사내 PC 가 HDD 라면 베타 배포 때 재 볼 거리다. + +## F-1 · F-2. 폴더 비교 "같은 것만" 에 내용이 다른 것처럼 보이는 줄이 섞인다 (2026-09-17, 추가 요청, 완료) + +사용자: "방금 폴더비교에서 같은것만 보기를 눌렀을때 내용이 다른파일들이 보이던데" — 9차 B-2 · 10차 D-1 에서 4,500개 시험 묶음으로 필터를 바꿔 가며 잴 때 화면으로 본 것. +사용자 결정(2026-09-17): 설정으로 같음이 된 파일은 **같음으로 두고 따로 표시**. + +### 먼저 가렸다 — 비교 판정인가, 화면인가 + +**비교 판정**: `FolderComparer` 를 설정 네 가지 조합으로 돌려 "같음" 인데 바이트가 다른 파일을 까닭별로 셌다(`SameCheck`, 앱 코드 그대로). + +| 작은 짝 13개 | 스타일 끔 · 주석 무시 끔 | 끔 · 켬 | Allman · 끔 | Allman · 켬(사용자 설정) | +|---|---|---|---|---| +| 01 같음 | 같음 | 같음 | 같음 | 같음 | +| 04 중괄호 자리만 | 다름 | 다름 | **같음** | **같음** | +| 06 머지 주석 줄만 | 주석만 다름 | **같음** | 주석만 다름 | **같음** | +| 05 코드 값 · 11 중괄호 + 코드 값 · 10 txt 값 | 다름 | 다름 | 다름 | 다름 | +| 02 BOM · 03 줄끝 · 07 인코딩 · 08 끝 공백 · 09 주석 · 12 빈 줄 · 13 들여쓰기 | 주석만 다름 | 주석만 다름 | 주석만 다름 | 주석만 다름 | + +- **코드 값이 다른 파일은 어느 설정에서도 "다름"** — 판정은 설계대로(6차 B-5 · E-1). 시험 묶음 4,500개는 두 설정 모두 "같음인데 바이트가 다른 파일" 0개. + +**화면**: 같은 조건(사용자 설정 그대로, 시험 묶음)으로 "같은 것만" 을 거니 파일 줄은 모두 "같음" · 양쪽 크기가 같았는데, +**폴더 줄(Config · Io · Log · Motion · Recipe · Ui · Vision · Weld)이 "다름" 에 주황 바탕**이었다(스크린샷 `d10-same-perf.png`). 사용자가 본 "다른 것" 은 이 줄이다. +작은 짝에서는 `06_머지주석만.cs` 가 크기 67B · 102B 인데 "같음" 이라 크기만 보면 다른 파일로 읽혔다(`d10-same-d10same.png`). + +### 원인 + +- **F-1**: 필터는 "안에 걸리는 것이 하나라도 있는 폴더" 를 남기는데, 폴더 줄은 폴더 자신의 상태(`FolderStatus` — 자식 중 하나라도 같음이 아니면 "다름")로 글자 · 색을 정했다. +- **F-2**: 설정으로 같음이 된 까닭을 결과에 남기지 않아 화면이 그냥 "같음" 이라고만 했다. + +### 고친 것 + +- `FolderComparer` — `SameReason`(None · Style · MergeNotes · StyleAndMergeNotes)을 항목에 남긴다. 설정으로 같음이 된 파일만 한 가지씩 켜서 다시 견줘 까닭을 정한다(그 파일만 값을 치른다). + 상태 글자는 `FolderStatusText.Of`(같음 · 같음(스타일만 다름) · 같음(머지 주석만 다름) · 같음(스타일 · 머지 주석만 다름) · 다름 …), 걸러 본 폴더 줄 글자는 `FolderStatusText.FilteredFolder`("같음 N개" · "왼쪽만 N개" · "오른쪽만 N개"). +- `FolderViewModel` — 필터가 같은 것만 · 왼쪽에만 · 오른쪽에만이면 가지치기한 뒤 폴더마다 남은 파일 수를 세어 폴더 줄에 적고(`ShowAsFiltered`), 줄 색도 그 갈래로(`DisplayStatus`). 다른 필터는 폴더 자신의 상태 그대로. +- `FolderView.xaml` — 줄 색이 `DisplayStatus` 를 따른다. 상태 칸 폭 90 → 200(긴 글자가 잘리지 않게, 머리글 칸도 같이). +- 하네스 `FolderTest` 15건(77건): 까닭 다섯 경우 · 요약 같음 수 그대로 · 주석 무시를 끄면 주석 파일은 같음 아님 · 글자 다섯 · 폴더 줄 글자 셋. + +### 확인한 것 (사용자 설정 그대로, 앱 화면) + +| 경우 | 결과 | +|---|---| +| 시험 묶음 "같은 것만" | 폴더 줄 **"같음 122개" · "같음 126개" · "같음 67개" …, 주황 없음** · 파일 줄 모두 "같음" · 요약 `같음 4063` 그대로 (`d10-same-perf-after.png`) | +| 작은 짝 "같은 것만" | `01_같음.cs` 같음 · `04_중괄호만.cs` **같음(스타일만 다름)** · `06_머지주석만.cs` **같음(머지 주석만 다름)** · 요약 `같음 3` 그대로 (`d10-same-small-after.png`) | + +- 하네스 22벌 1,146건 통과(+15) · 빌드 경고 0 · 오류 0. + +### 알게 된 것 (고치지 않음) + +- **BOM · 줄끝 · 인코딩 · 끝 공백 · 빈 줄 · 들여쓰기만 다른 파일도 "주석만 다름"** 이다. 주석 · 공백을 걷어내고 글자로 견주는 판정이라 그렇다(5차 · 3차 설계). 이름이 "주석만" 이라 BOM 만 다른 파일에는 맞지 않는 말이다 — 이름을 바꿀지는 따로 정할 거리. diff --git a/doc/history/changelog.md b/doc/history/changelog.md index a3bca93..a445ed3 100644 --- a/doc/history/changelog.md +++ b/doc/history/changelog.md @@ -8,6 +8,7 @@ | 날짜 | 항목 | 커밋 | |---|---|---| +| 2026-09-17 | **10차 F-1 · F-2 (추가 요청)** — 폴더 비교 "같은 것만" 에서 같은 파일을 품은 폴더 줄이 폴더 자신의 상태 "다름"(주황)으로 보여 내용이 다른 것이 섞인 것처럼 읽혔다. 걸러 볼 때(같은 것만 · 왼쪽에만 · 오른쪽에만) 폴더 줄은 걸린 파일 수와 그 갈래 색으로 적는다. 설정(C# 스타일 맞춤 · 머지 주석 무시)으로 같음이 된 파일은 사용자 결정대로 같음으로 두고 "같음(스타일만 다름)" · "같음(머지 주석만 다름)" 으로 까닭을 붙인다. 요약 수 그대로. 하네스 FolderTest +15 | 아래 | | 2026-09-17 | **10차 D-1** — 9차 B-2 에서 한 번 잰 "그날 첫 폴더 비교 9.2초" 를 다시 냈다. 파일마다 버퍼 없이 열어 캐시를 비워도(한 갈래 읽기 0.4 → 1.8초로 먹는 것 확인) 전체 비교는 0.46~0.54초로 데운 상태와 같았고(여러 갈래 읽기), 앱을 새로 켠 첫 비교도 느리지 않았다. 9.2초는 다시 안 남 → 고치지 않음(제품 코드 변경 없음). 매뉴얼 한계 문장을 잰 값으로 고침. HDD 는 재 보지 않음 | 아래 | | 2026-09-17 | **10차 C-1** — 설정 "머지 주석 무시" 를 끈 채 네 칸을 다시 정렬하면 주석 줄이 BASE 코드 줄과 한 행이 되어 반영 표시(BASE 줄 번호)가 주석 줄에, 반영한 코드 줄은 "직접 수정" 으로 보였다. 네 칸은 규칙과 상관없이 주석 줄과 코드 줄을 떼어 놓고, 다시 정렬한 주석 줄을 "반영함" 으로 칠하지 않게 함. 요약 · 줄 수 · 저장 해시 그대로. 두 칸도 떼어 보니 차이 수가 늘어(4 → 5줄) 두 칸은 그대로. 하네스 NoteTest +5 | 아래 | | 2026-09-17 | **10차 B-1** — Git 탭과 파일 비교 탭이 고른 커밋 값을 함께 쓰는데 표시는 새로고침 전까지 서로 안 따라왔다. 파일 비교 탭에서 고르면 Git 탭은 옛 커밋에 선택 표시가 남은 채 **[Revert] 가 보이지 않는 커밋에 걸렸다.** 사용자 결정대로 양방향으로 바로 따라가고(`CommitChosen`), 파일 비교 탭에 저장 안 한 편집이 있으면 Git 탭 목록이 선택을 바꾸기 전에 물어 [취소] 면 누름을 막는다. 하네스 +4 | 아래 | diff --git a/doc/작업지시/10차.md b/doc/작업지시/10차.md index 098dadc..2b41e91 100644 --- a/doc/작업지시/10차.md +++ b/doc/작업지시/10차.md @@ -122,6 +122,20 @@ --- +## F. 추가 요청 + +### F-1 · F-2. 폴더 비교 "같은 것만" 에 내용이 다른 것처럼 보이는 줄이 섞인다 (2026-09-17, 사용자) + +사용자: "방금 폴더비교에서 같은것만 보기를 눌렀을때 내용이 다른파일들이 보이던데" — 9차 B-2 · 10차 D-1 에서 4,500개 시험 묶음으로 필터를 바꿔 가며 잴 때 본 화면. + +- **F-1 폴더 줄** — "같은 것만" 은 같은 파일을 품은 폴더를 남기는데, 폴더 줄은 폴더 자신의 상태(안에 다른 것이 하나라도 있으면 **"다름", 주황**)로 보였다. + 방향: "같은 것만 · 왼쪽에만 · 오른쪽에만" 으로 걸러 볼 때 폴더 줄은 걸린 파일 수("같음 122개")와 그 갈래 색으로 적는다. "전체 · 다른 것만 · 코드가 다른 것만" 은 그대로. +- **F-2 설정으로 같음이 된 파일** — 설정 [C# 코드 스타일 맞춤](사용자 설정 Allman) · [비교 · 병합에서 머지 주석 무시](켬) 때문에 중괄호 자리 · 머지 주석 줄만 다른 파일은 크기가 달라도 "같음" 이다. + 사용자 결정: **같음으로 두고 따로 표시** — "같음(스타일만 다름)" · "같음(머지 주석만 다름)" · "같음(스타일 · 머지 주석만 다름)". 필터 · 요약 수는 그대로. +- **판정 기준**: 시험 묶음 "같은 것만" 에 주황 "다름" 줄이 없다. 작은 짝(같음 · 중괄호만 · 머지 주석만 · 코드 값 등)에서 까닭이 맞게 붙고 코드 값이 다른 파일은 어느 설정에서도 "다름". 요약 수 · 결과 글자 그대로. + +--- + ## 이번 지시서에서 하지 않는 것 - **실제 소스로 병합해 보기** — 실제 소스는 열지 않는다(2026-09-11 결정). diff --git a/doc/진행상황.md b/doc/진행상황.md index 0e64e9c..0ab38b1 100644 --- a/doc/진행상황.md +++ b/doc/진행상황.md @@ -313,6 +313,12 @@ | 대기 | E-1 다섯 길(+ pull)을 다시 끝까지 — 줄 고른 로그 = 누른 수 | | 대기 | E-2 웹 문서를 10차에 맞게 | +### F. 추가 요청 + +| 상태 | 항목 | +|---|---| +| **완료** | F-1 · F-2 폴더 비교 "같은 것만" 에 내용이 다른 것처럼 보이는 줄이 섞인다 (2026-09-17 사용자) — 폴더 줄이 폴더 자신의 "다름"(주황)으로 보이던 것을 걸러 본 갈래의 개수("같음 122개")로. 설정(스타일 맞춤 · 머지 주석 무시)으로 같음이 된 파일은 사용자 결정대로 "같음(스타일만 다름)" · "같음(머지 주석만 다름)" 으로 따로 표시. 요약 수 그대로 | + --- ## 3~4주차로 미룬 것 diff --git a/src/MergeHub/Services/FolderComparer.cs b/src/MergeHub/Services/FolderComparer.cs index 42fc23b..19d3d76 100644 --- a/src/MergeHub/Services/FolderComparer.cs +++ b/src/MergeHub/Services/FolderComparer.cs @@ -31,6 +31,59 @@ namespace MergeHub.Services CommentOnly } + /// + /// 바이트는 다른데 설정 때문에 "같음" 으로 본 까닭(10차 F-2). + /// + /// 설정 [C# 코드 스타일 맞춤] 이 켜져 있으면 중괄호 자리만 다른 파일, [비교 · 병합에서 머지 주석 무시] 가 켜져 있으면 + /// 머지 주석 줄만 다른 파일을 같음으로 본다(6차 B-5 · E-1). 그런데 화면에는 그냥 "같음" 이라 크기가 다른 파일이 + /// "같은 것만" 목록에 섞여 내용이 다른 파일처럼 보였다. 같음은 그대로 두고 왜 같은지를 따로 적는다(사용자 결정). + /// + public enum SameReason + { + /// 바이트가 같다(또는 빠른 비교에서 크기 · 수정일이 같다). + None, + /// C# 중괄호 자리만 다르다. + Style, + /// 머지 주석 줄(또는 줄 끝 머지 주석)만 다르다. + MergeNotes, + /// 둘 다를 맞춰야 같다. + StyleAndMergeNotes + } + + /// 폴더 비교 목록의 상태 글자. 화면과 검사가 같은 글을 쓴다(10차 F-1 · F-2). + public static class FolderStatusText + { + public static string Of(FolderEntryStatus status, SameReason reason) => status switch + { + FolderEntryStatus.Same => reason switch + { + SameReason.Style => "같음(스타일만 다름)", + SameReason.MergeNotes => "같음(머지 주석만 다름)", + SameReason.StyleAndMergeNotes => "같음(스타일 · 머지 주석만 다름)", + _ => "같음" + }, + FolderEntryStatus.Different => "다름", + FolderEntryStatus.LeftOnly => "왼쪽만", + FolderEntryStatus.RightOnly => "오른쪽만", + FolderEntryStatus.Binary => "다름(이진)", + FolderEntryStatus.CommentOnly => "주석만 다름", + _ => string.Empty + }; + + /// + /// "같은 것만 · 왼쪽에만 · 오른쪽에만" 으로 걸러 볼 때 폴더 줄에 적을 글. 걸린 파일 수를 적는다. + /// 폴더 자신의 상태(안에 다른 것이 하나라도 있으면 "다름")를 적으면 "같은 것만" 목록에 주황 "다름" 줄이 섞여 + /// 내용이 다른 것이 보이는 것처럼 읽혔다(10차 F-1). + /// + public static string FilteredFolder(FolderEntryStatus kind, int count) => kind switch + { + FolderEntryStatus.Same => $"같음 {count}개", + FolderEntryStatus.LeftOnly => $"왼쪽만 {count}개", + FolderEntryStatus.RightOnly => $"오른쪽만 {count}개", + _ => $"{count}개" + }; + } + /// 폴더 비교 규칙. public sealed class FolderCompareOptions { @@ -92,6 +145,9 @@ namespace MergeHub.Services public bool IsDirectory { get; } public FolderEntryStatus Status { get; set; } + /// 설정 때문에 같음으로 본 까닭. 같음이 아니거나 바이트가 같으면 None(10차 F-2). + public SameReason SameReason { get; set; } + public bool LeftExists { get; set; } public bool RightExists { get; set; } public long LeftSize { get; set; } @@ -374,7 +430,7 @@ namespace MergeHub.Services if (!item.LeftExists) return FolderEntryStatus.RightOnly; // 크기가 다르면 내용을 볼 필요가 없다. - if (item.LeftSize != item.RightSize) return DifferentKind(leftPath, rightPath, Math.Max(item.LeftSize, item.RightSize), options); + if (item.LeftSize != item.RightSize) return DifferentKind(item, leftPath, rightPath, Math.Max(item.LeftSize, item.RightSize), options); var quick = options.QuickCompare || item.LeftSize > options.FullCompareLimitBytes; @@ -386,12 +442,12 @@ namespace MergeHub.Services var gap = left > right ? left - right : right - left; return gap <= options.TimeTolerance ? FolderEntryStatus.Same - : DifferentKind(leftPath, rightPath, Math.Max(item.LeftSize, item.RightSize), options); + : DifferentKind(item, leftPath, rightPath, Math.Max(item.LeftSize, item.RightSize), options); } return SameContent(leftPath, rightPath) ? FolderEntryStatus.Same - : DifferentKind(leftPath, rightPath, Math.Max(item.LeftSize, item.RightSize), options); + : DifferentKind(item, leftPath, rightPath, Math.Max(item.LeftSize, item.RightSize), options); } /// @@ -400,14 +456,17 @@ namespace MergeHub.Services /// 이진이면 줄 단위 비교 화면을 열어도 볼 것이 없으니 따로 표시한다. /// 글 파일이면 코드는 같고 주석만 다른지를 한 번 더 본다. /// - private static FolderEntryStatus DifferentKind(string leftPath, string rightPath, long size, + private static FolderEntryStatus DifferentKind(FolderCompareItem item, string leftPath, string rightPath, long size, FolderCompareOptions options) { if (TextFile.IsBinary(leftPath) || TextFile.IsBinary(rightPath)) return FolderEntryStatus.Binary; if ((options.IgnoreMergeNotes || options.CSharpStyle != CSharpBraceStyle.None) && OnlyMergeNotesDiffer(leftPath, rightPath, size, options)) + { + item.SameReason = WhySame(leftPath, rightPath, size, options); return FolderEntryStatus.Same; + } return OnlyCommentsDiffer(leftPath, rightPath, size, options) ? FolderEntryStatus.CommentOnly @@ -453,6 +512,25 @@ namespace MergeHub.Services /// 어느 쪽에서도 주석을 뗀 것이 없으면 볼 것도 없다 - 바이트가 다른 까닭이 주석이 아니다. /// 줄끝(\r)은 그대로 남겨 견준다. 주석을 핑계로 줄끝 바꿈까지 "같음" 이 되면 안 된다. /// + /// + /// 설정으로 같음이 된 까닭(10차 F-2). 한 가지만 켜서도 같은지 차례로 본다 - 스타일만으로 같으면 스타일, + /// 머지 주석만으로 같으면 머지 주석, 둘 다 맞춰야 같으면 둘 다. 같음이 된 파일만 이 값을 치르므로 비교 시간에는 거의 안 든다. + /// + private static SameReason WhySame(string leftPath, string rightPath, long size, FolderCompareOptions options) + { + var styleOnly = new FolderCompareOptions { CSharpStyle = options.CSharpStyle, IgnoreMergeNotes = false, FullCompareLimitBytes = options.FullCompareLimitBytes }; + if (options.CSharpStyle != CSharpBraceStyle.None && OnlyMergeNotesDiffer(leftPath, rightPath, size, styleOnly)) + return SameReason.Style; + + var notesOnly = new FolderCompareOptions { CSharpStyle = CSharpBraceStyle.None, IgnoreMergeNotes = true, FullCompareLimitBytes = options.FullCompareLimitBytes }; + if (options.IgnoreMergeNotes && OnlyMergeNotesDiffer(leftPath, rightPath, size, notesOnly)) + return SameReason.MergeNotes; + + return options.IgnoreMergeNotes && options.CSharpStyle != CSharpBraceStyle.None + ? SameReason.StyleAndMergeNotes + : options.IgnoreMergeNotes ? SameReason.MergeNotes : SameReason.Style; + } + private static bool OnlyMergeNotesDiffer(string leftPath, string rightPath, long size, FolderCompareOptions options) { diff --git a/src/MergeHub/ViewModels/FolderViewModel.cs b/src/MergeHub/ViewModels/FolderViewModel.cs index 1fefd29..6340cad 100644 --- a/src/MergeHub/ViewModels/FolderViewModel.cs +++ b/src/MergeHub/ViewModels/FolderViewModel.cs @@ -61,16 +61,29 @@ namespace MergeHub.ViewModels [ObservableProperty] private bool _isSelected; - public string StatusText => Status switch + /// + /// 필터로 걸러 볼 때 폴더 줄에 적을 글. null 이면 폴더 자신의 상태를 적는다(10차 F-1). + /// "같은 것만" 에서 폴더가 자기 상태("다름", 주황)로 보이면 내용이 다른 것이 섞인 것처럼 읽혔다. + /// + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(StatusText))] + [NotifyPropertyChangedFor(nameof(DisplayStatus))] + private string? _filterLabel; + + private FolderEntryStatus? _filterKind; + + /// 폴더 줄을 걸러 본 갈래(같음 · 왼쪽만 · 오른쪽만)와 그 안에 걸린 파일 수로 적는다. + public void ShowAsFiltered(FolderEntryStatus kind, int count) { - FolderEntryStatus.Same => "같음", - FolderEntryStatus.Different => "다름", - FolderEntryStatus.LeftOnly => "왼쪽만", - FolderEntryStatus.RightOnly => "오른쪽만", - FolderEntryStatus.Binary => "다름(이진)", - FolderEntryStatus.CommentOnly => "주석만 다름", - _ => string.Empty - }; + _filterKind = kind; + FilterLabel = FolderStatusText.FilteredFolder(kind, count); + } + + /// 줄 색을 고를 상태. 걸러 보는 폴더 줄은 걸러 본 갈래의 색이다. + public FolderEntryStatus DisplayStatus => _filterKind ?? Status; + + /// 설정 때문에 같음이 된 파일은 까닭을 붙인다 - "같음(스타일만 다름)"(10차 F-2). + public string StatusText => FilterLabel ?? FolderStatusText.Of(Status, Item.SameReason); public string LeftInfo => Describe(Item.LeftExists, Item.LeftSize, Item.LeftModified); public string RightInfo => Describe(Item.RightExists, Item.RightSize, Item.RightModified); @@ -583,6 +596,7 @@ namespace MergeHub.ViewModels if (!Keep(node)) continue; Prune(node); + if (FilteredKind(Filter) is { } kind) LabelFolders(node, kind); // 다른 것부터 눈에 띄도록 펼쳐 둔다. 같기만 한 가지는 접어 둔다. node.IsExpanded = Filter != FolderFilter.Same && node.Status != FolderEntryStatus.Same; @@ -590,6 +604,25 @@ namespace MergeHub.ViewModels } } + /// 폴더 줄을 걸러 본 갈래로 적을 필터인지. "다른 것만" 류는 폴더 자신의 "다름" 이 맞는 말이라 그대로 둔다. + private static FolderEntryStatus? FilteredKind(FolderFilter filter) => filter switch + { + FolderFilter.Same => FolderEntryStatus.Same, + FolderFilter.LeftOnly => FolderEntryStatus.LeftOnly, + FolderFilter.RightOnly => FolderEntryStatus.RightOnly, + _ => null + }; + + /// 가지치기한 뒤 폴더마다 남은 파일 수를 세어 폴더 줄 글을 정한다. 파일 수를 돌려준다(10차 F-1). + private static int LabelFolders(FolderNode node, FolderEntryStatus kind) + { + if (!node.IsDirectory) return 1; + + var count = node.Children.Sum(child => LabelFolders(child, kind)); + node.ShowAsFiltered(kind, count); + return count; + } + /// 지금 필터에 걸리는 항목인지. 폴더는 안에 걸리는 것이 하나라도 있으면 남긴다. private bool Keep(FolderNode node) { diff --git a/src/MergeHub/Views/FolderView.xaml b/src/MergeHub/Views/FolderView.xaml index 9d1bffa..68d0834 100644 --- a/src/MergeHub/Views/FolderView.xaml +++ b/src/MergeHub/Views/FolderView.xaml @@ -34,7 +34,7 @@ 템플릿을 통째로 갈아끼우면 플랫폼 테마(펼침 표시·선택 색)를 잃으므로, 배경 띠 자체에 트리 폭만큼 최소 폭을 주고 넘치는 부분은 잘리게 둔다. --> -