--- InterpreterGantt Editor
+++ InterpreterGantt Editor
@@ -12,155 +12,144 @@
필드 타입 설명
depth 정수 들여쓰기 깊이. 탭 개수와 동일.
name 문자열 작업명. `#라벨` 접미어 포함 가능 (예: `설계#design`).
startOrRef 문자열 (선택) `YYYY-MM-DD` 시작일 또는 선행 작업 레이블 (예: `design`, `#design`). 둘 중 하나만.
est 정수 (선택) 소요 영업일수. 생략 시 defaultEst 적용.
progress 정수 (선택) 진척률 0~100. 직렬화 시 `숫자%` 형식으로 출력.
]]]
== UI 구조
-=== 툴바 버튼
-
-[[[#!Table tsv 1 1
-버튼 (아이콘) 단축키 동작
-+ (fa-plus) Enter 현재 행 아래에 새 행 추가 (현재 행과 같은 depth)
-- (fa-minus) Shift+Del 현재 행 삭제 (1행 이하일 때 삭제 불가)
-↑ (fa-arrow-up) Alt+↑ 현재 행을 한 칸 위로 이동
-↓ (fa-arrow-down) Alt+↓ 현재 행을 한 칸 아래로 이동
-▶ (fa-indent) Tab 현재 행 depth +1 (위 행의 depth+1 초과 불가, 자식 행 포함 이동)
-◀ (fa-outdent) Shift+Tab 현재 행 depth -1 (0 이하로 내려가지 않음, 자식 행 포함 이동)
-📅 (fa-calendar-day) — 현재 행의 Start/Ref 칸에 오늘 날짜(YYYY-MM-DD) 입력
-↶ (fa-undo) Ctrl+Z 마지막 Gantt 편집 작업 되돌리기
-↷ (fa-redo) Ctrl+Y / Ctrl+Shift+Z 되돌린 Gantt 편집 작업 다시 적용
-</> (fa-code) — GanttEditor를 닫고 원문 에디터로 전환
-]]]
-
=== 그리드 컬럼
현재 UI는 depth를 별도 숫자 컬럼으로 노출하지 않는다.
각 행의 depth는 row `data-depth` 값으로 보관하고, Task 입력칸의 왼쪽 padding으로 들여쓰기를 표시한다.
-depth는 Indent/Outdent 버튼 또는 Tab/Shift+Tab 단축키로 변경한다.
+depth는 Indent/Outdent 버튼 또는 [[Kbd(Tab)]] / [[Kbd(Shift Tab)]] 단축키로 변경한다.
[[[#!Table tsv 1 1
컬럼 고정폭 input type 비고
# 32px (셀, 클릭 가능) 행 번호 (1부터 시작). 클릭/드래그 동작은 일반 셀과 동일.
Task 나머지 text `이름` 또는 `이름#라벨` 형식. depth에 따라 들여쓰기 표시.
Start / Ref 160px text 날짜(`2026-06-01`) 또는 레이블(`design`, `#design`). `#13` 입력 후 포커스아웃 시 13번 행의 이름으로 자동치환. 비워 두면 생략.
Est 60px number 양의 정수. 스핀 버튼 숨김. 비워 두면 생략.
% 60px number 진척률 0~100. 스핀 버튼 숨김. 비워 두면 생략.
]]]
테이블은 `table-layout: fixed`로 컬럼 너비가 고정되며, 홀수/짝수 행 배경색을 다르게 표시한다.
+== 툴바 / 키보드 인터랙션
+
+툴바 버튼과 단축키는 같은 명령을 실행한다.
+행 단위 명령의 대상 행은 커서 행이 선택 묶음 안에 있으면 선택된 행 전체이고, 아니면 현재 커서 행 하나다.
+행 추가와 셀 값 변경(오늘 날짜, ref 치환)은 현재 커서/셀만 대상으로 한다.
+
+[[[#!Table tsv 1 1
+명령 툴바 버튼 키보드 위치/대상 동작
+행 추가 + (fa-plus) [[Kbd(Enter)]] 임의 셀 현재 행 아래에 새 행 삽입 (현재 depth 유지)
+행 삭제 - (fa-minus) [[Kbd(Shift Delete)]] 대상 행 대상 행 삭제 (1행 이하일 때 무시)
+위로 이동 ↑ (fa-arrow-up) [[Kbd(Alt ArrowUp)]] 대상 행 대상 행을 한 칸 위로 이동
+아래로 이동 ↓ (fa-arrow-down) [[Kbd(Alt ArrowDown)]] 대상 행 대상 행을 한 칸 아래로 이동
+들여쓰기 ▶ (fa-indent) [[Kbd(Tab)]] 대상 행 대상 행 depth +1 (위 행의 depth+1 초과 불가, 자식 행 포함)
+내어쓰기 ◀ (fa-outdent) [[Kbd(Shift Tab)]] 대상 행 대상 행 depth -1 (0 이하 불가, 자식 행 포함)
+오늘 날짜 입력 📅 (fa-calendar-day) — 현재 행 Start/Ref 셀 오늘 날짜(YYYY-MM-DD) 입력
+Undo ↶ (fa-undo) [[Kbd(Ctrl Z)]] 임의 셀 / GanttEditor 포커스 마지막 Gantt 편집 작업 되돌리기
+Redo ↷ (fa-redo) [[Kbd(Ctrl Y)]] / [[Kbd(Ctrl Shift Z)]] 임의 셀 / GanttEditor 포커스 되돌린 Gantt 편집 작업 다시 적용
+원문 전환 </> (fa-code) — GanttEditor GanttEditor를 닫고 원문 에디터로 전환
+상하 커서 이동 — [[Kbd(ArrowUp)]] / [[Kbd(ArrowDown)]] 임의 셀 상하 행 이동 + 이동한 행 단일 선택
+범위 선택 — [[Kbd(Shift ArrowUp)]] / [[Kbd(Shift ArrowDown)]] 임의 셀 마지막 선택 기준점부터 커서 행까지 범위 선택
+좌우 셀 이동 — [[Kbd(ArrowLeft)]] 셀 시작 / number 타입 좌측 셀로 이동
+좌우 셀 이동 — [[Kbd(ArrowRight)]] 셀 끝 / number 타입 우측 셀로 이동
+]]]
+
== 행 선택 및 드래그
행 번호(#) 열과 일반 셀 모두 같은 행 선택/드래그 모델을 사용한다.
마우스 클릭은 해당 셀에 포커스를 주고, 동시에 행 선택 상태를 갱신한다.
=== 행 선택
[[[#!Table tsv 1 1
동작 결과
선택되지 않은 행의 셀/행 번호 클릭 해당 행 단일 선택
선택된 행의 셀/행 번호 클릭 기존 선택 유지, 클릭한 셀로 포커스 이동
-Ctrl+클릭 개별 행 토글 선택
-Shift+클릭 마지막 클릭 행~현재 행 범위 선택
-ArrowUp / ArrowDown 커서 이동 후 해당 행 단일 선택
-Shift+ArrowUp / Shift+ArrowDown 마지막 선택 기준점부터 커서 행까지 범위 선택
+[[Kbd(Ctrl)]] + 클릭 개별 행 토글 선택
+[[Kbd(Shift)]] + 클릭 마지막 클릭 행~현재 행 범위 선택
+[[Kbd(ArrowUp)]] / [[Kbd(ArrowDown)]] 커서 이동 후 해당 행 단일 선택
+[[Kbd(Shift ArrowUp)]] / [[Kbd(Shift ArrowDown)]] 마지막 선택 기준점부터 커서 행까지 범위 선택
]]]
선택된 행은 배경색(`--color-flash-info-bg`)으로 강조 표시된다.
=== 드래그 동작
[[[#!Table tsv 1 1
조건 드래그 결과
선택되지 않은 행의 셀/행 번호에서 드래그 시작 행~현재 행 범위 선택
선택된 행의 셀/행 번호에서 드래그 선택된 행들을 드롭 위치 아래로 이동 (border 인디케이터 표시)
선택 묶음 내부로 드래그 순서 변경 없음
]]]
드래그 이동 후에는 드래그를 시작한 행의 상대 위치로 커서와 포커스를 복원한다.
-따라서 이동 직후에도 Arrow/Alt+Arrow/Undo/Redo 키 조작을 이어서 사용할 수 있다.
+따라서 이동 직후에도 [[Kbd(ArrowUp)]] / [[Kbd(ArrowDown)]], [[Kbd(Alt ArrowUp)]] / [[Kbd(Alt ArrowDown)]], [[Kbd(Ctrl Z)]] / [[Kbd(Ctrl Y)]] 키 조작을 이어서 사용할 수 있다.
== Undo / Redo
GanttEditor는 원문 CodeMirror history와 별도로 Gantt 전용 Undo/Redo 스택을 가진다.
다음 작업은 Undo/Redo 대상이다.
* 셀 값 변경
* `#13` 같은 row ref 자동 치환
* 오늘 날짜 입력
* 행 추가/삭제
- * 행 순서 이동(버튼, Alt+↑/↓, 드래그)
+ * 행 순서 이동(버튼, [[Kbd(Alt ArrowUp)]] / [[Kbd(Alt ArrowDown)]], 드래그)
* Indent/Outdent
셀 입력은 연속 입력을 너무 잘게 쪼개지 않도록 짧은 디바운스 단위와 blur 시점에 묶어서 기록한다.
행 선택만 바뀌는 동작은 문서 내용 변경이 아니므로 Undo history에 넣지 않는다.
== 직렬화 규칙
그리드 행 → Gantt TSV 라인:
1. `depth` 개수만큼 탭(`\t`)을 앞에 붙인다.
2. `작업명#라벨` 값을 쓴다.
3. `시작일/ref`가 비어 있지 않으면 `\t값`을 추가한다.
4. `소요일`이 비어 있지 않으면 `\t값`을 추가한다.
5. `진척률`이 비어 있지 않으면 `\t값%`를 추가한다.
`시작일/ref`가 없고 `소요일`만 있는 경우에도 `\t소요일`만 붙인다.
빈 중간 탭은 파싱 시 무시되므로 직렬화 시 중간에 빈 슬롯을 끼워 넣을 필요 없다.
-== 키보드 인터랙션
+== 인덴트 제약
-[[[#!Table tsv 1 1
-키 위치 동작
-Tab 임의 셀 depth +1 (Indent). 위 행의 depth+1 초과 불가. 자식 행 포함.
-Shift+Tab 임의 셀 depth -1 (Outdent). 0 이하 불가. 자식 행 포함.
-Enter 임의 셀 현재 행 아래에 새 행 삽입 (현재 depth 유지)
-Shift+Del 임의 셀 현재 행 삭제 (1행 이하일 때 무시)
-Alt+↑ 임의 셀 현재 행을 한 칸 위로 이동
-Alt+↓ 임의 셀 현재 행을 한 칸 아래로 이동
-ArrowUp / Down 임의 셀 상하 행 이동 + 이동한 행 단일 선택
-Shift+ArrowUp / Down 임의 셀 상하 행 이동 + 범위 선택
-Alt+ArrowUp / Down 임의 셀 현재 커서 행이 선택 묶음 안에 있으면 선택된 행들을 함께 이동, 아니면 현재 행만 이동
-Ctrl+Z 임의 셀 Gantt 편집 Undo
-Ctrl+Y / Ctrl+Shift+Z 임의 셀 Gantt 편집 Redo
-ArrowLeft 셀 시작 / number 타입 좌측 셀로 이동
-ArrowRight 셀 끝 / number 타입 우측 셀로 이동
-]]]
-
-=== 인덴트 제약
-
* 인덴트 시 위 행의 `depth + 1`을 초과할 수 없다. (위 행이 없으면 depth 0 고정)
- * 인덴트/아웃덴트 시 현재 행보다 depth가 큰 연속된 자식 행들도 함께 이동한다.
+ * 인덴트/아웃덴트 시 대상 행보다 depth가 큰 연속된 자식 행들도 함께 이동한다.
== 시각적 강조
[[[#!Table tsv 1 1
상태 강조 방법
현재 커서 행 행 전체 배경 `--color-link-hover-bg`
현재 활성 셀 outline `2px solid --color-focus-ring`
선택된 행(복수) 행 전체 배경 `--color-flash-info-bg`, 행 번호 셀 `--color-focus-ring` 배경
드래그 드롭 위치 대상 행 하단에 `2px solid --color-focus-ring` 선
셀 hover/일반 셀 cursor `cell`
행 번호/선택된 행 cursor `grab`
선택된 행 이동 드래그 중 cursor `grabbing`
]]]
== 기타 동작
* Gantt 에디터 진입 시 Wiki Formatting Help(`details.editHelp`)를 자동으로 숨기고, 에디터 종료 시 복원한다.
* 에디터 진입 시 첫 행 첫 열(Task)에 자동 포커스한다.
* input 변경 시 120ms 디바운스로 `applyGanttBlockEditor()`를 호출해 원문 textarea/CodeMirror에 즉시 반영한다.
- * Gantt 에디터가 열려 있고 일반 input/textarea에 포커스가 없을 때도 document 레벨에서 Undo/Redo 단축키를 보조 처리한다.
+ * Gantt 에디터가 열려 있고 일반 input/textarea에 포커스가 없을 때도 document 레벨에서 [[Kbd(Ctrl Z)]] / [[Kbd(Ctrl Y)]] / [[Kbd(Ctrl Shift Z)]] 단축키를 보조 처리한다.
== 감지 로직
* `detectTableBlock()`: `#!table`만 감지 → TableEditor 열기
* `detectGanttBlock()`: `#!gantt`만 감지 → GanttEditor 열기
* `detectGanttBlock()`은 `[[[#!gantt ...]]]`, `[[[` + `#!gantt`, plain `#!gantt` 문서를 모두 처리
* plain `#!gantt` 문서는 다음 섹션 헤더(`=`, `==` 등)를 데이터 끝으로 본다
* 초기 로드 시 `#!gantt` 감지되면 GanttEditor 자동 열기 (TableEditor보다 우선)
* `.toggleTableEditor` 버튼 클릭 시 블록 종류에 따라 분기