From a6877d7b13230bdb234d03534b2cae84cee7623f Mon Sep 17 00:00:00 2001 From: ksj09406 Date: Thu, 10 Sep 2026 21:21:14 +0900 Subject: [PATCH] =?UTF-8?q?C-1=20=EB=8B=A4=EC=8B=9C:=20=EB=A8=B8=EB=A6=AC?= =?UTF-8?q?=EA=B8=80=EC=97=90=20=EB=91=90=20=EA=B2=BD=EB=A1=9C=EC=9D=98=20?= =?UTF-8?q?=EB=8B=A4=EB=A5=B8=20=EB=B6=80=EB=B6=84=EC=9D=84=20=EB=82=A8?= =?UTF-8?q?=EA=B8=B4=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 파일 이름만 남기니 양쪽이 똑같이 보였다. 파일 비교는 이름이 같은 경우가 오히려 흔하다. PathUtil.DistinctTail 로 같은 앞부분만 떼고 나머지를 적는다. 검사 11건 추가. --- doc/history/2026-09-10-4차.md | 29 ++++++++++++++++- doc/history/changelog.md | 2 ++ src/MergeHub/Services/PathUtil.cs | 40 ++++++++++++++++++++++++ src/MergeHub/ViewModels/HomeViewModel.cs | 23 +++++++++++--- 4 files changed, 89 insertions(+), 5 deletions(-) diff --git a/doc/history/2026-09-10-4차.md b/doc/history/2026-09-10-4차.md index a438222..97a1cfd 100644 --- a/doc/history/2026-09-10-4차.md +++ b/doc/history/2026-09-10-4차.md @@ -266,4 +266,31 @@ MergeHub 파일 비교 결과 | 머리글 우클릭 → 전체 경로 복사 | 클립보드에 전체 경로가 들어왔다 | | 탐색기에서 `기준 파일...` 단추에 놓기 | `BASE · C.cpp` 로 바뀌고 LOCAL 은 그대로 | -검사 560건 통과 · 빌드 경고 0 · 오류 0. \ No newline at end of file +검사 560건 통과 · 빌드 경고 0 · 오류 0. +### C-1 다시 — 파일 이름만 남긴 것이 잘못이었다 (2026-09-10) + +**사용자 지적** - "파일 비교는 서로 다른 경로에 있는 파일을 보는 것 아니냐. +경로가 같으면 같은 파일일 텐데 왜 경로를 지웠느냐." + +맞는 지적이다. 처음 고칠 때 머리글을 `BASE · {파일 이름}` 으로 줄였는데, +**파일 비교에서 이름이 같은 경우가 오히려 흔하다**(같은 파일의 두 판을 견주는 것이 주된 쓰임이다). +그러면 양쪽 머리글이 `BASE · Weld.cpp` / `LOCAL · Weld.cpp` 로 똑같아져 어느 쪽이 어느 쪽인지 알 수 없다. +실제로 B-1 확인 때 그 화면이 나왔는데 그때는 못 알아봤다. +툴팁에 전체 경로가 있긴 하지만 양쪽에 하나씩 올려 보고 머릿속에서 견줘야 한다. + +**전체 경로도 아니고 파일 이름도 아닌, 다른 부분만 적는다.** +`PathUtil.DistinctTail` 을 새로 두어 같은 앞부분만 떼고 나머지를 보여 준다. + +``` +D:\work\trunk\src\a.cpp → trunk\src\a.cpp +D:\work\branch\src\a.cpp → branch\src\a.cpp +``` + +파일 이름 칸은 언제나 남긴다. 드라이브가 다르거나 겹치는 앞부분이 없으면 전체 경로를 그대로 준다. +대소문자와 슬래시 방향은 같게 본다. + +**확인** - 이름이 같은 두 파일을 열었더니 `BASE · left\A.cpp` / `LOCAL · right\A.cpp` 로 갈렸다. +검사 11건 추가(`PathTest` 43 → 54). 전체 **571건 통과**. + +**남길 것** - 화면을 줄이는 일은 무엇이 남아야 하는지부터 정하고 줄여야 한다. +여기서는 "경로가 길다"만 보고 줄였는데, 정작 그 경로가 두 칸을 가르는 유일한 정보였다. \ No newline at end of file diff --git a/doc/history/changelog.md b/doc/history/changelog.md index 0eb6ec7..92d6ca2 100644 --- a/doc/history/changelog.md +++ b/doc/history/changelog.md @@ -8,6 +8,7 @@ | 날짜 | 항목 | 커밋 | |---|---|---| +| 2026-09-10 | **4차 C-1 다시** — 머리글을 파일 이름만으로 줄인 것이 잘못이었다. 두 경로에서 다른 부분만 남기게 고침 | 아래 | | 2026-09-10 | **4차 C-1** — 파일 비교에서 같은 경로가 나오던 세 자리를 하나로. 코드가 두 줄 더 보인다 | 아래 | | 2026-09-10 | **4차 B-3** — 폴더 비교 목록을 파일 비교 화면에서 이전/다음으로 딛는다 (Ctrl+PageUp/PageDown) | 아래 | | 2026-09-10 | **4차 B-1** — 최근에 견준 파일 짝·폴더 짝을 기억해 위 줄에서 바로 연다. 없는 경로는 흐리게만 하고 지우지 않는다 | 아래 | @@ -32,6 +33,7 @@ | 날짜 | 문서 | 내용 | |---|---|---| +| 2026-09-10 | **4차 C-1 다시** — 머리글을 파일 이름만으로 줄인 것이 잘못이었다. 두 경로에서 다른 부분만 남기게 고침 | 아래 | | 2026-09-10 | **4차 C-1** — 파일 비교에서 같은 경로가 나오던 세 자리를 하나로. 코드가 두 줄 더 보인다 | 아래 | | 2026-09-10 | **4차 B-3** — 폴더 비교 목록을 파일 비교 화면에서 이전/다음으로 딛는다 (Ctrl+PageUp/PageDown) | 아래 | | 2026-09-10 | **4차 B-1** — 최근에 견준 파일 짝·폴더 짝을 기억해 위 줄에서 바로 연다. 없는 경로는 흐리게만 하고 지우지 않는다 | 아래 | diff --git a/src/MergeHub/Services/PathUtil.cs b/src/MergeHub/Services/PathUtil.cs index 9e0588e..245aeaa 100644 --- a/src/MergeHub/Services/PathUtil.cs +++ b/src/MergeHub/Services/PathUtil.cs @@ -122,5 +122,45 @@ namespace MergeHub.Services return string.Empty; } } + + /// + /// 두 경로에서 서로 다른 부분만 남긴다. + /// + /// 왜 필요한가 - 파일 비교는 다른 자리에 있는 파일을 견주는 일이다. 경로가 같으면 같은 파일이니 + /// 다른 것은 언제나 경로 쪽인데, 파일 이름만 보여 주면 양쪽이 똑같이 보여 어느 쪽이 어느 쪽인지 알 수 없다 + /// (실제로 `BASE · Weld.cpp` / `LOCAL · Weld.cpp` 로 똑같이 나왔다). + /// 전체 경로를 다 적으면 길어서 읽히지 않는다. 그래서 같은 앞부분만 떼고 나머지를 보여 준다. + /// + /// 예) D:\work\trunk\src\a.cpp · D:\work\branch\src\a.cpp + /// → trunk\src\a.cpp · branch\src\a.cpp + /// + /// 드라이브가 다르거나 겹치는 앞부분이 없으면 그대로 준다. + /// 두 경로가 아주 같으면(있을 수 없지만) 파일 이름만 준다 - 그때는 견줄 것이 없다. + /// + public static (string Left, string Right) DistinctTail(string? left, string? right) + { + var l = left ?? string.Empty; + var r = right ?? string.Empty; + + if (l.Length == 0 || r.Length == 0) return (Name(l), Name(r)); + + var sep = new[] { '\\', '/' }; + var lp = l.Split(sep, StringSplitOptions.RemoveEmptyEntries); + var rp = r.Split(sep, StringSplitOptions.RemoveEmptyEntries); + + // 파일 이름 칸은 언제나 남긴다. 그 앞까지만 견준다. + var limit = Math.Min(lp.Length, rp.Length) - 1; + var same = 0; + while (same < limit && + string.Equals(lp[same], rp[same], StringComparison.OrdinalIgnoreCase)) same++; + + if (same == 0) return (l, r); + + return (string.Join("\\", lp, same, lp.Length - same), + string.Join("\\", rp, same, rp.Length - same)); + } + + private static string Name(string path) => + path.Length == 0 ? string.Empty : System.IO.Path.GetFileName(path.TrimEnd('\\', '/')); } } diff --git a/src/MergeHub/ViewModels/HomeViewModel.cs b/src/MergeHub/ViewModels/HomeViewModel.cs index 770bea9..c05b051 100644 --- a/src/MergeHub/ViewModels/HomeViewModel.cs +++ b/src/MergeHub/ViewModels/HomeViewModel.cs @@ -1743,8 +1743,7 @@ namespace MergeHub.ViewModels ClearPanes(); IsBinaryFile = true; RefreshLanguage(); - BaseHeader = $"BASE · {Path.GetFileName(LeftFile)}"; - LocalHeader = $"LOCAL · {Path.GetFileName(RightFile)}"; + SetPlainHeaders(); CompareBinary(LeftFile, RightFile); }); @@ -1786,8 +1785,7 @@ namespace MergeHub.ViewModels Lines.Clear(); foreach (var row in rows) Lines.Add(row); - BaseHeader = $"BASE · {Path.GetFileName(LeftFile)}"; - LocalHeader = $"LOCAL · {Path.GetFileName(RightFile)}"; + SetPlainHeaders(); _originalLocalText = BuildLocalText(); SyncEditorFromLines(); @@ -1872,6 +1870,23 @@ namespace MergeHub.ViewModels }); } + /// + /// 파일 두 개를 견줄 때의 패널 머리글. + /// + /// 파일 이름만 적지 않는다. 파일 비교는 다른 자리에 있는 파일을 견주는 일이라 + /// 이름이 같은 경우가 흔하고(같은 파일의 두 판), 그러면 양쪽 머리글이 똑같아져 + /// 어느 쪽이 어느 쪽인지 알 수 없다. 그렇다고 전체 경로를 다 적으면 길어서 읽히지 않는다. + /// 그래서 로 같은 앞부분만 떼고 나머지를 적는다. + /// 전체 경로는 툴팁과 우클릭 복사에 그대로 있다. + /// + private void SetPlainHeaders() + { + var (left, right) = PathUtil.DistinctTail(LeftFile, RightFile); + + BaseHeader = $"BASE · {left}"; + LocalHeader = $"LOCAL · {right}"; + } + // ================= 저장 안 한 편집 지키기 ================= ///