721줄짜리 진행상황.md 를 날짜별 파일과 changelog 로 나누고 73줄로 줄였다. 지시서 네 개는 git mv 로 doc/작업지시/ 에 모았다. 링크 15개 전부 살아 있다. 옮기기만 하고 내용은 고치지 않았다.
24 KiB
작업 지시 — MergeHub 사용성 보강 (2차)
대상: D:\Sorce\MergeTool\MergeHub (플러그인) · D:\Sorce\MergeTool\UbisamPlatform (셸)
전제: 1차 지시서(머지툴보강.md)의 작업 14 · 1-11-3 은 모두 끝난 상태다.
공통 규칙
- 항목 하나를 끝낼 때마다 빌드하고 실제로 실행해 화면을 확인한 뒤 보고할 것. 전부 끝내고 한 번에 보고하지 말 것.
- 기존 테스트 하네스(Align 37 · Move 11 · Editor 14 · Rules 21 · Sanity 20 · Token 15 · Note 16 · ThreeWay 20 · Lang 40 · Folder 27 = 221건)는 계속 통과해야 한다. 로직을 건드리면 테스트를 먼저 늘린다.
- 빌드 경고 0 · 오류 0 을 유지한다.
- 플랫폼(
UbisamPlatform)을 고치면 다른 소비 프로그램에 미치는 영향을 함께 적고doc/history/changelog.md에 남긴다.
1. 사용자 이름 등록
1-1. 첫 실행 시 이름 입력
- 프로그램을 켰을 때 등록된 사용자 이름이 없으면 이름을 묻는 창을 띄운다.
- 입력값은
D:\UbisamConfig아래에 저장한다. - 이미 등록돼 있으면 창을 띄우지 않는다. 매번 뜨면 안 된다.
- 설정 화면에서 언제든 바꿀 수 있어야 한다(지금의
MergeHub > 머지 주석 > 작성자칸이 그 자리다). - 빈 값으로 넘어가려 하면 막거나, 넘어가더라도 다음 실행에 다시 묻는다.
1-2. 머지 주석이 이 이름을 쓴다
현재 GitWorkspace.ResolveAuthorName() 이 설정값 → git config user.name → 윈도우 계정 순으로 고른다.
1-1 에서 등록한 이름이 이 "설정값" 자리에 들어가면 된다 — 순서 자체는 그대로 두는 것이 맞다(설정을 비워 두면 Git 설정을 따라가는 지금 동작이 쓸모 있다).
판정 기준: 이름을 처음 등록하고 아무 줄이나 반영하면 주석에 그 이름이 나온다. 프로그램을 다시 켜도 묻지 않는다.
2. 머지 주석을 "쌓이게" 바꾸기
2-1. 지금 동작
Services/MergeNote.cs 가 줄 끝에 주석을 붙인다(Append). 그 파일 주석에 적힌 이유는:
줄 "위"가 아니라 "끝"에 붙인다 - BASE/LOCAL 을 같은 줄 번호로 나란히 보여주는 구조라 줄을 새로 끼워 넣으면 두 패널의 정렬이 통째로 어긋난다.
이 제약이 지금도 유효한지 먼저 확인하라. 그동안 정렬기(histogram)와 필러 처리가 바뀌었으므로, 줄을 끼워 넣어도 정렬이 스스로 맞을 수 있다. 유효하다면 어떻게 우회할지 설계부터 적고 시작한다.
2-2. 바꿀 동작
- 주석을 그 줄 위에 별도 줄로 넣는다(줄 끝 X).
- 같은 줄을 다시 반영하면 기존 주석을 지우지 않고 새 주석을 추가한다.
- 쌓이는 순서는 새 주석이 코드 줄 바로 위, 오래된 주석일수록 위로 밀린다.
// [hong] 2026-09-01 1차 반영 ← 가장 오래된 것이 맨 위
// [kim] 2026-09-05 재확인
// [lee] 2026-09-07 최종 ← 가장 최근이 코드 바로 위
laser.SetPower(2000);
- 주석 기호는 지금처럼 언어를 따른다(
MergeNote.CommentTokensFor).LanguageProfile이 이미 언어별 주석 기호를 들고 있으므로 둘 중 하나로 합치는 것을 검토하라 — 같은 지식이 두 곳에 있으면 언젠가 어긋난다.
2-3. 반드시 확인할 것
- 주석 줄이 늘어나도 BASE ↔ LOCAL(↔ REMOTE ↔ MERGED) 행이 어긋나지 않아야 한다.
- 저장했다가 다시 열었을 때 주석이 중복으로 다시 붙지 않아야 한다.
- 되돌리기(Undo · Revert · 전체 되돌리기)로 주석도 함께 사라져야 한다.
NoteTest하네스(16건)를 이 동작에 맞게 늘린다.
3. 차이 이동에서 행이 안 맞는 문제 (결함)
이전 차이 · 다음 차이 · 처음 · 마지막 을 누르면 행 위치가 어긋난다.
- 재현 조건부터 정확히 적어라 — 워드랩 켬/끔, 2-Way/3-Way, 필러 줄이 있는 경우 각각.
- 관련 코드:
HomeViewModel의_diffStarts·ComputeDiffBlockStarts·GoToRow,HomeView.OnScrollToRowRequested(현재LocalEditor.ScrollToLine(row - 3)으로 위 여유 3줄을 둔다). - 의심 지점:
ScrollToRowRequested는 편집기의 줄 인덱스로 스크롤하는데, 표시층은 ListBox 의 픽셀로 따라간다. 워드랩이 켜져 있으면 한 행이 여러 시각 줄이라 둘이 어긋난다. - 고친 뒤에는 선택된 행이 화면 안에 들어오고, 세 패널(또는 네 패널)이 같은 행에 서 있어야 한다.
판정 기준: 워드랩을 켠 3-Way 상태에서 처음→다음 차이를 끝까지 눌러도 매번 그 차이 줄이 화면에 보이고 네 패널이 같은 줄을 가리킨다.
4. WinMerge 단축키
4-1. 적용
지금 있는 것: Alt+↑/↓(이전/다음 차이) · Ctrl+Home/End(처음/마지막) · Ctrl+G(줄 이동) · F2(북마크).
WinMerge 기준으로 맞추고 빠진 것을 채운다. 최소한 아래는 넣는다.
| 키 | 동작 |
|---|---|
Alt+↓ / Alt+↑ |
다음 / 이전 차이 |
Alt+Home / Alt+End |
첫 / 마지막 차이 |
Alt+← / Alt+→ |
왼쪽→오른쪽 / 오른쪽→왼쪽 반영 (3-Way 에서는 Take Mine / Take Theirs) |
Ctrl+S |
저장 |
F5 |
다시 비교 |
F7 / Shift+F7 |
다음 / 이전 차이(대체 키) |
Ctrl+G |
줄 이동 |
F2 |
다음 북마크 |
Ctrl+F |
찾기 (없으면 이 항목은 범위 밖으로 빼고 그렇다고 보고할 것) |
- 편집기가 먼저 삼키는 키가 있으므로
PreviewKeyDown에서 가로챈다(지금 방식 유지). - 기존 편집 동작을 뺏으면 안 된다 — 예:
Ctrl+A,Ctrl+Z는 편집기 것이다. - 실제로 WinMerge 와 다르게 정한 것이 있으면 왜 다른지 적어라.
4-2. 단축키 설명 창
- 우측 상단에 버튼을 두고, 누르면 단축키 목록 창이 뜬다.
- "우측 상단"이 어디인지 확인할 것 — 지금 화면에서 그 자리는 ACTIONS 패널 위쪽이거나 상단 툴바 오른쪽 끝이다. 둘 중 눈에 띄고 다른 것을 밀어내지 않는 자리를 고르고 이유를 적는다.
- 목록은 코드에 박은 문자열이 아니라 실제 키 처리와 한 곳에서 나와야 한다 — 둘이 갈라지면 설명이 거짓말이 된다.
5. 소스가 더 잘 보이게 — 상·하단 줄이기 (플랫폼)
이건 플랫폼 변경이라 다른 소비 프로그램에 모두 영향이 간다. 먼저 영향 범위를 적고 시작할 것.
5-1. 상단 브랜딩 바
ShellWindow.xaml — Padding="26,14", 로고 Height="30", 장비명 FontSize="18", 시계 FontSize="25".
5-2. 하단 탭 바
ShellStyles.xaml 의 Ubisam.Style.SidebarItem.Horizontal — Padding="30,13,30,14", 아이콘 22x22, 아이콘 아래 여백 7, 글자 13.5.
5-3. 방향
- 두 줄을 합쳐 세로로 최소 40~60px 은 벌어야 코드가 눈에 띄게 더 보인다.
- 다만 터치로도 누르는 장비라는 점을 잊지 말 것. 탭은 손가락으로 누를 수 있는 크기를 유지해야 한다 — 무작정 줄이면 안 된다.
- 가능하면 크기를 상수로 박지 말고 지금의 화면 배율(
UiSettingsService.ContentScale)처럼 한 곳에서 정하도록 빼라. 장비마다 다르게 쓸 여지가 생긴다. - 줄이기 전후의 코드 표시 줄 수를 실제로 세어 얼마나 늘었는지 숫자로 보고할 것.
진행 순서
1 사용자 이름 등록 (독립적, 먼저 끝내면 다른 작업의 주석 확인이 쉬워진다)
3 차이 이동 행 어긋남 (결함 — 다른 작업 확인에 계속 걸린다)
2 머지 주석 쌓기 (정렬에 영향이 크므로 3 이 끝난 뒤)
4 단축키 + 설명 창
5 상·하단 줄이기 (플랫폼)
2번을 3번 뒤로 미룬 이유 — 주석 줄이 늘어나면 행 정렬이 흔들리는데, 그 상태에서 차이 이동 결함까지 겹치면 무엇이 원인인지 가릴 수 없다.
결정 사항 (2026-09-07, 사용자 확인 완료)
- 주석은 고친 줄 위에 올린다. 새 주석이 코드 줄 바로 위에 붙고 기존 주석은 위로 밀린다. 정렬 제약은 우회해서라도 이 동작으로 간다.
- 사용자 이름은 플랫폼의 "현재 사용자"로 둔다. 다른 소비 프로그램도 쓸 수 있어야 한다.
- 찾기(
Ctrl+F) 를 포함해 머지툴에 맞는 단축키를 전부 넣는다. 찾기 기능 자체도 만든다. - 터치는 필수가 아니다. 상·하단을 줄인다.
진행 기록
| 날짜 | 항목 | 결과 |
|---|---|---|
| 2026-09-07 | 문서 작성 | 착수 전 |
| 2026-09-07 | 1. 사용자 이름 등록 | 완료. 플랫폼에 CurrentUserService 신설(D:\UbisamConfig\Settings\CurrentUserService.json). 이름이 없으면 첫 실행에 UserNameDialog 로 한 번만 묻는다(취소 버튼 없음 - 넘어가면 다음 실행에 또 물어야 하고, 그러면 "매번 뜨는 성가신 창"이 된다). 소비 프로그램은 DI 로 주입받아 쓴다. GitWorkspace.ResolveAuthorName() 순서는 MergeHub 설정 → 플랫폼 사용자 → git config → 윈도우 계정. 플랫폼 사용자를 git config 보다 앞에 둔 이유 - 사람이 직접 적어 넣은 이름이고, 장비를 여럿이 쓰는 현장에서는 그게 실제 작업자다. 곁들여 고친 것: 작성자 이름을 저장소를 읽을 때만 정하고 있어서, Git 없이 파일 두 개를 비교하면 이름이 비고 주석에 윈도우 계정이 찍혔다. 생성 시점에 한 번 정하고 설정에서 바꾸면 따라가게 했다. 실행 확인: 이름 없이 켜면 창이 뜨고, 김상준 등록 뒤 다시 켜면 안 뜬다. 주석 미리보기가 // [김상준] 2026-09-07. |
| 2026-09-07 | 3. 차이 이동 행 어긋남 | 완료. 원인 둘. ① OnScrollToRowRequested 가 논리 행 번호를 "화면에 보이는 줄" API(GetCharacterIndexFromLineIndex)에 그대로 넘기고 있었다. 워드랩이 켜지면 한 행이 여러 줄로 접히므로 캐럿이 딴 줄로 갔다 - 실제로 상태바는 6행인데 화면에서 선택된 줄은 8행이었고 아래로 갈수록 더 벌어졌다(9행에서는 2줄 차이). 글에서 직접 세어 논리 행 → 글자 위치로 바꾸도록 고쳤다. ② 그렇게 고쳐도 화면이 안 굴러갔다 - TextBox.ScrollToLine 이 이 화면(편집기가 세 겹의 스크롤 주인)에서는 듣지 않아, 마지막을 눌러도 맨 위에 남았다. 캐럿의 실제 좌표를 재서 스크롤뷰어를 직접 옮기도록 바꿨다(워드랩이든 아니든 같은 방식). 실행 확인: 워드랩 켠 상태로 처음→다음 차이를 끝까지, 마지막, 이전 차이까지 눌러도 상태바 행과 화면에서 선택된 행이 매번 일치(5↔4, 8↔7, 10↔9, 27↔26, 38↔37). |
| 2026-09-07 | 2. 머지 주석을 위로 쌓기 | 완료. 주석을 줄 끝이 아니라 고친 줄 바로 위에 한 줄로 넣는다. 코드 줄의 들여쓰기를 그대로 따라간다. 같은 줄을 다시 반영하면 새 주석이 코드 바로 위에 들어가고 앞서 남긴 주석은 위로 밀린다(지우지 않는다). 정렬은 저절로 맞는다 - 끼워 넣은 줄은 "LOCAL 에만 있는 줄"이라 이미 있던 추가 줄 처리대로 BASE 쪽에 빈 자리가 생긴다. MergeNote.cs 에 적혀 있던 "줄을 끼워 넣으면 정렬이 어긋난다"는 제약은 그동안 정렬기와 필러 처리가 바뀌어 더는 유효하지 않았다. 여기서 결함 하나를 잡았다: 주석 줄이 BASE 에 없는 줄이라 차이로 잡혔고, 그래서 다음 Accept 나 전체 반영이 방금 남긴 주석을 지워 버렸다("BASE 를 따른다 = BASE 에 없는 줄은 없앤다" 규칙 때문). MergeLine.IsMergeNote 를 두어 주석 줄은 차이로 세지도, 반영 대상이 되지도 않게 했다. Undo/Redo/Revert 는 LineEdit.InsertedNote 로 주석 줄까지 함께 넣고 뺀다 - 본문만 되돌리고 주석을 남기면 파일에 유령 주석이 쌓인다. 실행 확인: 전체 되돌리기 43줄·주석 0 → 1회 반영 44줄·주석 1(반영한 줄 바로 위) → Undo 43줄·주석 0 → Redo 44줄·주석 1. 전체 반영은 반영한 줄마다 각자 위에 주석이 붙는다. |
| 2026-09-07 | 4. WinMerge 단축키 + 설명 창 | 완료. 키 표를 Services/ShortcutMap.cs 한 곳으로 모았다 — 키 처리(HomeView.View_PreviewKeyDown → RunShortcut)와 설명 창(Views/ShortcutHelpWindow)이 같은 목록을 읽으므로 설명이 실제 동작과 갈라질 수 없다. 넣은 키: Alt+↓/↑·F4/Shift+F4(다음·이전 차이), Alt+Home/End·Ctrl+Home/End(첫·마지막 차이), Alt+→/←(왼→오른·오른→왼 반영), Ctrl+Z/Ctrl+Y, Ctrl+M(북마크 설정/해제)·Alt+PageDown·F2(다음 북마크), Ctrl+G, Ctrl+D(폴더 비교), F5·Ctrl+R, Ctrl+S, Ctrl+F·F3/Shift+F3·Esc, F1(이 목록). 찾기 기능 자체도 만들었다 — 편집기 위에 떠 있는 찾기 칸(패널 머리·바닥에 끼우면 열 때마다 BASE 와 높이가 어긋난다), 대소문자 구분, 앞뒤로 한 바퀴 돌기, 몇 개인지 표시. 처리는 편집기가 아니라 화면 전체(UserControl.PreviewKeyDown) 에 건다 — 편집기에만 걸면 파일 목록이나 찾기 칸에 초점이 있을 때 단축키가 죽는다. WinMerge 와 다르게 정한 것 3가지: ① Ctrl+W(탭 닫기)는 넣지 않았다 — 탭이 고정이라 닫을 것이 없고, 아무 일도 않는 키는 없느니만 못하다. ② Ctrl+D 는 새 창이 아니라 폴더 비교 탭으로 간다 — 창을 여러 개 띄우는 도구가 아니다. ③ Ctrl+Z 는 머지 반영을 되돌리되, 되돌릴 머지 작업이 없으면 키를 먹지 않아 편집기의 글자 되돌리기가 그대로 산다(Run() 이 CanExecute 를 보고 판단). Alt 를 누르면 WPF 가 e.Key 에 Key.System 을 넣고 진짜 키를 e.SystemKey 로 보내므로 그것부터 풀어 준다. 버튼은 상단 상태 바 오른쪽 끝에 뒀다 — 그 줄이 내용에 따라 늘었다 줄었다 하는 WrapPanel 이라 그대로 넣으면 자리가 떠다녀서, DockPanel 로 감싸 오른쪽에 붙박았다. ShortcutTest(58건) 신설: 키 중복·풀림·편집기 몫 침범 여부·표기·묶음 순서·WinMerge 핵심 키 존재를 본다. 실행 확인: Alt+Home→첫 차이(5행), Alt+↓→다음 차이(8행), Alt+→→그 줄 반영(주석 포함, 머지 반영함 1), Ctrl+Z→되돌림(머지 반영함 0·Redo 켜짐). Ctrl+F 로 "Polarize" 찾기 3개, 27행 20열로 이동. F1/버튼 둘 다 목록 창이 뜬다. |
| 2026-09-07 | 5. 상·하단 줄이기 (플랫폼) | 완료. 크기를 XAML 안에 박아 두지 않고 ShellStyles.xaml 에 Ubisam.Metric.BrandingBar.* · Ubisam.Metric.NavItem.* 로 빼서, 소비 프로그램이 Application.Current.Resources 에서 같은 키를 덮어쓰면 장비마다 다르게 쓸 수 있다(기존 Ubisam.Metric.ContentPadding 과 같은 방식). 값: 브랜딩 바 여백 26,14→26,7, 로고 30→24, 구분선 24→18, 장비명 18→15, 시계 25→19 / 탭 여백 30,13,30,14→30,6,30,7, 아이콘 22→19, 아이콘 아래 여백 7→3, 글자 13.5→12.5. 줄 수 확인(2560×1600 @150%, 최대화): 하단 탭 바 135px→95px, 코드 편집 영역 958px→1038px(+80px), 코드 표시 줄 31줄 → 34줄(+3줄). 화면 배율 100% 기준 약 53 DIP 를 벌었다(목표 40~60). 다른 소비 프로그램 영향: 플랫폼 전체에 걸리므로 모든 프로그램의 상·하단 띠가 같이 얇아진다. 터치 장비라면 위 세 값(NavItem.Padding·IconSize·FontSize)만 되돌리면 원래 크기다. |
| 2026-09-07 | 곁들여 고친 것 3가지 | ① 켤 때마다 이름 확인: UserNameDialog.AskIfMissing → Ask. 한 장비를 여러 사람이 쓰므로 앞사람 이름으로 기록이 남으면 안 된다. 지난번 이름이 미리 채워지고 전체 선택돼 있어 같은 사람이면 Enter 한 번이다. ② 마우스 가로 휠: WPF 에는 가로 휠 이벤트가 아예 없어(MouseWheel 은 세로뿐) 창 메시지 WM_MOUSEHWHEEL(0x020E) 을 직접 후킹했다. 여기서 결함 하나를 더 잡았다 — 가로로 밀 때 BASE·REMOTE·LOCAL 원본 패널이 따라오지 않았다. 표시층 ListBox 를 가로로 굴리려 했는데, 행이 칸 너비에 맞춰 늘어나 굴릴 여지(ScrollableWidth)가 0 이라 아무 일도 일어나지 않았던 것. LOCAL 처럼 글자만 TextShiftX 만큼 미는 방식으로 네 패널을 통일했다(여백·줄번호는 제자리). ③ 아래로 스크롤한 상태에서 전체 되돌리기를 하면 글자가 위로 밀리던 것: AlignDecorationToEditor 가 편집기의 0번째 글자를 표시층의 처음 그려진 행과 견주고 있었다. 가상화 때문에 스크롤한 뒤에는 그 행이 0행이 아니라서, 스크롤한 거리만큼 어긋난 보정값이 들어갔다. 컨테이너에서 실제 행 번호를 얻어 같은 줄끼리 견주도록 고쳤다. 실행 확인: 전체 반영 후 아래로 스크롤 → 전체 되돌리기 → 줄 번호와 코드가 모든 행에서 일치. |
| 2026-09-07 | 가로 휠 — 3-Way 확인 중 결함 발견·수정 | 3-Way 에서 가로 휠이 아무 일도 하지 않았다. 스크롤 주인인 MERGED 는 폭 전체를 쓰므로 밀 여지가 없는데(ScrollableWidth 0), 정작 잘려 보이는 것은 위의 좁은 원본 세 칸(LOCAL(Mine)·BASE·REMOTE)이었기 때문이다. 게다가 그 세 칸에는 각자 따로 노는 가로 스크롤 막대가 달려 있어, 끌면 줄 번호까지 같이 밀려 나가고 세 칸이 서로 어긋났다. 바로잡은 방식: 가로 스크롤 그룹을 둘로 나눴다 — 폭이 같은 것끼리만 묶는다. ① 위 원본 세 칸(3-Way) = 한 덩어리, ② MERGED(2-Way 에서는 BASE+LOCAL) = 한 덩어리. 원본 칸용으로 SourceShiftX 를 새로 두고 세 템플릿이 그 값만큼 글자만 민다(줄 번호·[<] 는 제자리). 2-Way 에서는 BASE 와 LOCAL 의 폭이 같으므로 SourceShiftX 가 TextShiftX 를 그대로 따라간다 — 지금까지의 동작 그대로다. 휠은 마우스가 놓인 칸을 민다(WM_MOUSEHWHEEL 의 좌표 대신 Mouse.GetPosition 을 쓴다 — DPI 가 섞인 화면에서 창 메시지의 픽셀 좌표를 직접 환산하면 어긋난다). 원본 칸의 제 스크롤 막대는 Hidden 으로 껐다 - 두 방식이 겹치면 같은 것을 두 번 미는 꼴이 된다. 실행 확인(mergehub-demo, 3-Way = feature/cooling): BASE 위에서 오른쪽으로 6칸 → 세 칸이 똑같이 밀리고 줄 번호는 제자리, MERGED 는 그대로. 왼쪽으로 10칸 → 처음 자리에서 정확히 멈춤(과도 스크롤 없음). 2-Way 재확인: 100%→39.5%, BASE 동반 이동. |
| 2026-09-07 | 3-Way 확인 중 결함 둘 더 잡음 (원본 칸이 비어 버림 · 워드랩이 안 접힘) | ① MERGED 에 글자를 하나만 쳐도 LOCAL(Mine)·REMOTE 칸이 통째로 비었다. 사용자는 "가로 휠을 하면 글이 사라진다"고 보았지만, 실제 원인은 휠이 아니라 편집 후 재정렬이었다 - ReloadLinesFrom 이 3-Way 여부와 무관하게 늘 BuildLines(2-Way)로 다시 만들고 있었다. 칸(레이아웃)은 IsThreeWay 를 따라 그대로 남고 내용만 빠지니 "글자가 사라진" 것처럼 보인다. REMOTE 전문을 _remoteTextSnapshot 으로 붙들어 두고, 3-Way 면 BuildThreeWayLines 로 다시 맞추게 고쳤다. 실행 확인: MERGED 에 abc 한 번, 150자짜리 긴 줄 한 번 - 두 경우 모두 세 칸의 내용·Conflict 3·Theirs only 1 이 그대로 남는다. ② 워드랩을 켜도 원본 세 칸이 접히지 않았다. 가로 이동량을 재려고 그 칸들의 가로 스크롤을 Hidden(막대만 감춤, 굴리기는 가능)으로 둔 것이 원인 - 굴릴 수 있으면 WPF 는 칸 너비를 무한으로 잡아 재므로 접힐 자리가 없다. 워드랩을 켜면 Disabled(너비 고정), 끄면 Hidden(폭 측정 가능)로 바꾸는 SourceBars 를 두어 해결. 실행 확인: 워드랩 켠 3-Way 에서 LOCAL(Mine) 07행이 4줄, REMOTE 05행이 3줄로 접히고 BASE 쪽 빈자리 높이가 같이 늘어 세 칸의 같은 행이 같은 눈높이에 온다(09/05/06행 · 11/07/08행 · 19/15/16행 확인). 덤으로 표시층 ListBox 가 스스로 굴러가지 못하게 막았다(BlockSelfScroll) - ListBox 가 "고른 줄을 보이게" 하려고 제멋대로 굴리면 여백까지 밀려 나간다. 미니맵 이동도 편집기 캐럿 기준으로 바꿨다(표시층을 직접 굴리지 않는다). |
| 2026-09-07 | 남은 것 2가지 (확인됨, 미수정) | ① 3-Way + 워드랩에서 위 세 칸과 아래 MERGED 의 세로 위치가 어긋난다. 두 무리의 칸 너비가 달라 접히는 자리가 다르고, 따라서 같은 행이라도 높이가 다르다. 지금은 픽셀 오프셋으로 맞추므로 접힌 줄을 지날 때마다 조금씩 벌어진다(4칸 굴린 뒤 2행 차이). 제대로 맞추려면 픽셀이 아니라 행 번호로 맞춰야 하고, 그러려면 양쪽 모두 "N행의 픽셀 위치"를 되돌려 주는 길이 필요하다 - 스크롤 동기화를 다시 짜는 일이라 따로 잡는 편이 안전하다. 워드랩을 끄면 모든 칸의 행 높이가 같아 어긋나지 않는다. ② MERGED 를 직접 편집하면 LOCAL(Mine) 칸도 그 편집을 따라간다. MERGED 는 Mine 의 복사본에서 출발하고, 편집 후 재정렬은 "지금 글"로 다시 맞추기 때문이다. "파일을 연 시점의 내 줄"로 얼어붙게 하려면 편집 전 LOCAL 을 따로 정렬해 넣어야 하는데, 사용자가 줄을 더하거나 지우면 행이 어긋나 4-way 정렬이 된다. 반영(Accept·Take Mine/Theirs) 으로 고치는 경우에는 지금도 Mine 칸이 그대로 남는다. |
| 2026-09-07 | 남은 것 2가지 — 둘 다 완료 | ① 3-Way + 워드랩 세로 어긋남. 위 원본 세 칸과 아래 MERGED 는 칸 너비가 달라 접히는 자리가 다르고, 따라서 같은 행이라도 높이가 다르다. 지금까지 픽셀 오프셋을 그대로 넘겨 맞추던 것을 행 기준 변환으로 바꿨다 — 편집기의 세로 위치 → 그 자리의 논리 행 + 행 안으로 들어간 비율 → 원본 칸의 행 높이표(MergeLine.SourceRowHeight)로 다시 픽셀. 반대 방향(원본 칸을 굴렸을 때)도 같은 식의 역변환을 넣었다. 변환은 워드랩을 켠 3-Way 에서만 탄다(SourceRowsDifferFromEditor) - 그 밖에는 모든 칸의 행 높이가 같아 픽셀 그대로가 정확하다. 실행 확인: 워드랩 켠 3-Way 에서 아래로 굴리면 네 칸이 모두 05행에서 시작하고, BASE 칸에서 굴려도(역방향) 마찬가지다. 고치기 전에는 MERGED 10행 ↔ 원본 08행으로 벌어졌다. ② MERGED 를 고치면 LOCAL(Mine) 칸도 따라가던 것. 편집 후 재정렬이 "지금 글"을 MINE 자리에도 그대로 쓰고 있었다. BASE 를 축으로 MINE·REMOTE·MERGED 세 쪽을 세우는 ThreeWayAligner.AlignFour 를 새로 만들어 두 열을 갈랐다(MergeLine.SetThreeWay 로 MINE 을 따로 받는다). 방식은 기존 3-Way 정렬 그대로다 - BASE 와 2-way 정렬을 세 번 한 뒤 BASE 줄 번호로 맞물리고, BASE 줄이 없는 추가분은 MINE↔MERGED 를 먼저 짝지은 뒤 그 묶음을 REMOTE 와 짝짓는다(결과는 내 것의 복사본에서 출발하므로 이 순서라야 "내가 넣은 줄"이 편집 뒤에도 제자리에 남는다). MERGED == MINE 이면 결과가 기존 3-Way 정렬과 글자 하나 다르지 않다 - 파일을 연 직후 화면은 그대로라는 뜻이고, 테스트로도 못 박았다. ThreeWayTest 20건 → 31건(4-Way 11건 추가: 3-Way 와 동일함 2건, 결과만 고침·줄 추가·줄 삭제·내가 넣은 줄·저쪽 줄 가져오기·양쪽 추가·번호 갈라짐·빈 글 2건). 실행 확인: MERGED 1행에 abc 를 쳐도 LOCAL(Mine) 1행은 using System; 그대로이고, 그 행에 Take Mine(<) 버튼이 생긴다. 네 칸의 행 정렬도 그대로다. 전체 290건 통과. |