UbisamBase 플랫폼 위에서 도는 플러그인. 지금까지 만든 것을 그대로 담는다. - 폴더 비교 / 파일 비교(부분 수용·워드랩·찾기) / 3-Way 병합 / Git 조작 - 비교 엔진: histogram 정렬 · 이동 블록 감지 · 무시 규칙 · 13개 언어 토크나이저 - doc/ 에 작업 지시서와 진행 기록 빌드 산출물(bin/obj)은 추적하지 않는다 - 플랫폼 런타임이 빌드 때마다 D:\UbisamPlatform\bin 에서 복사되어 들어오므로 저장소에 담을 이유가 없다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
264 lines
38 KiB
Markdown
264 lines
38 KiB
Markdown
# MergeHub 확장 — 머지툴 기본기 보강
|
||
|
||
> 작성 2026-09-07 · 상태: 착수 전 · 선행 확인 3건 있음(맨 아래)
|
||
>
|
||
> 새 세션에서 이어서 작업할 때는 이 문서를 읽고 시작하면 된다.
|
||
|
||
## 배경
|
||
|
||
MergeHub는 사내 Git 머지/비교 도구다. 지금은 **Git 저장소 안의 파일만**, **C# 소스만**,
|
||
**BASE ↔ LOCAL 2분할로만** 비교할 수 있다. WinMerge와 비교하면 머지툴이면 당연히 있어야 할
|
||
조작(차이 탐색·무시 규칙·폴더 비교)이 빠져 있어 실무에서 쓰기 어렵다.
|
||
|
||
**방향을 다시 잡는다: 머지툴이 본체이고 Git은 그 위에 얹는 기능이다.**
|
||
Git 저장소가 아니어도, 소스 코드가 아니어도 비교가 되어야 한다.
|
||
|
||
## 프로젝트 현황
|
||
|
||
| 항목 | 내용 |
|
||
|---|---|
|
||
| 소비 프로젝트 | `D:\Sorce\MergeTool\MergeHub\src\MergeHub` (net48, OutputType=Library) |
|
||
| 플랫폼 | UbisamBase 호스트+플러그인. `D:\UbisamPlatform\bin` 을 `Reference`+`Private=false` 로 참조, `CopyPlatformRuntime` 타겟이 런타임 복사 |
|
||
| 플랫폼 소스 | `D:\Sorce\MergeTool\UbisamPlatform` — 가이드는 `doc\platform-guide.md` |
|
||
| 실행 | `bin\Release\net48\UbisamBase.Shell.exe` |
|
||
| MVVM | CommunityToolkit.Mvvm 8.3.2 (`[ObservableProperty]`, `[RelayCommand]`) |
|
||
| Git | LibGit2Sharp 0.32.0 |
|
||
|
||
### 관련 파일
|
||
|
||
```
|
||
Views/HomeView.xaml(.cs) 머지 화면. 현재 [커밋트리 | BASE | LOCAL | ACTIONS] 4열
|
||
ViewModels/HomeViewModel.cs ~900줄. 정렬·적용·Undo/Redo·전체편집
|
||
Views/GitView.xaml(.cs) Git 조작 탭
|
||
Services/LineAligner.cs LCS 줄 정렬. Align(baseLines, localLines) → AlignedRow 목록
|
||
Services/GitService.cs Git API 60여 개. GetThreeWayContent(path) 이미 있음
|
||
Services/GitWorkspace.cs DI 싱글턴. 저장소 상태·세마포어 게이트
|
||
Services/CodeSanityChecker.cs 코드 이상 검사
|
||
Services/MergeNote.cs 머지 주석 생성
|
||
Views/Controls/CSharpTokenizer.cs C# 전용 토크나이저. CodeTokenKind 15종
|
||
Views/Controls/CodeTextBlock.cs TextBlock 파생. Code/Words/InBlockComment/HighlightSyntax DP
|
||
Views/Controls/ChangeMiniMap.cs 미니맵
|
||
Models/MergeLine.cs 한 행. LineHighlight { None,Changed,Applied,Edited,Added,Removed }
|
||
MergeHubSettings.cs IgnoreWhitespace, WordLevelDiff, SyntaxHighlight 등
|
||
```
|
||
|
||
---
|
||
|
||
## 참고자료와 라이선스 — 먼저 읽을 것
|
||
|
||
**WinMerge 소스 코드를 받거나 읽지 말 것.** GPLv2+ 라 코드를 참고해 옮기면
|
||
MergeHub 전체가 GPL 의무에 걸린다. C++/MFC 라 어차피 C#/WPF 로 옮길 수도 없다.
|
||
|
||
대신 이것들을 쓴다.
|
||
|
||
| 목적 | 참고할 것 |
|
||
|---|---|
|
||
| 조작 감각·UI 관례·단축키 | **WinMerge 설치본을 직접 써 볼 것** (UI 관례를 따르는 건 자유) |
|
||
| 기능 정의·필터 파일 형식 | https://manual.winmerge.org/en/ |
|
||
| 줄 정렬 알고리즘 | **Histogram diff** (git 기본 알고리즘) · Myers diff 논문 *An O(ND) Difference Algorithm* |
|
||
| 단어 단위 diff | **DiffPlex** (MIT) — 필요하면 참조 가능 |
|
||
|
||
---
|
||
|
||
## 작업 1. 머지툴 기본 조작 · UI
|
||
|
||
WinMerge 화면에 가깝게 만든다. 세 갈래다.
|
||
|
||
### 1-1. 파일 비교
|
||
|
||
- **차이 탐색** — 첫 / 이전 / 다음 / 마지막 차이로 점프.
|
||
단축키 `Alt+↑` `Alt+↓` `Ctrl+Home` `Ctrl+End`, 툴바 버튼도 같이.
|
||
현재 몇 번째 차이인지 상태바에 `차이 3 / 15` 로 표시.
|
||
- **Go to** — 줄 번호 또는 차이 번호로 이동 (`Ctrl+G`).
|
||
- **워드랩 토글** — 긴 줄을 접어서 표시. 현재는 가로 스크롤뿐.
|
||
접힌 줄은 여백에 화살표 표시. BASE/LOCAL 양쪽 줄 높이가 어긋나지 않아야 한다.
|
||
|
||
> **완료 (2026-09-07).** 여백(줄번호·`[>]`)을 행 안쪽으로 옮겨 높이가 저절로 맞게 했고,
|
||
> 가로 스크롤 때는 글자만 `TranslateTransform` 으로 밀어 여백을 고정한다.
|
||
> 접히는 폭을 맞추려고 편집기 세로 스크롤바를 항상 띄우고 표시층에 같은 폭의 여백을 줬다.
|
||
>
|
||
> 한 가지 더 필요했다 - 한쪽만 접힌 행에서 아래가 통째로 밀리는 문제.
|
||
> `MergeLine.RowHeight` 에 두 패널이 각자 글 높이를 알려 주고 **큰 쪽을 함께 쓰도록** 해서 맞췄다.
|
||
- **상태바** — 줄/열 위치, 감지된 **인코딩**, **줄바꿈 형식(CRLF/LF)** 표시.
|
||
- **북마크** — 여백 더블클릭으로 표시/해제, `F2` 로 다음 북마크.
|
||
- **읽기 전용 토글** — LOCAL 편집 잠금.
|
||
|
||
#### 1-1-A. 정렬 알고리즘 교체 — LCS → Histogram diff
|
||
|
||
현재 `LineAligner` 는 순수 LCS 다. LCS 는 `{`, `}`, 빈 줄처럼 **짧고 자주 반복되는 줄**을
|
||
엉뚱하게 짝지어 정렬이 지저분해진다. git 이 LCS 대신 histogram 을 기본으로 쓰는 이유가 그것이다.
|
||
|
||
- **Histogram diff 로 교체한다.** 원리: 양쪽에서 **드물게 나오는 줄**(빈도가 낮은 줄)을
|
||
먼저 앵커로 잡고, 그 앵커를 기준으로 앞뒤 구간을 재귀적으로 다시 정렬한다.
|
||
흔한 줄로 짝을 맞추지 않으므로 사람이 보기에 자연스러운 정렬이 나온다.
|
||
- 기존 최적화는 유지한다 — 앞뒤 공통 구간 잘라내기, 크기 상한(`MaxCells`) 넘으면 포기.
|
||
- **기존 `AlignTest` 26건이 전부 통과해야 한다.** 실패하면 정렬이 나빠진 것이므로 원인을 밝힌다.
|
||
- 새 알고리즘 전용 테스트를 추가한다. 최소한 이 두 가지:
|
||
- 같은 코드 블록이 여러 번 반복되는 파일에서 올바른 쪽에 붙는지
|
||
- 중괄호·빈 줄만 있는 구간이 엉키지 않는지
|
||
|
||
#### 1-1-B. 이동된 블록 감지
|
||
|
||
- 정렬 결과에서 **삭제 구간과 추가 구간의 내용이 같으면**
|
||
"삭제+추가" 가 아니라 **"이동"** 으로 표시한다 (`LineHighlight` 에 `Moved` 추가, 별도 색).
|
||
- 메서드 순서만 바꾼 경우가 흔한데, 지금은 전부 삭제+추가로 보인다.
|
||
- 양쪽 블록을 선으로 잇거나 "→ 42행으로 이동" 같은 힌트를 준다.
|
||
- 미니맵과 범례에도 반영한다.
|
||
|
||
### 1-2. 무시 규칙
|
||
|
||
지금 `MergeHubSettings.IgnoreWhitespace` 는 **`GitService` 의 patch 파싱에만** 걸려 있고
|
||
홈 화면의 `LineAligner` 비교에는 적용되지 않는다. 이걸 바로잡고 확장한다.
|
||
|
||
- **공백 3단계** — 전부 비교 / 개수 변화만 무시 / 완전 무시
|
||
- **대소문자 무시**
|
||
- **줄 필터** — 정규식에 맞는 줄은 차이로 치지 않는다.
|
||
타임스탬프·빌드번호·`$Id$` 같은 것. 규칙 여러 개를 이름 붙여 저장/재사용.
|
||
- 무시 규칙은 **툴바에서 즉시 토글**되고, 바꾸면 화면이 바로 다시 계산되어야 한다.
|
||
현재 켜진 규칙을 상태바에 요약 표시.
|
||
- 무시로 처리된 줄은 "차이 없음" 과 구분되는 옅은 색으로 표시.
|
||
- 구현 위치 주의 — 무시 규칙은 **정렬 전에 비교용 키를 만드는 단계**에 넣는다.
|
||
화면에 보이는 원문은 그대로 두고, 비교할 때만 정규화한 문자열을 쓴다.
|
||
|
||
### 1-3. 폴더 비교
|
||
|
||
새 화면. 파일 하나가 아니라 **폴더 두 개**를 비교한다.
|
||
|
||
- 비교 방식: **전체 내용 / 빠른 내용(크기+수정일)** 선택. 큰 파일은 자동으로 빠른 비교.
|
||
- **트리 뷰** (하위 폴더 재귀) + 목록 뷰
|
||
- 각 항목 상태: 같음 / 다름 / 왼쪽만 / 오른쪽만 / 이진파일
|
||
- 파일 필터 — 정규식 포함·제외. 규칙 세트 저장
|
||
- 항목 더블클릭 → 기존 파일 비교 화면으로
|
||
- 좌↔우 복사, 삭제. **파괴적 동작은 확인 대화상자 필수**
|
||
- 결과 요약: 전체 N개 · 다름 N · 왼쪽만 N · 오른쪽만 N
|
||
|
||
---
|
||
|
||
## 작업 2. Git 유무에 따라 화면 바꾸기
|
||
|
||
- 연 경로에서 **`.git` 을 상위로 거슬러 탐색**한다 (`GitService.Discover` 이미 있음).
|
||
- **있으면** — 지금처럼 커밋 이력 패널을 보여주고, BASE를 커밋에서 불러온다.
|
||
- **없으면** — 커밋 이력 패널을 **숨기고**, Git 탭도 숨기거나 비활성화한다.
|
||
대신 **"파일 두 개를 직접 골라 비교"** 모드로 동작한다 (왼쪽/오른쪽 파일 선택).
|
||
- 전환은 자동이며, 사용자에게 현재 어느 모드인지 명확히 보여야 한다.
|
||
- 폴더 비교도 마찬가지 — Git 없이 동작해야 한다.
|
||
|
||
**판정 기준**: Git이 아닌 아무 폴더의 텍스트 파일 두 개를 열어 비교·편집·저장까지 된다.
|
||
|
||
---
|
||
|
||
## 작업 3. 진짜 3-Way 비교
|
||
|
||
기획안에는 "3-Way Merge" 라고 적혀 있으나 **실제는 2분할**이다.
|
||
1번 칸은 커밋 트리이고 BASE ↔ LOCAL만 비교한다.
|
||
|
||
- 패널을 **BASE(공통 조상) / LOCAL(내 작업) / REMOTE(상대 변경)** 3분할로 만든다.
|
||
- `GitService.GetThreeWayContent(path)` 가 이미 세 버전을 돌려준다 — 이걸 쓴다.
|
||
- `LineAligner` 를 **3열 정렬**로 확장한다. 지금은 2열이다.
|
||
권장 방식: **BASE 를 축으로 BASE↔LOCAL, BASE↔REMOTE 를 각각 정렬한 뒤 BASE 행 기준으로 합친다.**
|
||
세 쪽 모두에 대응되는 행, 두 쪽만 있는 행, 한 쪽만 있는 행이 한 행에 정렬되어야 한다.
|
||
- 각 줄에서 **LOCAL로 가져오기 / REMOTE로 가져오기 / 양쪽 다** 를 고를 수 있어야 한다.
|
||
- **충돌 판정**: BASE 대비 LOCAL과 REMOTE가 서로 다르게 바뀐 줄을 별도 색으로.
|
||
- 커밋 트리 패널은 접거나 폭을 줄일 수 있게 한다 — 3분할이면 가로가 부족하다.
|
||
- Git이 없거나 3-way 대상이 아니면 **2분할로 자동 전환**.
|
||
|
||
---
|
||
|
||
## 작업 4. 소스 아닌 파일 · 다른 언어
|
||
|
||
지금 구문 강조는 `CSharpTokenizer` 하나뿐이고, `CodeSanityChecker.AppliesTo` 도
|
||
`.cs .cpp .c .h .hpp .java .js .ts` 만 받는다.
|
||
|
||
- 토크나이저를 **언어별로 갈아끼울 수 있는 구조**로 바꾼다.
|
||
`CSharpTokenizer` 를 `ITokenizer` 뒤로 넣고 확장자로 고른다.
|
||
기존 `Tokenize(line, inBlockComment, out stillInBlockComment)` 시그니처(줄 넘어가는 블록 주석 상태)는 유지한다.
|
||
- 최소 지원: **C 계열**(C/C++/C#/Java/JS/TS) · **XML/HTML** · **JSON** · **SQL** ·
|
||
**Python** · **INI/설정** · **Markdown** · **일반 텍스트(강조 없음)**
|
||
- **일반 텍스트가 기본값**이다. 모르는 확장자는 강조 없이 비교만 되면 된다.
|
||
`.txt .md .csv .log .xml .json .yml` 등 문서 파일이 정상 동작해야 한다.
|
||
- **이진 파일 감지** — NUL 바이트가 있으면 텍스트로 열지 않고
|
||
"이진 파일 · 같음/다름" 만 알린다. 열어서 깨뜨리면 안 된다.
|
||
- `CodeSanityChecker` 는 **코드 파일에서만** 돌린다. 문서에서는 조용해야 한다.
|
||
- 인코딩 판별(BOM → UTF-8 엄격 → CP949)은 지금 로직을 그대로 쓴다.
|
||
- 기존 `TokenTest` 63건은 C# 토크나이저용이다 — **그대로 통과해야 한다.**
|
||
|
||
---
|
||
|
||
## 지켜야 할 것
|
||
|
||
- **주석은 한글**로, 기존 코드와 같은 밀도로. "무엇을" 이 아니라 **"왜"** 를 적는다.
|
||
- **빌드 경고 0 · 오류 0** 을 유지한다.
|
||
- 새 알고리즘(histogram 정렬, 3열 정렬, 이동 블록 감지, 무시 필터)은
|
||
**스크래치패드에 테스트 하네스**를 만들어 검증하고 결과 건수를 보고한다.
|
||
기존 하네스 방식(`AlignTest`, `SanityTest`, `TokenTest`)을 따른다.
|
||
- **기존 테스트를 깨뜨리지 말 것.** 깨지면 원인을 밝히고 보고한다.
|
||
- **PowerShell `Get-Content`/`Set-Content` 로 프로젝트 파일을 읽고 쓰지 말 것.**
|
||
PS 5.1이 UTF-8을 ANSI로 읽어 한글 주석을 손상시킨다. Read/Write/Edit 도구를 쓴다.
|
||
- 플랫폼(`UbisamPlatform`)을 고쳐야 하면 **먼저 알리고**, 고친 뒤에는
|
||
Core → Shell 빌드 → `scripts\publish-platform.ps1` → MergeHub 재빌드 순서를 지키고
|
||
`doc\history\changelog.md` 에 기록한다.
|
||
- **커밋·푸시하지 않는다.** 필요하면 먼저 확인받는다.
|
||
|
||
## 하지 말 것
|
||
|
||
- **WinMerge 소스 코드를 받거나 읽지 말 것** (GPLv2+ — 위 라이선스 항목 참조).
|
||
- WinMerge를 따라가되 **우리 목적과 무관한 것은 넣지 않는다** —
|
||
이미지 비교, CSV 표 형식 비교, 압축파일 내부 비교, 플러그인 시스템(ActiveX).
|
||
|
||
## 진행 방식
|
||
|
||
권장 순서:
|
||
|
||
```
|
||
1-1-A 정렬 교체(histogram) ← 다른 모든 것의 품질이 여기에 달림
|
||
1-1 차이 탐색 · Go to · 워드랩 · 상태바 · 북마크
|
||
1-1-B 이동 블록 감지
|
||
1-2 무시 규칙
|
||
2 Git 유무 분기
|
||
4 다국어 · 문서 · 이진파일
|
||
3 3-Way
|
||
1-3 폴더 비교
|
||
```
|
||
|
||
정렬 교체를 맨 앞에 두는 이유 — 이동 블록 감지와 3-Way 정렬이 모두 그 위에 얹히므로
|
||
나중에 바꾸면 두 번 일한다.
|
||
|
||
**각 항목을 끝낼 때마다 빌드하고 실제로 실행해 화면을 확인한 뒤 보고할 것.**
|
||
전부 끝내고 한 번에 보고하지 말 것.
|
||
|
||
---
|
||
|
||
## 시작 전에 확인할 것 (미해결)
|
||
|
||
1. **3-Way의 REMOTE는 무엇인가** — 병합 충돌 중일 때의 `MERGE_HEAD` 인가,
|
||
아니면 사용자가 고른 임의의 브랜치·커밋인가? 후자면 브랜치 선택 UI가 필요하다.
|
||
2. **폴더 비교에서 Git 커밋 두 개 사이 비교**도 필요한가, 아니면 파일시스템 폴더 두 개만인가?
|
||
3. **가로 공간** — 3분할 + 커밋트리 + ACTIONS 를 한 화면에 넣을지,
|
||
커밋 트리를 접는 방식으로 갈지.
|
||
|
||
---
|
||
|
||
## 진행 기록
|
||
|
||
| 날짜 | 항목 | 결과 |
|
||
|---|---|---|
|
||
| 2026-09-07 | 문서 작성 | 착수 전 |
|
||
| 2026-09-07 | **패널 이름·머리 정렬 · C#/C++ 데모 · 탭 인디케이터** | **완료.** ① 패널 이름을 모드와 상관없이 **BASE / LOCAL** 로 통일(`기준 파일`·`내 파일` 삭제). ② **경로 줄 높이를 맞췄다** — LOCAL 머리에만 있던 `전체 반영`·`전체 되돌리기` 를 ACTIONS 로, BASE 머리에만 있던 파일 목록 콤보를 상단 툴바로 옮겨 두 머리를 `제목 + 부제 + 경로` 로 똑같이 만들었다. 옮긴 버튼들은 줄 단위 반영과 성격이 같아 ACTIONS 가 원래 자리이기도 하다. ③ **C# · C++ 데모 파일** 을 모두 만들었다 — 파일 비교 기본값은 `WeldController_기준.cs ↔ _내작업.cs`, 같은 폴더에 `.cpp` 쌍도 있고, 폴더 비교 데모(`folder-demo`)에는 `.cs`·`.cpp`·`.h`·문서가 섞여 있다. Git 데모 저장소에는 `WeldController.cpp` 를 새 커밋으로 넣고 거기서 갈라지는 `feature/cpp-tuning` 을 만들어, **C++ 파일로도 제대로 된 3-Way**(merge base 가 그 파일을 갖고 있음)가 된다. ④ **탭 인디케이터 결함**: 폴더 비교에서 파일을 더블클릭하면 내용과 강조는 파일 비교로 넘어가는데 **아래 파란 막대만 폴더 비교에 남았다.** 코드로 탭을 옮기면 그 탭 화면이 그 자리에서 만들어지느라 배치가 밀리는데, `MoveTabIndicator` 는 그때 막대를 0 으로 만들려 했고 **진행 중인 애니메이션이 값을 붙들고 있어 그 지정이 무시**됐다 — 결국 옛 자리 그대로였다. 배치가 끝난 뒤 한 번 다시 재도록 고치고(무한 재시도 방지 포함), 선택이 아예 없을 때는 애니메이션을 먼저 끊고 지우게 했다. **곁들여 고친 것**: 파일 두 개를 직접 고른 모드에서 **코드 검사가 늘 "검사 대상 아님"** 이었다 — `SelectedFile` 은 Git 모드에서만 채워지는데 그걸 보고 있었다. `CurrentFilePath` 로 바꿔 `.cs`·`.cpp` 모두 검사된다(확인: `이상 없음`). `전체 되돌리기` 버튼 글자가 두 칸 배치에서 잘리던 것도 한 줄에 하나씩으로 폄. |
|
||
| 2026-09-07 | **폴더 비교 → 파일 비교 더블클릭이 안 먹던 것** | **완료.** 기능은 이미 있었는데 **탭 순서를 바꾸면서 깨졌다**. 탭 내용은 그 탭을 <b>처음 열 때</b> 만들어진다. 폴더 비교가 첫 화면이 되면서, 파일을 처음 더블클릭하는 순간에는 파일 비교 화면이 아직 없어 요청 이벤트를 받을 사람이 없었다. 요청은 허공에 사라지고, 뒤이어 만들어진 화면은 기본 데모 파일을 열었다 - 겉보기에 "더블클릭이 안 먹는다". `GitWorkspace` 가 요청을 **남겨 두고**, 화면이 만들어질 때 스스로 집어 가도록 고쳤다(`HasPendingPlainCompare` / `DeliverPendingPlainCompare`). **곁들여 고친 것**: ① 한쪽에만 있는 파일(왼쪽만·오른쪽만)은 열리지 않았다 — 오히려 그런 파일이야말로 "뭐가 들었길래 새로 생겼나"를 보고 싶은 대상이다. 없는 쪽을 빈 내용으로 열어 전부 추가(또는 삭제)로 보이게 했다. ② 열 수 없는 항목(폴더·이진 파일)을 눌러도 **아무 일도 일어나지 않아** 기능이 없는 줄 알게 됐다. 왜 못 여는지 토스트로 알린다. ③ Enter 로도 열린다. ④ 클릭한 자리에서 항목을 직접 집는다 — 펼침 화살표처럼 선택을 바꾸지 않는 자리를 두 번 누르면 엉뚱한 항목이 열렸다. ⑤ 안내 문구가 없어진 탭 이름("홈 화면")을 가리키고 있던 것을 고쳤다. **실행 확인**: 프로그램을 새로 켠 뒤 **첫 더블클릭**부터 바로 열림 — 양쪽 다 있는 `Weld.cs`(총 5 라인·차이 2 라인), 왼쪽에만 있는 `Legacy.cs`(총 1 라인·차이 1 라인) 모두 정상. 폴더는 접기/펼치기만 된다. |
|
||
| 2026-09-07 | **탭 순서·용어 정리 · 데모 전환 · 모니터 2 확인** | **완료.** ① **탭 순서를 실제 작업 순서로**: `폴더 비교 → 파일 비교 → Git`. 사용자가 짚은 대로 "폴더를 먼저 보고 고칠 파일을 골라 들어가는" 흐름이 맞다. `홈` 이라는 이름도 하는 일과 맞지 않아 `파일 비교` 로 바꿨다. 폴더 비교에서 더블클릭하면 파일 비교 탭으로 넘어가므로 흐름이 이어진다. ② **용어를 머지툴 표준으로**: `LOCAL (Mine)` · `BASE` · `REMOTE (Theirs)` · `MERGED`, 버튼은 `Take Mine` / `Take Theirs`, 범례는 `Theirs only` / `Conflict`. 한글 풀이(내 작업 원본·공통 조상·고른 브랜치·최종 결과)와 곁들인 설명 줄은 지웠다 — 이 용어는 Git 과 다른 머지툴에서 그대로 쓰이므로 여기서만 다르게 부르면 옮겨 다닐 때 오히려 헷갈린다. ③ **데모 전환 버튼**(발표용): 상단의 `데모 → .git 있음/없음` 하나로 Git 저장소 화면과 파일 비교 화면을 즉시 오간다. 설정에 `DemoGitPath`·`DemoPlainPath` 를 넣었고 둘 다 실재할 때만 버튼이 뜬다. **여기서 결함 둘을 잡았다** — (1) 전환 중 3-Way 를 끄면서 부른 재로드가 **작업 게이트를 먼저 잡아** 뒤따르는 저장소 닫기·파일 비교가 "다른 작업 진행 중"으로 통째로 건너뛰어져 화면이 빈 채 남았다(`_suspendReload` 로 차단). (2) 늦게 끝난 Git 본문 로드가 이미 바뀐 화면을 덮어써 **경로는 새 파일인데 내용은 옛 파일**이 됐다(양쪽 로드의 UI 반영 직전에 모드가 그대로인지 확인). **실행 확인**: 21줄 레시피 ↔ 34줄 StartWeld.cs 를 세 번 왕복해도 매번 정확. ④ **3-Way 워드랩 재검증**: LOCAL 4줄 접힘 · REMOTE 3줄 접힘 · BASE 빈칸인데도 `void StartWeld()` 가 세 칸 **정확히 같은 y**. 아래 MERGED 는 폭이 넓어 같은 줄이 한 줄에 들어가고 빈칸이 안 생긴다. ⑤ **모니터 2 확인**(1920×1080 @100%, 모니터 1 은 2560×1600 @150%): 4분할·워드랩·용어 모두 정상, 배율 때문에 깨지는 곳 없음. 상단 툴바만 폭에 맞춰 두 줄로 접힌다(정상 동작). |
|
||
| 2026-09-07 | **워드랩 4분할 대응 · 전체화면 점검** | **완료.** ① 3-Way 로 패널이 넷이 되면서 행 높이 계산이 어긋나 있었다 — `MergeLine.ReportTextHeight` 가 BASE·LOCAL **둘만** 보고 있어 REMOTE·LOCAL원본이 접혀도 반영되지 않았다. 더 중요한 것은 **맞춰야 할 묶음이 하나가 아니라는 점**이다. 3-Way 에서 위 원본 세 칸은 폭이 같아 서로 맞춰야 하지만, 아래 MERGED 는 폭이 가로 전체라 접히는 자리가 애초에 다르다. 같은 높이를 강요하면 MERGED 는 안 접힌 줄에 빈칸이 생기고 그 위에 겹친 편집기와도 어긋난다. 그래서 높이를 **`RowHeight`(MERGED·편집기)** 와 **`SourceRowHeight`(원본 세 칸)** 둘로 나눴다(2-Way 에서는 같은 값). ② 같은 이유로 글자 폭 보정(`MatchTextWidths`)도 모드를 타게 했다 — 2-Way 는 BASE 가 미니맵 폭만큼 물러나야 LOCAL 과 맞지만, 3-Way 에서 그러면 **BASE 만 좁아져** 위 세 칸의 접히는 자리가 어긋난다. 모드가 바뀌면 다시 재도록 `IsThreeWay` 변경을 구독한다. ③ 폴더 비교의 줄 배경이 **글자 끝에서 끊겨** 넓은 화면에서 색 띠가 중간에 잘려 보였다. TreeViewItem 기본 템플릿이 머리를 `Auto` 폭으로 잡아 `HorizontalContentAlignment=Stretch` 가 듣지 않는다 — 템플릿을 갈아끼우면 플랫폼 테마를 잃으므로 배경 띠에 트리 폭만큼 `MinWidth` 를 주고 넘치는 부분은 잘리게 뒀다. ④ `줄바꿈 끄기` 버튼 글자가 칸을 넘어 잘리던 것을 `줄바꿈 켬/끔` 으로 맞춤(`필터 켬/끔` 과 같은 꼴). **실행 확인**(2560×1600 최대화): 2-Way 는 BASE 의 빈 블록이 LOCAL 의 접힌 높이를 그대로 따라가 `void StartWeld()` 가 같은 눈높이. 3-Way 는 LOCAL 4줄 · REMOTE 3줄로 접힘이 다른데도 위 세 칸이 같은 높이로 맞물리고, 아래 MERGED 는 폭이 넓어 **한 줄에 다 들어가며 빈칸이 안 생긴다**. 접힌 줄에서 캐럿도 논리 행/열을 정확히 보고한다(`End` → `5행 67열`, 시각 줄이 아니라 실제 줄 기준). 폴더 비교도 실제 프로젝트 폴더(`Views` ↔ `Services`, 27개)로 전체화면 확인. |
|
||
| 2026-09-07 | **1-3 폴더 비교 (별도 탭)** | **완료.** 새 파일 `Services/FolderComparer.cs` · `ViewModels/FolderViewModel.cs` · `Views/FolderView.xaml` · 테스트 **27/27**. 홈에 넣지 않고 **탭을 따로** 뒀다 — 홈은 3-Way 에서 이미 네 칸을 쓰고 있어 트리를 얹을 자리가 없다. 담은 것: 트리 뷰(하위 폴더 재귀) · 상태 5종(같음 / 다름 / 왼쪽만 / 오른쪽만 / **다름(이진)**) · **전체 내용 ↔ 빠른 비교(크기+수정일)** 전환 · 한도(기본 8MB)를 넘는 파일은 전체 비교를 골라도 자동으로 빠른 비교 · 정규식 **포함·제외** 필터(기본 제외에 `.git` · `bin` · `obj` · `.dll` · `.pdb`) · 같은 파일 숨기기 · 요약(`전체 N개 · 다름 N · 왼쪽만 N · 오른쪽만 N · 같음 N`) · **좌↔우 복사와 삭제(원본·대상 경로를 그대로 보여 주는 확인 대화상자 필수, 기본 선택은 취소)** · 항목 더블클릭 → 홈 탭에서 줄 단위 비교. 비용이 드는 것은 파일을 여는 일뿐이라 **열기 전에 거를 수 있는 것을 먼저 거른다** — 크기가 다르면 내용을 안 보고, 내용 비교도 64KB 씩 읽다가 다른 곳을 만나면 즉시 멈춘다. 실수로 `C:\` 를 고른 경우를 대비해 5만 항목에서 끊고 요약에 그렇다고 적는다. **실행 확인**: 데모 폴더 두 개 → `절차서.txt`·`Weld.cs` 다름, `Legacy.cs` 왼쪽만, `New.cs` 오른쪽만, `bin/tool.dll` 은 기본 제외 규칙으로 빠짐(`전체 5개 · 다름 2 · 왼쪽만 1 · 오른쪽만 1 · 같음 1`). `Weld.cs` 를 더블클릭하니 홈 탭으로 넘어가 두 파일이 줄 단위로 열렸다(`1800→2000`, `Emit→EmitFast` 단어 단위 강조). **곁들여 고친 플랫폼 결함**: 코드로 탭을 옮기면(새 API `TabManager.Activate`) **내용만 바뀌고 네비게이션 강조는 그대로 남아** 두 곳이 어긋났고, 그 상태에서 강조된 탭을 눌러도 이미 선택된 항목이라 아무 일도 일어나지 않았다. |
|
||
| 2026-09-07 | **3-Way 를 4분할로 재구성 · 캐럿 가로 어긋남** | **완료.** ① 사용자 지적대로 **일반적인 3-Way 도구 구성(원본 3 + 결과 1)**으로 바꿨다. 위에 **LOCAL(내 작업 원본) · BASE(공통 조상) · REMOTE(고른 브랜치)** 를 읽기 전용으로 나란히, 아래에 **MERGED(최종 결과)** 를 폭 전체로 두고 여기서만 고친다. 원본을 넷째 칸으로 붙이지 않은 이유 — 한 칸이 40자도 안 돼 코드를 읽을 수 없다. 세로를 쓰면 위는 68자, 아래는 200자 넘게 나온다. 2-Way 는 아래 두 줄이 높이 0 이라 지금까지의 좌우 배치 그대로다. `MergeLine.OriginalLocalText` 를 새로 붙들어 둔다 — **이게 없으면 REMOTE 를 한 번 가져오는 순간 내 원래 내용이 화면에서 사라져** 정작 충돌을 판단할 근거를 잃는다. LOCAL 패널의 `[<]` 와 ACTIONS 의 `내 것으로` 가 Accept Mine, REMOTE 쪽 `[<]` 와 `저쪽 것으로` 가 Accept Theirs 다. 위 세 칸은 3-Way 에서 머리를 74px 로 줄이고 바닥을 감춰(같은 정보가 아래 상태바에 있다) 코드를 더 보여 준다. ② **캐럿이 글자 가운데에 박히던 것**: LOCAL 표시층의 본문 테두리(문제 줄 표시용 2px)가 레이아웃 폭을 먹어 **BASE·REMOTE 및 그 위에 겹친 편집기보다 글자가 2 DIP 오른쪽에서 시작**하고 있었다. 테두리와 안여백의 합을 세 패널 모두 2 로 맞춰 해결. ③ **상태바 열 번호가 틀리던 것**: `TextBox.GetLineIndexFromCharacterIndex`·`GetCharacterIndexFromLineIndex` 는 "화면에 보이는 줄" 기준이라 글을 갈아 끼운 직후 `CaretIndex` 와 어긋난다(11글자 줄에서 Home 을 눌렀는데 `10열`). 글에서 직접 세도록 바꿔 Home=1열·End=길이+1 로 정확해졌다. |
|
||
| 2026-09-07 | **작업 4 다른 언어·문서 지원** | **완료.** 새 파일 `Services/LanguageProfile.cs`(언어 표 + `LanguageCatalog`) · `Services/CodeTokenizer.cs`(표를 보고 도는 범용 토크나이저) · 테스트 **40/40**, 기존 하네스 전부 유지(Align 37 · Move 11 · Editor 14 · Rules 21 · Sanity 20 · Token 15 · Note 16 · ThreeWay 20). 언어마다 토크나이저를 만들지 않았다 — 색칠에 필요한 것은 "주석은 어디서 시작하나 · 문자열은 무엇으로 묶나 · 예약어는 무엇인가" 셋뿐이고 나머지는 어느 언어나 같아서, **표 하나에 적고 토크나이저 하나가 그 표를 본다**. C# 만 전용 토크나이저를 그대로 쓴다(축자·보간 문자열 `@"" $""` 과 접근제한자 구분은 표로 담기지 않고 이미 테스트로 굳어 있다). 담은 것: C# · C/C++ · Java · JS/TS · Python · SQL(대소문자 무시) · 셸/배치(`rem` 포함) · XML/HTML/XAML · JSON · YAML · INI/설정 · Markdown · **평문(기본값)**. 모르는 확장자는 평문이라 **색을 잘못 입히는 일이 없다**. `CodeSanityChecker.AppliesTo` 의 확장자 switch 를 걷어내고 언어 표의 `HasBraces` 하나로 판단하게 바꿔, 괄호로 블록을 여닫지 않는 형식(YAML·INI·평문)에는 검사를 걸지 않는다. 상태바에 `UTF-8 · LF · Python` 처럼 고른 언어를 띄운다. **이진 파일**은 앞 8KB 에 NUL 이 있으면 이진으로 보고(UTF-16 BOM 은 예외) 비교하지 않고 그렇다고 알린다 — 깨진 글자로 화면을 채우지 않기 위해서다. **실행 확인**: `.py` 두 개를 비교하니 `#` 주석·`def`/`if`·독스트링·숫자가 파이썬 규칙대로 칠해지고, 상태바가 `Python`, 코드 검사는 `검사 대상 아님`(파이썬은 중괄호를 쓰지 않는다)으로 나왔다. |
|
||
| 2026-09-07 | **작업 3 3-Way 비교** | **완료.** REMOTE 는 **사용자가 고르는 브랜치**다(상단 `3-Way 상대` 드롭다운). 고르면 BASE 가 `merge-base(HEAD, 고른 브랜치)`, LOCAL 은 워킹트리, REMOTE 는 그 브랜치의 파일이 된다 — BASE 를 HEAD 로 두면 "저쪽이 고친 것"과 "내가 고친 것"을 가를 수 없어서 반드시 공통 조상이어야 한다. 병합 중이면 브랜치를 고를 것도 없이 Git 이 들고 있는 세 벌(`GetThreeWayContent`)을 그대로 쓴다. 새 파일 `Services/ThreeWayAligner.cs` · 테스트 **20/20**. 세 글을 한꺼번에 정렬하지 않고 **BASE↔LOCAL · BASE↔REMOTE 두 번 정렬한 뒤 BASE 줄 번호로 맞물린다** — 검증된 2-way histogram 정렬기를 그대로 쓰기 위해서다. 양쪽이 같은 자리에 넣은 줄은 한 번 더 정렬해 짝지어 한 행으로 합친다(안 합치면 "둘 다 같은 줄 추가"가 충돌로 보인다). 판정은 `MergeLine.ThreeWay` — 같음 / 나만 고침 / 저쪽만 고침 / 둘 다 같게 / **충돌**. 색은 저쪽만 고침=남색, 충돌=자홍(가장 눈에 띄게, 이동·단순 차이보다 앞세움), 범례에도 3-Way 일 때만 두 항목이 붙는다. REMOTE 줄의 `[<]` 버튼과 ACTIONS 의 `저쪽 것으로` 로 그 줄을 가져오고, 되돌리기 스택은 BASE 반영과 같은 것을 쓴다. 3-Way 를 안 쓰면 REMOTE 칸은 **폭 0 으로 접힌다**(Visibility 만 숨기면 star 열이 자리를 그대로 차지한다). **실행 확인**: 데모 저장소에 공통 조상에서 갈라진 `feature/cooling` 을 만들어 붙였더니 `laser.Power`·`Wait()` 두 줄이 **충돌 2**, `fan.Speed = 70;` 이 **저쪽만 고침 1** 로 잡히고, `[<]` 로 가져오니 머지 주석까지 붙어 LOCAL 에 들어왔다(편집 1건). 세 패널의 같은 행이 정확히 같은 눈높이. **곁들여 고친 것**: `LoadFileAsync` 도 `RunAsync` 실패 시 화면을 갈아엎지 않게 막았다(파일 비교에서 겪은 것과 같은 결함). |
|
||
| 2026-09-07 | **캐럿 어긋남 · 입력 지연 · 화면 배율 · 데모 기본값** | **완료.** ① **캐럿이 글자에 안 맞던 원인**: 편집기와 표시층을 맞출 때 기준이 서로 다른 두 좌표를 견줬다. 별도 WPF 프로브(`scratchpad/LineProbe`)로 직접 재 보니 Consolas 12·줄높이 20 에서 `TextBox.GetRectFromCharacterIndex(0).Top = 4.67`(줄상자 위 여백을 지난 **글자 상자** 위쪽), `TextBlock` 의 `(0,0) = 0`(**줄상자** 위쪽). 이 여백만큼 표시층이 아래로 밀려 선택 영역이 글자보다 반 줄 위에 있는 것처럼 보였다. 여백을 `BaselineOffset − FontFamily.Baseline×FontSize` 로 글꼴에서 직접 구해 빼도록 고침(상수를 안 써서 배율이 바뀌어도 따라간다). 덧붙여 **BASE 패널에도 같은 이동값**을 걸었다 — LOCAL 만 밀면 두 패널의 줄이 6px 어긋난다(UIA 로 확인: 어긋남 0). ② **입력 지연의 남은 절반**: 화면 글자는 편집기가 아니라 표시층이 그리는데(편집기 글자는 투명) 표시층을 600ms 재정렬 타이머에만 맡겨 **친 글자가 그때까지 안 보였다**. `ShowTypedLineNow` 로 캐럿이 있는 줄만 즉시 반영(줄 수가 달라지면 재정렬에 맡김). **실행 확인**: 타이핑 120ms 뒤 촬영해 `-RC7` 이 이미 보이고 캐럿이 글자 끝에 정확히 붙음. ③ **화면 배율**: 지금까지 상·하단 바만 커지고 정작 작업 화면은 그대로였다. 플랫폼 `ShellWindow` 의 콘텐츠에 `LayoutTransform` 을 걸고 `UiSettingsService.ContentScale`(= ChromeScale ÷ 기준 1.2, 즉 "100% = 지금 그대로") 추가. **실행 확인**: 80% 에서 코드 행 높이 30px → 24px(UIA 측정), 같은 화면에 더 많은 줄. ④ **데모를 .git 없는 폴더로**: `plain-compare` 의 용접 레시피 두 개(`WeldRecipe_기준.txt` ↔ `WeldRecipe_내작업.txt`)를 기본으로 열게 함(`DefaultLeftFile`/`DefaultRightFile` 설정 추가). **곁들여 고친 실제 결함**: 저장소가 아닌 폴더에 자동 열기를 걸면 실패할 뿐 아니라 **작업 게이트를 쥐고 있어 뒤따르는 파일 비교가 통째로 취소**돼 화면이 `차이 없음` 으로 비었다. `GitWorkspace.LooksLikeRepository` 로 저장소일 때만 자동 열기를 시도하고, `LoadPlainFilesAsync` 도 `RunAsync` 실패 시 화면을 갈아엎지 않게 함. |
|
||
| 2026-09-07 | **작업 2 Git 유무 분기** | **완료.** `.git` 이 없으면 커밋 이력 칸을 접고(폭 0) Git 상태·새로고침·파일 목록·커밋 상세·커밋 메시지를 숨긴다. 대신 상단에 **기준 파일 / 내 파일** 고르기가 나오고, 패널 제목이 `기준 파일 / 내 파일` 로 바뀌며(Git 용어 안 씀), 저장 버튼이 `Save & Commit` → `저장`(커밋 없이 오른쪽 파일에 쓰기)이 된다. 모드는 상단 배지로 항상 보인다. 새 파일 `Services/TextFile.cs` — 인코딩·줄바꿈 판별 규칙을 `GitService` 와 동일하게 맞춰, 같은 파일을 어느 경로로 열든 결과가 같고 저장할 때 형식이 바뀌지 않는다. **실행 확인**: Git 아닌 폴더의 `left.txt`↔`right.txt` 비교 → 다름 1 · 추가 1, 전체 반영 후 저장하니 파일이 정확히 갱신됨(머지 주석 포함). Git 모드 복귀도 이상 없음. |
|
||
| 2026-09-07 | **설정 반영·패널 높이·ACTIONS 잘림 수정** | 플랫폼 `SettingsService` 인스턴스 분리 버그를 고쳐(아래 플랫폼 변경 이력) **설정 → 저장 → 홈 복귀만으로 재비교**되게 함(`RecompareIfSettingsChanged`, 홈이 다시 보일 때 설정 서명이 바뀌었으면 한 번만). BASE/LOCAL 하단 요약 칸을 공통 높이(`PaneFooterHeight` 54)로 맞춰 두 패널의 코드 영역 크기를 같게 함 — LOCAL 쪽 3줄을 2줄로 합침. ACTIONS 패널에 스크롤을 주고 폭을 196 → 214 로 넓혀 잘리지 않게 함. |
|
||
| 2026-09-07 | **타이핑 지연 해소 · 버튼 재배치 · 검사 팝업** | **완료.** ① **지연의 진짜 원인**은 겹친 레이어가 아니라 글자마다 도는 두 가지였다 — 문서 전체를 문자열로 복사(`TextBox.Text` 양방향 바인딩)와 **전체 줄을 훑는 차이 판정**(무시 규칙이 켜져 있으면 양쪽 줄을 정규화). 15,005줄 파일 기준 각각 0.12ms / **2.19ms** 한 타. 바인딩을 걷어내 편집기가 글을 직접 들고(ViewModel 은 필요할 때만 읽음), 차이 덩어리 목록을 캐시하고, 캐럿이 같은 줄 안에서 움직이면 명령 상태 갱신을 건너뛰게 했다. 캐시 조회는 0.000ms. ② 차이 탐색·비교 규칙 버튼을 코드 패널 위에서 **ACTIONS 의 커밋 메시지 아래**로 옮김(읽는 자리와 조작하는 자리를 분리). 머리 높이도 150 → 124 로 복귀. ③ 코드 검사 요약을 눌러 **팝업으로 문제 목록**을 보고, 항목을 누르면 그 줄로 이동. **곁들여**: 화살표 글리프(⤒↑↓⤓)가 이 서체에 없어 빈 버튼으로 나오던 것을 글자로 교체, 파일 로드 시 차이 캐시가 갱신되지 않아 `차이 없음` 으로 잘못 나오던 것 수정. |
|
||
| 2026-09-07 | **1-2 무시 규칙** | **완료.** `Services/CompareRules.cs` · 테스트 21/21, 기존 정렬 37/37 유지. 공백 3단계 · 대소문자 · 정규식 줄 필터. 툴바에서 즉시 토글되고 상태바에 `무시: 공백 개수 · 대소문자 · 줄필터 1` 로 요약된다. **구현 갈래가 둘**이다 — 공백·대소문자는 정렬 단계의 *비교용 키*(`LineAligner.Align` 에 keys 인자 추가, 원문은 보존), 줄 필터는 정렬 뒤 행 표시(`MergeLine.IsIgnored`). 필터를 정렬 키에 섞으면 걸린 줄끼리 같은 것으로 묶여 엉뚱하게 짝지어진다. **곁들여 고친 것**: ① `MergeLine.State` 가 원문끼리만 비교해 규칙이 안 먹던 문제 → 정규화 함수를 넘겨 해결 ② 무시된 줄이 차이 탐색에 걸리던 문제. **실행 확인**: 다름 3 → (공백) 1 → (대소문자) 0, 추가 3 → (줄필터) 1 + 무시 2, `차이 - / 2` → `- / 1`. |
|
||
| 2026-09-07 | **1-1-B 이동 블록 감지** | **완료.** `Services/MoveDetector.cs` · 테스트 11/11. 지워진 구간과 추가된 구간에서 **줄이 이어지는 최장 공통 부분**을 찾아 이동으로 묶는다(구간 전체를 견주면 정렬기가 `}`·빈 줄을 한쪽에 붙여 놓아 어긋난다). 2줄 미만이거나 중괄호·빈 줄만인 구간은 제외. 색은 청록(삭제/추가와 계열 구분), 범례에 `자리 옮김` 추가, 툴팁에 `24행으로 옮김`. **실행 확인**: 데모 파일의 `Cooldown()` 을 옮겨 두니 범례가 `자리 옮김 6` 으로 잡힘. |
|
||
| 2026-09-07 | **LOCAL 행 구조 개편 (워드랩 준비)** | 여백(줄번호·`[>]`)을 별도 컨트롤에서 **행 안쪽으로** 옮겨 높이가 저절로 맞게 함. 가로 스크롤 때는 글자만 `TranslateTransform` 으로 밀고 열에서 클리핑. BASE 여백도 54로 맞추고, 세 곳의 글자 폭을 스크롤바·미니맵 폭만큼 보정해 접히는 자리를 일치시킴. 워드랩 토글 버튼 추가. **화면 확인 완료** — 가로 스크롤 시 여백 고정, 줄 번호가 두 패널에서 정확히 같은 눈높이. 워드랩도 양쪽이 같은 자리에서 접히고 행이 맞물림(`MergeLine.RowHeight` 로 큰 쪽 높이를 공유). |
|
||
| 2026-09-07 | **1-1 파일 비교 (워드랩 제외)** | **완료.** 차이 탐색(첫/이전/다음/마지막 · `Alt+↑↓` `Ctrl+Home/End`, 끝에서 순환) · 상태바(`12행 5열` · `차이 2 / 3` · 인코딩 · 줄바꿈) · `Ctrl+G` 줄 이동 · 북마크(여백 더블클릭, `F2`) · 편집 잠금. 차이는 **덩어리 단위**로 센다(12줄 삭제 = 차이 1개). 인코딩·줄바꿈 판별은 `GitService.DescribeWorkingFile` 로 노출. **워드랩은 남김** — 아래 참고. |
|
||
| 2026-09-07 | **LOCAL 패널을 상시 편집기로 전환** | **완료.** "전체 편집" 모드 버튼 삭제. LOCAL 칸이 항상 편집 가능(여러 줄 선택·붙여넣기·삭제). 화면은 세 겹 — 왼쪽 여백(줄번호·`[>]`) / 색·문법 표시층 / 투명 편집기. BASE 와 눈높이를 맞추려고 지워진 줄 자리에 빈 줄(필러)을 넣고, 저장·재정렬 전에 `EditorLayout.StripFillers` 로 걷어낸다(테스트 14/14). 타이핑이 멈추면(600ms) 다시 정렬. **곁들여 고친 것**: 편집 후 원래부터 BASE 와 달랐던 줄까지 전부 "직접 수정"으로 칠해지던 문제 → 파일을 연 시점 LOCAL 과 견줘 실제로 손댄 줄만 표시. |
|
||
| 2026-09-07 | **1-1-A 정렬 교체 (LCS → Histogram)** | **완료.** `AlignTest` 26건 유지 + 신규 11건 = **37/37 통과**. 빌드 경고 0. 데모 파일에서 중복된 `fan.Off();` 가 엉뚱한 짝에 붙던 문제가 실제로 해소됨. 안전선을 표 크기(`MaxCells` 400만 칸)에서 줄 수(`MaxRegionLines` 2만 줄)로 바꿈 — 히스토그램은 표를 만들지 않으므로 예전보다 훨씬 큰 구간도 정확히 정렬한다. |
|