ICEFiction 개발기 ④: 화면은 멀쩡했다, 파일을 열기 전까지는 (v0.6.0)
선택 문단 정렬·탭 들여쓰기·캐릭터 갤러리를 붙였다. 그런데 오래 붙든 건 타입 검사와 빌드를 멀쩡히 통과한 버그 세 개였다. 특히 인용문 안에 본문이 통째로 갇혀 있던 건, 파일을 열어보기 전까진 보이지도 않았다.
화면은 멀쩡했다. 파일을 열어보니 본문이 통째로 인용문에 갇혀 있었다.
이번 v0.6.0에서 제일 오래 붙든 건 새 기능이 아니라 눈에 보이지 않던 버그 세 개였다. 셋 다 타입 검사와 빌드를 아무 문제 없이 통과했다. 실제로 앱을 띄워 보고, 저장된 파일을 열어보고 나서야 드러났다.
만든 것 다섯

1. 선택한 부분만 정렬. 드래그한 문단만 가운데·오른쪽으로 보낼 수 있다. 시나, 편지, 제사(題辭) 같은 걸 넣을 때 필요하다.
문제는 마크다운엔 정렬 문법이 없다는 거다. 방법을 정해야 했다. 앱 전용 표식을 쓰면 .md는 깨끗하지만 다른 앱에선 표식이 글자로 노출된다. 그래서 표준 HTML 블록으로 감쌌다.
<div align="center">
빗속에서, 우리는
서로의 이름을 부르지 않았다
</div>
이렇게 쓰면 깃허브·옵시디언·VS Code 미리보기에서도 그대로 가운데 정렬된다. 여는 태그 뒤의 빈 줄이 중요한데, 저게 없으면 안쪽 내용이 마크다운으로 파싱되지 않는다(CommonMark 규칙). 에디터에선 태그를 감추고 정렬만 보여준다 — 원고엔 남고, 화면엔 안 보인다.
커서만 찍어도 그 문단 전체가 잡힌다. 문단 한가운데서 정렬이 끊기면 안 되니까.
2. 탭키 들여쓰기. Tab을 누르면 한 칸 들어간다. 그런데 여기서도 함정이 있었다. 마크다운은 줄 앞에 탭문자나 4칸 공백이 오면 코드블록으로 오인한다. 원고 첫 줄을 탭으로 들여쓰면 본문이 시커먼 코드 상자가 된다.
그래서 전각 공백(U+3000) 한 칸을 넣는다. 한국 소설 원고의 표준 들여쓰기이면서, 마크다운이 건드리지 않는 유일하게 안전한 선택이다. 위 스크린샷 마지막 문단이 그렇게 들어가 있다.
3. 인용문 가독성. “인용이 잘 안 보여, 텍스트가.” 회색 55%짜리로 흐리게 깔아뒀더니 종이 위에서 안 읽혔다. 좌측 바가 이미 “이건 인용이다”라고 말하고 있으니, 글자는 본문만큼 진하게(92%) 두는 게 맞았다. 장식이 정보를 가리면 안 된다.
4. 기본 글꼴을 나눔고딕으로. 지난 릴리스에서 글꼴 4종을 앱에 내장했으니, 기본값도 내장 글꼴로 바꿨다. 기존 설정도 함께 옮겨가도록 마이그레이션을 넣었다.
5. 섹션 갤러리.

바인더에서 캐릭터를 누르면 인물이 카드로 죽 펼쳐진다. 인스펙터에서 붙인 얼굴 이미지가 그대로 표지가 되고, 카드를 누르면 그 인물의 시트가 열린다. 원고·세계관·노트도 마찬가지다.
장편을 쓰다 보면 인물 이름이 목록의 글자로만 남는다. 얼굴을 걸어두니 “이 사람이 누구였더라”가 사라졌다. 책장이 책을 고르는 화면이라면, 이건 책 안에서 사람을 고르는 화면이다.
못 보고 있던 버그 셋
여기부터가 이번에 배운 것이다.
① 데코레이션이 통째로 사라졌다
정렬 태그를 화면에서 감추려고 CodeMirror의 “블록 교체” 장식을 썼다. 그랬더니 정렬이 아예 적용되지 않았다. 태그도 안 숨겨지고, 가운데 정렬도 안 되고.
원인은 CodeMirror의 제약이었다. 뷰 플러그인은 블록 장식을 제공할 수 없다. 세로 레이아웃에 영향을 주기 때문이다. 그런데 이걸 어기면 “이 장식만 무시”가 아니라 그 플러그인의 장식 세트 전체가 무효가 된다. 정렬뿐 아니라 같이 들어 있던 것까지 다 죽는다.
에러 메시지 하나 없이 조용히. 정렬 장식만 별도 StateField로 분리해서 해결했다.
② 문단의 첫 줄만 정렬이 빠졌다
고쳤더니 이번엔 두 줄짜리 문단에서 첫 줄만 왼쪽에 남았다. 둘째 줄부터는 멀쩡히 가운데.
감춤 범위를 “여는 태그부터 첫 내용 줄 직전까지” 한 번에 잡았는데, 그 범위의 끝이 첫 내용 줄의 시작점과 정확히 맞닿았다. 그러자 그 줄에 붙여둔 정렬 장식이 감춤 범위에 먹혀 사라진 것이다.
감춤 범위가 태그 줄 안에서 끝나도록 고쳤다. 그리고 테스트를 한 줄짜리 문단에서 두 줄짜리로 바꿨다. 한 줄로 테스트하면 영원히 못 잡는 버그였다. 테스트가 통과한다고 기능이 되는 게 아니라, 테스트가 그 버그를 잡을 수 있게 생겼는지가 문제다.
③ 인용문에서 빠져나올 수 없다
설치파일을 다 만들고, 마지막으로 패키지된 앱을 띄워 저장된 파일을 열어봤다.
> 인용문입니다
>
> 다시 본문
인용문을 쓰고 Enter를 눌러도 계속 인용 기호가 따라붙었다. 이후 본문이 전부 인용문 안에 갇혀 있었다. 그런데 화면에선 그 기호를 감추고 있으니 눈으로는 전혀 보이지 않는다. 파일을 열어야만 드러난다.
파보니 마크다운 확장이 Enter 키를 높은 우선순위로 선점하고 있었고, 그 구현은 빈 인용 줄이 두 번 연속돼야만 인용을 빠져나온다. 즉 사용자는 Enter를 세 번 눌러야 했다. 그걸 알 리가 없다.
Enter 한 번이면 나오게 고쳤다. 인용문과 다음 문단 사이에 빈 줄도 확보했다 — 빈 줄이 없으면 마크다운이 다음 문단을 다시 인용문으로 빨아들인다.
하필 인용문이 이번 릴리스에서 처음 제대로 렌더되기 시작했다. 안 보이던 시절엔 아무도 인용문을 안 썼으니 문제가 드러나지 않았던 것이다. 기능을 고치자 그 기능의 진짜 문제가 따라 나왔다.
그래서 검증을 이렇게 한다
- 타입 검사 0, 유닛 50건, 편집기 E2E 32건, 책장 E2E 5건
- 패키지 스모크 — 개발 빌드가 아니라 설치파일과 동일한 산출물을 띄워 다시 확인한다
- 인용문·들여쓰기 같은 건 화면이 아니라 저장된 원본 파일로 검증한다
세 번째가 이번의 교훈이다. 화면은 거짓말을 한다. 라이브 프리뷰가 기호를 감추고 있으면, 눈으로 보는 것과 파일에 적힌 것이 다르다. 진실의 원천은 파일이다. 그러면 테스트도 파일을 봐야 한다.
다음
- macOS 빌드 (절차는 저장소
docs/BUILD-MAC.md에 정리해뒀다) - 위키링크 + 백링크, 전문 검색
- 스냅샷·버전 비교
집필 도구를 만들며 계속 확인하는 게 있다. 쓰는 사람은 버그 리포트를 이렇게 쓰지 않는다. “뷰 플러그인이 블록 장식을 제공할 수 없어서요.” 그냥 이렇게 쓴다. “인용이 잘 안 보여, 텍스트가.”
그 한 줄 뒤에 무엇이 있는지 파는 게 내 일이다.