새 플랫폼(UbisamBase.Launcher) 위로 옮기면서 12차 A~E 를 한 번에 담는다.
항목별 값과 판정은 doc/history/2026-09-23-12차.md, 요약은 doc/history/changelog.md.
A. 폴더 비교를 읽기 쉽게
- A-1 폴더 줄의 크기가 늘 0B 이던 것 - 안에 든 파일 크기 합계를 아래에서 위로 더해 적는다
(걸러 낸 파일은 합계에서도 빠진다)
- A-2 좌우로 나눠 보이기 - 왼쪽 · 오른쪽 목록을 나란히 두고 같은 줄에 맞춘다.
한쪽에만 있는 항목은 반대편을 비운다
B. 파일 비교 화면
- B-1 2-Way 에서 양쪽으로 머지 - 칸마다 반영 · 저장. 왼쪽 기준점을 따로 세고,
되돌리기 · 저장 백업도 양쪽 모두
- B-2 프로그램 정보 창 - 버전 · 빌드 날짜 · 만든 사람 · 사내 문의처 · 플랫폼 버전 · 로그 폴더
- B-3 칸 아래에 무엇이 달라졌는지 - 칸마다 줄 수 · 추가 · 삭제 · 수정, 가운데에 진행
C. 플랫폼 (플랫폼 저장소에서 함께 나감)
- C-2 하단 탭 줄을 한 단계 작게 - 74 -> 61 DIP. 실측 133 -> 109px 이고
그만큼 코드 칸이 늘어 파일 비교가 47 -> 48줄
E. 저장하지 않아도 남는 편집
- E-2 여러 짝을 동시에(문서 탭). 지금까지는 한 짝만 들어서 짝을 바꾸면
저장하지 않은 편집을 묻고 버리면 사라졌다(재현: 16줄 -> 15줄).
이제 떠 있던 탭이 그 글을 맡아 두므로 묻지 않는다.
- 탭마다 HomeViewModel 을 따로 만들지 않았다 - 이 화면은 GitWorkspace 의 여러 사건과
한 자리짜리 약속(ConfirmDiscardEdits · ConfirmLeaveCommit)에 물려 있다.
화면은 하나로 두고 탭이 파일에 없는 것만 맡는다(고친 글 · 왼쪽 글 · 되돌리기 이력 ·
두 기준점 · 캐럿 · 스크롤 · 저장 형식)
- 탭 이름은 파일 이름, 다르면 왼 <-> 오. 양쪽이 같은 부분은 한 번만 적는다
(WeldController_기준 <-> 내작업.cs, 421 -> 288px). 같은 이름이 겹치면
갈릴 때까지 위 폴더를 한 겹씩 덧붙인다
- 저장하지 않은 탭에 가운뎃점. 사람이 손댄 것만 센다 - 중괄호 맞춤으로만 바뀐 것은
묻는 자리와 같은 기준으로 뺀다(안 그러면 .cs 를 여는 것만으로 늘 점이 붙는다)
- 탭이 사라져도 고친 글은 보관함에 남아 다시 열면 되살아난다(짝 50개).
E-1(껐다 켜도 남는 편집)은 이 보관함을 파일로 옮겨 적으면 된다
- 이전 · 다음 파일은 지금 탭의 짝만 바꾸고, 폴더 비교에서 두 번 누르면 새 탭(사용자 결정)
- Ctrl+Tab · Ctrl+Shift+Tab · Ctrl+W · 가운데 단추 닫기. 닫을 때도 묻지 않는다
- Git 탭 · 병합 중 네 칸은 탭이 맡지 않는다 - 그쪽은 예전처럼 묻는다
하네스 27벌 1,787건 통과 · 실패 0(DocTabTest 106건 새로 만듦).
빌드 경고 0 · 오류 0. 화면으로 E-2 34건 · 회귀 19건 확인.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
29 KiB
12차 진행 기록 (2026-09-23 ~)
지시서: ../작업지시/12차.md
A-1. 폴더 줄의 크기가 늘 0B (2026-09-27, 완료)
무엇이 문제였나
크기를 파일 줄에만 채웠다(FolderComparer 의 파일 루프에서 FileInfo.Length). 폴더 줄은 LeftSize ·
RightSize 가 0 인 채로 화면에 내려가 어느 폴더든 0 B 로 보였다. 어느 쪽이 더 큰지, 어느 폴더가 무거운지를
목록에서 알 수 없었다.
어떻게 고쳤나
Services/FolderSizeText.cs 를 새로 두었다. 화면 없이 검사할 수 있게 계산만 떼어 낸 것이다.
| 하는 일 | 함수 |
|---|---|
| 사람이 읽는 크기로 적기 | Of(long bytes) — 1KB 미만은 바이트 그대로(999 B), 그 위는 소수 한 자리(1.5KB · 2.4MB · 3GB) |
| 폴더 줄에 합계 채우기 | FillFolderSizes(items) — 아래에서 위로, 폴더는 자기 아래 것들의 합 |
- 부르는 자리는
FolderComparer.Compare의ClassifyAll다음,Tally앞이다. 파일 갈래를 정하는 판단은 파일 크기를 보고 하므로(크기가 다르면 열지 않는다) 그보다 먼저 채우면 판단이 달라진다 — 그래서 뒤에 둔다. - 걸러 낸 것은 합계에서도 빠진다. 포함 · 제외 규칙에 걸린 파일은 애초에 목록에 없으므로 따로 뺄 일이 없다.
- 한쪽에만 있는 폴더는 그쪽만 합계고 반대쪽은 0 이다(화면에는
-). - 화면 쪽은
FolderViewModel.Describe가{크기} · {수정일}을 만들 때FolderSizeText.Of를 쓰게 바꿨다. 예전에는{바이트:N0} B라 300,000 B 처럼 읽기 어려웠다.
값으로 확인한 것
시험 재료는 만들어 썼다(%TEMP%\mergehub-a1, 실제 업무 저장소는 읽지 않는다).
| 폴더 | 화면 | 탐색기 속성(파일 크기 합) |
|---|---|---|
Docs |
2.4MB · 2.4MB | 2,500,000 · 2,500,000 |
Legacy(왼쪽만) |
50KB · - |
51,200 · 없음 |
NewOnly(오른쪽만) |
- · 40KB |
없음 · 40,960 |
Src |
490.2KB · 491.7KB | 502,000 · 503,500 (기본 제외 규칙에 걸린 Src\bin 9MB 는 빠짐) |
Src\Core |
472.7KB · 474.1KB | 484,000 · 485,500 |
Src\Core\Motion |
179.7KB · 181.2KB | 184,000 · 185,500 |
Src\Ui |
17.6KB · 17.6KB | 18,000 · 18,000 |
- 파일 줄도 함께 읽기 쉬워졌다 —
Unit0.cs 293KB·Home.cs 62.5KB / 64KB·manual.txt 2.4MB. - 비교 시간: 4,608 줄(136MB · 파일 8,922개) 짜리 묶음에서 합계 채우기 0ms(빠른 비교 203ms 대비 0.0%). 디스크를 다시 읽지 않고 이미 만들어 둔 목록을 한 번 훑을 뿐이라 늘어날 여지가 없다.
하네스
FolderTest 88 → 111건(+23) · 실패 0.
- 글자 8건: 1KB 미만 · 1024 · 소수 한 자리 · 딱 떨어질 때 · MB · GB · TB 를 넘을 때 · 음수
- 합계 9건: 여러 겹 · 양쪽 따로 · 가운데 폴더 · 맨 안쪽 · 한쪽에만 있는 폴더 · 파일 줄은 그대로 · 탐색기 속성과 같은 값(양쪽)
- 걸러 내기 3건: 제외한 폴더 · 제외해도 다른 줄은 그대로 · 포함 규칙에 안 맞는 파일
- 판단이 안 바뀌는지 4건: 크기가 다른 이진 파일 · 같은 파일 · 한쪽에만 있는 폴더 · 하위 폴더를 안 볼 때
남긴 것
- 폴더 줄의 수정일은 그대로 비워 둔다. 폴더의 수정 시각은 안의 파일과 무관하게 바뀌어(윈도가 하위 항목을 더하거나 지울 때만 갱신) 사람이 기대하는 값과 다르다 — 크기만 적는 편이 오해가 적다.
A-2. 좌우로 나눠 보이기 (2026-09-27, 완료)
무엇이 문제였나
한 줄에 이름 | 상태 | 왼쪽(크기·수정일) | 오른쪽(크기·수정일) 이 늘어서 있었다. 이름이 한 번만 나오니
"이 줄이 어느 쪽 것인가"를 상태 글자를 읽어야 알 수 있었고, 한쪽에만 있는 항목도 - 한 글자로만 표시됐다.
어떻게 고쳤나
한 줄을 왼쪽 목록 · 가운데 상태 · 오른쪽 목록 세 칸으로 나눴다(11차 F-10 파일 비교와 같은 모양).
- 칸마다 자기 쪽 이름과 크기를 적는다. 그쪽에 없으면 그 칸을 통째로 비운다 — 빈칸이 "여기엔 없다"를
상태 글자보다 먼저 말해 준다. 없는 쪽 크기를
-로 적던 것도 뺐다. - 가운데 칸이 두 목록을 가르는 선이다(같음 · 다름 · 왼쪽만 · 오른쪽만).
줄마다 칸이 어긋나는 문제가 하나 있었다. TreeView 는 깊이만큼 줄 전체를 오른쪽으로 밀기 때문에,
칸 폭을 고정해도 깊은 줄일수록 가운데 · 오른쪽 칸이 오른쪽으로 밀려 두 목록으로 읽히지 않는다.
그래서 TreeDepthMarginConverter(새로 둠)로
- 줄 바깥틀을 민 만큼 되돌리고(
Negative=True, 깊이 × 19 DIP 음수 여백) — 칸 경계와 가운데 구분선이 줄마다 같은 자리에 온다, - 이름에만 다시 같은 값을 들여쓴다 — 계층은 그대로 보이고, 왼쪽 · 오른쪽 이름이 같은 높이 · 같은 들여쓰기로 맞는다.
트리 자체는 그대로 쓴다(목록 둘을 따로 두고 스크롤 · 펼침을 맞추는 길은 택하지 않았다) — 접기 · 펼치기, 선택, 복사 · 삭제, 걸러 보기, 더블클릭으로 파일 비교 열기가 손대지 않은 채로 남는다.
화면으로 확인한 것
| 판정 기준 | 결과 |
|---|---|
| 같은 이름이 같은 높이에 온다 | Src > Core > Motion > Axis.cs 까지 네 겹 모두 양쪽 같은 줄 · 같은 들여쓰기 |
| 한쪽만 있는 항목이 어느 쪽인지 한눈에 | Legacy(왼쪽만)는 오른쪽 칸이 빈칸, NewOnly(오른쪽만)는 왼쪽 칸이 빈칸 |
| 접기 · 펼치기 | 모두 펼침 · 모두 접기 모두 그대로. 칸 경계는 깊이가 달라도 한 자리 |
| 걸러 보기 | 왼쪽에만 2줄 · 오른쪽에만 2줄 · 같은 것만 2줄 · 다른 것만 6줄 |
| 복사 단추 | Legacy 고르고 [→ 오른쪽으로 복사] → 확인 창(본 창 가운데) → 복사됨. 다시 비교하니 왼쪽만 1 · 같음 4 가 왼쪽만 0 · 같음 5 로 |
| 좁은 창 | 1750×1100(1166 DIP) 창모드에서도 세 칸(420+170+420 DIP) 이 다 보인다 |
하네스
FolderTest 111 → 118건(+7) · 실패 0 — 뿌리 여백 0 · 한 겹 19 · 세 겹 57 · 되돌리는 쪽은 음수 ·
되돌린 뒤 다시 들여쓰면 제자리 · 위아래 여백은 안 건드림 · 깊이가 아니거나 음수면 0.
남긴 것
- 칸 폭은 고정(420 · 170 · 420 DIP)이다. 트리가 깊이마다 폭을 다르게 잡아서 비율(
*) 폭을 쓰면 줄마다 칸이 달라진다 — 화면이 아주 좁으면 오른쪽 목록이 잘린다(1166 DIP 까지는 확인했다).
B-1. 2-Way 에서 양쪽으로 머지 (2026-09-27, 완료)
지시서에 남겨 둔 "정할 것"을 물어 정했다 — 두 파일 비교에서만 양방향(사용자 결정 2026-09-27). Git 모드에서 왼쪽은 지난 커밋이라 고쳐 쓸 파일이 없고, 네 칸(3-Way)의 BASE 는 공통 조상이라 거기에 쓰는 것이 뜻이 없다.
무엇이 문제였나
반영이 BASE → LOCAL 한 방향뿐이고 저장도 오른쪽 파일에만 됐다. 두 파일을 견주다 왼쪽이 맞는 경우 (오른쪽에서 잘못 지웠거나, 왼쪽 파일도 같이 맞춰야 하는 경우)에는 도구 밖에서 손으로 고쳐야 했다.
어떻게 고쳤나
| 무엇 | 어디 |
|---|---|
줄 반영 [<] |
BASE 칸 여백(왼쪽에 있는 줄) · LOCAL 칸 여백(왼쪽에 없는 줄 - BASE 칸에는 그 줄 자체가 없어 달 자리가 없다) |
| 칸마다 저장 | ACTIONS 의 ◀ 왼쪽 저장 · 오른쪽 저장 ▶. 고친 것이 없는 쪽은 꺼진다 |
| 반영 규칙 | Services/PaneText.cs(새로 둠) — 두 방향이 같은 규칙을 쓴다 |
| 되돌리기 | 편집 기록(LineEdit)에 Side 를 더해 어느 칸을 고친 편집인지 들고 다닌다. 한 스택에 쌓여 누른 차례대로 풀린다 |
| 저장 기준점 | 왼쪽 · 오른쪽을 따로 센다(_leftBaseline) — 한쪽을 저장해도 다른 쪽의 "저장할 것 있음"은 그대로 |
반영 규칙은 어느 쪽으로든 같다. 반대쪽에 줄이 있으면 그 글을 가져오고(없던 줄이면 생긴다), 반대쪽에 없으면
이 칸에서도 지운다. 머지 주석(설정 "머지 주석 넣기")도 양쪽 모두 남는데, 왼쪽에 넣는 주석은
LOCAL(파일이름) 을 출처로 적고 왼쪽에만 있는 줄로 들어간다 — 오른쪽 파일에는 섞이지 않는다.
MergeLine.HasBase · BaseNumber 가 이제 바뀔 수 있는 값이다(예전에는 정렬 결과라 고정이었다).
BASE 칸 목록도 그 변화를 따라가게 했다(PaneView 의 live filtering) — 이게 없으면 왼쪽에 넣은 줄이 안 보이고
왼쪽에서 지운 줄이 빈 칸으로 남는다(화면 시험에서 실제로 걸려 고쳤다).
화면으로 확인한 것
시험 재료는 만들어 썼다(%TEMP%\mergehub-b1, left.cs · right.cs).
| 판정 기준 | 결과 |
|---|---|
| 왼쪽 파일에 반영 · 저장된다 | 값이 다른 줄 · 왼쪽에만 있는 줄 · 오른쪽에만 있는 줄 셋을 [<] 로 반영 → ◀ 왼쪽 저장 → 왼쪽 파일이 오른쪽 내용 + 머지 주석 2줄 |
| 오른쪽은 그대로다 | 오른쪽 파일 해시 07f16198… 저장 전후 같음. 오른쪽 저장 ▶ 은 고친 것이 없어 꺼져 있었다 |
| 되돌리기(11차 F-8) | Undo 세 번에 BASE 칸이 처음 모습으로(값 100 · 왼쪽에만 있던 줄 · 주석 사라짐), Redo 켜짐. 저장한 뒤라 ◀ 왼쪽 저장 은 다시 켜진다(저장한 글과 달라졌으므로 - F-8 의 뜻 그대로) |
| 저장할 때 백업(11차 F-9) | {설정}\Backup\MergeHub\2026-09-27\…\left.20260927-191108.cs |
| 두 파일 비교에서만 | git mergetool 네 칸(--merge --base --local --remote --merged)에서 [<](새 단추) 0개 · ◀ 왼쪽 저장 안 보임. 네 칸의 기존 <(Take Mine · Take Theirs)는 그대로 |
하네스
TwoWayTest 29건 새로 · 실패 0 — 칸의 글 만들기 3 · 반영 규칙 7(양방향 · 한쪽에만 있는 줄 · 같은 줄 ·
멱등) · 왼쪽으로 반영한 뒤 5 · 오른쪽으로 반영한 뒤 3(예전 길 그대로) · 양쪽 저장 기준점 5 · 로그 문구 4 · 기타 2.
남긴 것
- 왼쪽 칸은 타이핑으로는 못 고친다. 편집기는 오른쪽에만 겹쳐 있다 - 왼쪽은
[<]로 반영해서 고친다 (지시서가 정한 것: "칸마다 저장 단추 · 왼쪽 칸에도 반영 단추 [<]"). - 왼쪽으로 반영한 줄에는 "머지 반영함" 색을 칠하지 않는다. 반영하고 나면 양쪽이 같아져 색이 필요 없다.
B-2. 프로그램 정보 창 (2026-09-27, 완료)
지시서의 "정할 것"을 물어 정했다(사용자 결정 2026-09-27).
- 넣을 것: 기본 4가지(프로그램 이름 · 버전 · 빌드 날짜 · 만든 사람) + 사내 문의처.
- 버전 출처:
MergeHub.csproj의<Version>을 실행 파일에서 읽는다. 12차 =0.12.0.
어떻게 만들었나
| 값 | 어디서 |
|---|---|
| 이름 · 만든 곳 | 어셈블리의 Product(MergeHub) · Company(UbiSam) — csproj 에 적는다 |
| 버전 | 어셈블리 버전. 뒤가 0 인 자리는 떼고 적는다(0.12.0.0 → 0.12) |
| 빌드 날짜 | csproj 가 빌드할 때 박아 둔 값(AssemblyMetadata "BuildDate") |
| 만든 사람 · 문의처 | 설정 프로그램 정보 > 만든 사람 · 사내 문의처. 비우면 만든 사람은 회사 이름, 문의처는 "적혀 있지 않습니다" |
빌드 날짜를 어셈블리에 박는 까닭 — 실행 파일(PE) 머리의 시각 자리를 읽어 보니 요즘 SDK 는 결정적 빌드라
그 자리에 내용 해시가 들어간다(날짜로 읽으면 2100년 같은 값). 그래서 csproj 에서 빌드 시각을 박고,
못 찾을 때만 PE 시각 → 파일 수정 시각 순으로 물러난다(ProgramInfoReader.ChooseBuildDate).
파일 수정 시각을 첫째로 두지 않는 까닭은 복사 · 압축 풀기로 바뀌기 때문이다.
창은 [단축키] 옆 [정보] 단추로 연다. 단축키 창과 같은 규칙 — 이미 떠 있으면 새로 띄우지 않고 앞으로 가져온다. [정보 복사] 로 네 줄을 그대로 클립보드에 담는다(결함을 알릴 때 첫 질문이 늘 "어느 버전이냐" 라서).
화면으로 확인한 것
| 판정 기준 | 결과 |
|---|---|
| 버전이 실제 실행 파일 값과 같다 | 창 0.12 ↔ MergeHub.dll 어셈블리 버전 0.12.0.0 |
| 빌드 날짜가 실제 값과 같다 | 창 2026-09-27 19:51 ↔ 실행 파일에 박힌 BuildDate 2026-09-27 19:51 |
| 창을 닫아도 화면 상태가 그대로다 | 닫기 전후 화면 같음(BASE · LOCAL 칸 · 선택 줄 · ACTIONS 상태 그대로) |
| 설정에서 받은 값 | 만든 사람 · 문의처를 적으니 그대로 보이고, 비우면 회사 이름 · 안내 글 |
하네스
AboutTest 28건 새로 · 실패 0 — 버전 글 5 · PE 시각 읽기 9 · 빌드 날짜 고르기 4 ·
적혀 있지 않은 칸 4 · 실제 실행 파일 대조 5(버전 · 박힌 날짜 · 창에 적을 값 한 벌 · 문의처 빈칸)
남긴 것
- 만든 사람 · 사내 문의처는 비워 두었다. 사람 이름 · 연락처는 지어낼 값이 아니다 - 설정 > MergeHub > 프로그램 정보 에서 적으면 그때부터 창에 나온다.
- 버전은 차수에 맞춰 손으로 올린다(12차 = 0.12.0). 올리는 자리는 csproj 한 곳이다.
B-3. 칸 아래에 무엇이 달라졌는지 (2026-09-27, 완료)
무엇이 문제였나
요약이 창 맨 아래 상태 줄 한 곳에만 있었다("총 7줄 · 남은 차이 3줄"). 칸이 둘 · 넷이 되면서 이 칸에 몇 줄이 있고 저쪽과 무엇이 다른가는 눈으로 세야 했다.
어떻게 고쳤나
- 칸마다 한 줄을 칸 아래에 붙였다 —
6줄 · 추가 1 · 삭제 1 · 수정 1. 다른 것이 없으면6줄 · 같음, 0 인 칸은 아예 적지 않는다(0 을 늘어놓으면 읽을 것만 는다). - 가운데(칸 사이 틈) 아래에 진행 — 위에
3 / 7(몇 번째 차이를 보고 있나), 아래에남은 2(아직 다른 줄). 틈이 48 DIP 라 두 줄로 짧게 적는다. 남은 것이 없으면 아랫줄은 비운다. - 세는 규칙은
Services/PaneSummary.cs(새로 둠)에 모았다.
칸을 기준으로 읽는다 — 추가 는 이 칸에만 있는 줄, 삭제 는 저쪽에는 있는데 이 칸에 없는 줄,
수정 은 양쪽에 있고 글이 다른 줄이다. 그래서 두 칸의 추가 · 삭제는 서로 거울이 된다.
무시 규칙에 걸린 줄과 우리가 넣은 머지 주석은 차이로 세지 않는다(화면 색 · 차이 이동과 같은 기준) —
다만 줄 수에는 들어간다(파일에 있는 줄이므로).
3분할에서는 네 칸 모두 BASE(공통 조상)와 견준다 — "누가 무엇을 고쳤나" 가 그 화면에서 읽어야 할 것이라서다.
BASE 칸 자신은 견줄 것이 없어 4줄 · 기준 이라고만 적는다.
화면으로 확인한 것
| 판정 기준 | 결과 |
|---|---|
| 반영 · 되돌리기 · 저장마다 숫자가 따라간다 | 반영 전 6줄 · 추가 1 · 삭제 1 · 수정 1(양쪽) · 남은 3 → [>] 하나 → 오른쪽 8줄 · 추가 1 · 수정 1 · 왼쪽 6줄 · 삭제 1 · 수정 1 · 남은 2 → Undo → 처음 값 그대로 |
| 3분할에서도 칸마다 맞는 숫자 | LOCAL(Mine) 4줄 · 수정 1 · BASE 4줄 · 기준 · REMOTE(Theirs) 4줄 · 수정 1 · MERGED 4줄 · 수정 1 · 가운데 - / 1 · 남은 1 |
| 긴 파일에서 느려지지 않는다 | 5만 줄 × 두 칸 × 네 번 = 22ms(한 번에 3ms 남짓). 목록을 한 번 훑을 뿐 파일을 다시 읽지 않는다 |
하네스
SummaryTest 25건 새로 · 실패 0 — 두 칸 요약 7 · 다른 것이 없을 때 4 · 세지 않는 줄 3 ·
세 칸(BASE 기준) 5 · 가운데 진행 5 · 긴 파일 1.
남긴 것
- 맨 아래 상태 줄의 "파일 전체" 요약은 그대로 둔다 — 칸 요약과 다른 값이다(전체 줄 수 · 남은 차이 · 편집 건수).
- 가운데 진행은 두 줄뿐이다. 틈을 넓히면 더 적을 수 있지만, 틈은 잇는 선(11차 F-10)의 자리라 좁게 두었다.
C-2. 플랫폼 탭 줄 크기 줄이기 (2026-09-28, 완료 · 배포됨)
플랫폼(D:\Sorce\ubsrepo) 쪽이라 모든 사내 프로그램에 함께 간다. 지시서 원칙대로 코드와 값은 다 만들고
배포는 사용자 확인 뒤에 한다 — 아래 "배포" 참고.
무엇을 얼마나 줄였나
Themes/ShellStyles.xaml 의 Ubisam.Style.SidebarItem.Horizontal(하단 탭 줄 항목) 한 곳이다.
| 값 | 전 | 후 |
|---|---|---|
| 위아래 여백 | 13 / 14 | 9 / 10 |
| 아이콘 | 22×22 | 20×20 |
| 아이콘 아래 틈 | 7 | 5 |
| 글자 | 13.5 | 12.5 |
| 항목 높이(DIP) | 74 | 61 |
값으로 잰 것
2560×1600 · 배율 150% · 셸 배율 1.2 에서 실제 화면 픽셀로 쟀다.
| 전 | 후 | |
|---|---|---|
| 탭 줄 높이 | 133px | 109px (−24px, −18%) |
| 파일 비교 코드 칸 높이 | 1,081px | 1,105px |
| 코드 줄 수(줄 높이 23px) | 47줄 | 48줄 (+1) |
배율 1.2 기준으로는 89 → 73px 이다(사용자가 말한 "95px" 과 같은 자리 - 재는 방법에 따라 테두리 · 밑줄이 붙는다).
글자 · 아이콘이 작아졌지만 한글 라벨(폴더 비교 · 파일 비교 · 화면 잠금 · 바탕화면 · 종료)은 잘리지 않고, 선택 밑줄 · 탭 접기 띠 · 오른쪽 동작 항목도 그대로다(화면 확인).
배포
이 항목만 빌드하면 D:\UbisamPlatform\bin 에 바로 반영된다. 처음에는 배포본을 백업해 두고 잠깐 바꿔치기해서
시험하고 되돌렸는데, 그 뒤 새 플랫폼(D:\Sorce\ubsrepo)을 빌드하면서 함께 나갔다.
- 영향: 이 플랫폼으로 만든 모든 프로그램의 하단 탭 줄이 함께 작아진다. 기능 · 배치는 그대로고 높이만 준다.
- 배포 확인 (2026-09-28): 배포본
UbisamBase.Core.dll이 지금 소스의 빌드 결과와 해시가 같고(BA27EE48…, 738,304바이트, 04:09), 실제로 켜서 잰 하단 탭 줄이 111px · 항목 109px(배율 150% 기준 72.7 DIP)로 "후" 값과 맞았다. 앞서 적었던 "지금 배포 폴더에는 예전 것이 그대로" 는 그 뒤 빌드로 낡은 글이 되어 고쳤다.
E-2. 여러 짝을 동시에 (문서 탭) (2026-09-28, 완료)
먼저 재현 (화면, 값)
| 단계 | 값 |
|---|---|
| 짝 A 열기 | 오른쪽 15줄 · public int Version = 2; |
| 고치고 저장하지 않음 | 16줄 · 마지막 줄 // E2-MARK-ALPHA · [오른쪽 저장 ▶] 켜짐 · 아래 줄 "남은 차이 3줄 · 편집 1건" |
| 다른 짝 열기 | 모달 "a-right.cs 에 저장하지 않은 편집이 있습니다" · [취소] [저장하지 않고 계속] [저장하고 계속] |
| [저장하지 않고 계속] | 화면이 15줄로 돌아감 — 고친 글이 사라졌다(원본 파일은 안 바뀜) |
한 번에 한 짝만 들기 때문이다. 짝을 바꾸는 순간 앞 짝의 편집 글이 갈 곳이 없어서 묻고, 버리면 그대로 사라진다.
고친 방식
탭마다 HomeViewModel 을 따로 만들지 않았다. 이 화면은 GitWorkspace 의 여러 사건과 한 자리짜리 약속
(ConfirmDiscardEdits · ConfirmLeaveCommit)에 물려 있다 — 여럿을 만들면 같은 사건에 여러 화면이 동시에 반응하고
약속은 마지막 것만 남는다. 그래서 화면은 하나로 두고 탭이 편집만 맡는다.
Services/DocTabs.cs(새로 만듦) — 계산만 한다(화면 없이 검사할 수 있다).DocTab: 짝 하나 · 이름(Title) · 저장 안 한 표시(IsDirty) · 떠 있는지(IsCurrent) · 맡아 둔 편집(Parked)DocTabState: 파일에 없는 것만 담는다 — 고친 글 · 왼쪽 글(B-1) · 되돌리기/다시하기 이력 · 두 기준점 · 캐럿 자리 · 스크롤 행 · 저장 형식. 파일에서 다시 읽을 수 있는 것(원본 글 · 줄 정렬)은 담지 않는다 — 담아 두면 파일이 그 사이 바뀌었을 때 낡은 것을 보여 준다.- 이름 짓기 : 파일 이름, 양쪽이 다르면
왼 ↔ 오(최근 목록RecentPair.Label과 같은 규칙). 같은 이름이 겹치면 갈릴 때까지 위 폴더를 한 겹씩 덧붙인다(Unit0.cs가 여러 폴더에 있는 사내 소스 때문). - 보관함 : 탭을 닫거나 짝을 바꿔 탭 자체가 사라져도 고친 글은 짝 이름으로 남는다(50개). ◀ ▶ 로 훑다가 앞 파일로 돌아왔을 때 고친 것이 사라지면 그것이 곧 E-2 가 없애려던 일이다. E-1(껐다 켜도 남는 편집)은 이 보관함을 파일로 옮겨 적으면 된다.
- 상한 20 : 넘으면 저장할 것 없는 탭 가운데 가장 오래 안 본 것을 닫는다. 고친 탭은 절대 닫지 않는다(넘겨서라도 연다).
ViewModels/HomeViewModel.Tabs.cs(새로 만듦) — 화면과 이어 주는 자리.ParkCurrentTab(맡기기) ·ResumePendingTab(되살리기) ·OpenPairInTab·EnsureTabForCurrentPair·GoToTab· 명령 네 개(ActivateTab · CloseTab · NextTab · PreviousTab).HomeViewModel.cs세 군데만 고쳤다.OnPlainCompareRequested: 두 파일 비교끼리 짝을 바꿀 때 묻지 않는다. Git · 네 칸에서 넘어올 때는 그대로 묻는다.MoveFile(◀ ▶) : 묻지 않고 지금 탭의 짝만 바꾼다(사용자 결정 — 탭이 늘지 않아 목록을 훑기 좋다).LoadPlainFilesAsync: 맨 앞에서EnsureTabForCurrentPair, 맨 끝(파일을 다 읽은 뒤)에서ResumePendingTab.
HomeView.xaml: 맨 위에 문서 탭 줄. ItemsControl 이 아니라 ListBox 다 — ItemsControl 은 UIA 에 "컨트롤" 로 보이지 않아 화면 시험이 탭 줄을 아예 못 읽고, 키로 옮기는 것도 공짜로 얻을 수 없다. 고르기가 곧 탭 옮기기다. 탭이 둘 이상일 때만 보인다(한 짝만 볼 때 줄을 낭비하지 않는다).- 단축키 : Ctrl+Tab · Ctrl+Shift+Tab · Ctrl+W(notepad++ · 브라우저와 같은 손버릇). 가운데 단추로도 닫힌다.
- 닫을 때 · 옮길 때 묻지 않는다 — 글이 보관함에 남기 때문이다.
원본 파일이 그 사이 바뀌었으면
되살리고 알린다. 사용자가 아까운 것은 자기가 고친 글이다. "파일을 연 시점"은 새로 읽은 글로 두어 [전체 되돌리기]가 지금 파일로 가고, 고친 글은 편집으로 남는다 — 그래야 어느 쪽도 잃지 않는다. 알림으로 "저장하면 바뀐 파일을 덮어씁니다" 를 말해 준다.
화면을 켜 놓고 보다 고친 두 가지 (2026-09-28)
만들어 놓고 실제 설정으로 켜서 눈으로 보다 찾았다. 둘 다 사용자가 고르게 했다.
(가) 켜자마자 가운뎃점이 붙었다. 설정에 C# 중괄호 맞춤이 켜져 있으면 .cs 를 여는 것만으로
"저장할 것 있음" 이 되어, 손대지도 않은 탭에 점이 붙었다. 늘 붙어 있는 점은 뜻이 없다.
"저장하지 않은 편집이 있습니다" 를 묻는 자리(WillAskBeforeDiscard)는 이미 스타일 맞춤만 바뀐 것을 빼고 세고 있었다 —
점도 같은 기준(HasTypedEdits)을 쓰게 했다. 맡길 때도 같다(스타일로만 바뀐 글은 맡기지 않는다 — 다시 열면 똑같이 만들어진다).
(나) 긴 짝 이름이 탭 줄을 많이 먹었다. WeldController_기준.cs ↔ WeldController_내작업.cs 하나가 421px(280 DIP),
탭 줄의 1/9 를 차지하고 뒤가 잘려 WeldController_내작... 으로 보였다. 사내 소스에는 이름이 살짝만 다른 짝이 흔하다.
양쪽이 같은 부분은 한 번만 적게 했다(사용자 결정).
| 전 | 후 | |
|---|---|---|
| 탭 이름 | WeldController_기준.cs ↔ WeldController_내작... |
WeldController_기준 ↔ 내작업.cs |
| 탭 폭 | 421px | 288px (−32%, 잘림 없음) |
뒤쪽은 확장자일 때만 접는다. 글자 단위로 같은 꼬리를 세면 낱말 가운데서 잘린다 —
a-left.cs ↔ a-right.cs 에서 t.cs 가 같다고 a-lef ↔ right.cs 가 되어 읽을 수 없었다(하네스에서 걸렸다).
앞이 한 글자만 같은 것은 접지 않는다(abc.cs ↔ axy.cs 는 그대로).
하네스
DocTabTest 106건 통과 — 이름 짓기(겹칠 때 폴더 덧붙이기 · 한쪽만 있는 짝) · 저장 표시 · 같은 짝 두 탭 금지 ·
Replace · 닫기 자리 이동 · Ctrl+Tab 돌기 · 상한 · 보관함(짝 바꿔도 · 닫아도 · 모두 닫아도 · 치워도 되살아남 · 50개 한도) ·
같은 부분 접기(사내 소스 짝 · 앞뒤가 다 겹치는 짝 · 한 글자만 같으면 접지 않음 · 폴더까지 겹치는 경우).
화면으로 확인 (값)
| 확인 | 값 |
|---|---|
| 폴더 비교에서 두 번 누르기 | alpha.cs → 탭 1개(줄 안 보임) · bravo.cs → 탭 2개 alpha.cs | bravo.cs |
| 짝을 바꿀 때 | 묻는 창이 뜨지 않는다 |
| 저장 안 한 표시 | alpha 만 고쳤을 때 가운뎃점 1개 → 둘 다 고치면 2개 |
| 탭을 오간 뒤 | alpha 15줄(E2-MARK-ALPHA 그대로) · bravo 15줄(E2-MARK-BRAVO 그대로) · 서로 섞이지 않음 |
| 되돌리기 | Undo 가 그 탭 것만 되돌리고 Redo 로 돌아옴 · 다른 탭은 그대로 |
| Ctrl+Tab | alpha 로 넘어가고 그 탭의 편집도 그대로 |
| 저장 | 그 탭의 가운뎃점만 사라짐(2 → 1) · 저장 단추 꺼짐 · 파일에 실제로 써짐 · 다른 파일은 안 바뀜 |
| 탭 닫기 | 묻지 않음 · 한 짝만 남자 탭 줄이 사라짐 · 오류 글 0 |
회귀로 함께 본 것.
- ◀ ▶ 로 훑기 :
1 / 2→2 / 2→1 / 2, 탭이 늘지 않고(0개 = 줄 안 보임) 돌아오니 고친 글 그대로(15줄). - 켤 때 저절로 열리는 짝(설정의 기본 짝)에서 고친 것도 탭이 맡는다 —
EnsureTabForCurrentPair를 넣기 전에는 그 짝만 탭이 없어 편집이 사라졌다(화면에서 찾아 고쳤다). - Git 모드로 넘어갈 때는 여전히 묻는다(탭이 맡을 수 없는 자리). 데모 전환은 예전부터 두 번 묻는다 —
화면이 한 번(
데모 폴더를 바꿉니다),GitWorkspace가 한 번(Git 작업을 합니다: 데모 저장소 열기). 이번 변경과 무관하다. - 하네스 전체 27벌 1,777건 통과 · 실패 0(빌드 경고 0 · 오류 0).
시험 도구를 런처에 맞추기 (2026-09-28)
새 플랫폼부터 프로그램을 UbisamBase.Launcher.exe 로 켜고, 런처가 셸을 같은 프로세스 안에 올린다
(별도 프로세스로 띄우면 디버거가 안 붙어서 소비 프로젝트 중단점이 안 걸린다 — 런처 주석). 그래서 창을 든
프로세스 이름이 UbisamBase.Shell 에서 UbisamBase.Launcher 로 바뀌었고, 예전 이름만 찾던 화면 시험
도구가 전부 "창이 안 뜬다" 로 멈춰 있었다.
| 전 | 후 | |
|---|---|---|
| 켜는 파일 | UbisamBase.Shell.exe |
UbisamBase.Launcher.exe (없으면 셸로 되돌아감) |
| 창 주인 프로세스 | UbisamBase.Shell 만 |
UbisamBase.Launcher · UbisamBase.Shell 둘 다 |
a2lib.ps1에Shell-Procs·Shell-Proc·Stop-App을 두고Start-App·Get-Win이 그것을 쓰게 했다. 런처가 업데이트 진행 창(제목 없는 창)을 먼저 띄우는 경우를 대비해 제목이 있는 창을 먼저 고른다.- 스크립트 76개 · 156곳을 함께 고쳤다(옛 이름만 찾던
Get-Process, 지금 빌드 자리를 가리키던 실행 경로). 고치기 전 파일은 스크래치패드_prelauncher\에 그대로 뒀다. - 확인: 문법 검사 187개 통과, 끄기 → 켜기 → 창 찾기 → 네 탭 넘기기 → 단추 찾기 → 끄기까지 실제로 돌았고, 설정 · 창 자리 네 파일은 해시 그대로 되돌렸다.
- 시험 도구일 뿐 제품 코드는 바뀌지 않았다.
여기까지의 하네스 (2026-09-27)
A-1 · A-2 · B-1 · B-2 · B-3 을 넣은 뒤 30벌 1,830건 통과 · 실패 0(빌드 경고 0 · 오류 0).
- 새로 만든 것:
TwoWayTest29건(B-1) ·AboutTest28건(B-2) ·SummaryTest25건(B-3) - 늘어난 것:
FolderTest88 → 118건(A-1 +23 · A-2 +7) - 나머지 26벌은 그대로 통과 —
MergeLine.HasBase·BaseNumber를 바뀔 수 있는 값으로 바꾼 것이 정렬 · 이동 · 3-Way · 저장 길에 영향을 주지 않았다는 뜻이다(MergeSaveTest 350 · NoteTest 93 · MemberTest 83 포함).