fix(cafe24): 소스 들여쓰기 정상화 + 줄 번호·가로 스크롤 편집기
1) 들여쓰기가 안 되던 원인 인라인 요소가 여러 줄에 걸쳐 있으면 그 구간을 하나의 텍스트 덩어리로 다뤄 첫 줄에만 들여쓰기를 붙이고 있었다. 그래서 <img> 가 한 줄에 하나씩 적힌 상세페이지에서 두 번째 <img> 부터 1열에 붙어 나왔다. 원문 줄바꿈을 살리면서 각 줄을 현재 깊이로 들여쓰도록 고쳤다. 줄 앞 공백은 렌더링에 영향이 없으므로 안전하다. 상세페이지는 <img> 를 한 줄에 하나씩 적어두는 경우가 많고 그 모양이 저자의 의도라, 한 줄로 합치는 것보다 살리는 쪽이 읽기 좋다. 주석도 줄을 강제로 나누지 않게 바꿨다. `<!-- 대파_타임랩스 --><img ...>` 처럼 바로 뒤 요소를 설명하는 주석이 많아서, 나누면 라벨과 대상이 떨어져 오히려 읽기 나빠진다. 빈 줄은 구획 표시로 한 줄까지 유지한다. 이 과정에서 멱등성이 다시 깨지는 것을 테스트가 잡았다 — 텍스트 끝에 남은 "\n " 조각이 매번 빈 줄로 바뀌고 있었고, 양 끝 공백을 함께 제거하도록 고쳤다. 2) 줄 번호와 가로 스크롤 전문 편집기처럼 줄 번호 칸을 넣었다. 줄바꿈을 허용하면 한 논리 줄이 여러 행이 되어 번호가 어긋나므로, 줄바꿈을 끄고(white-space:pre + wrap=off) 가로로 스크롤한다. 번호 칸은 position:sticky 라 가로로 스크롤해도 왼쪽에 남는다. 크기 계산도 단순해졌다. <pre> 가 흐름에 남아 상자 크기를 정하고 textarea 가 inset:0 으로 그 위를 덮는다 — JS 로 높이를 맞추지 않으니 어긋날 여지가 없다. 색상 계열은 그대로 뒀다(태그 초록·속성 갈색·값 남색·주석 회색). 검증: 유닛테스트 45개 통과(신규 4개 — 모든 줄 들여쓰기, 주석과 요소 붙임, 빈 줄 1개 유지, 실제 상세페이지 모양 멱등). 브라우저 실측: 줄 번호 개수가 줄 수와 일치(18/18, 19/19), 번호와 코드의 세로 위치 일치, 긴 줄에서 편집기 안에서만 가로 스크롤(1920 > 716)되고 페이지는 가로 스크롤 없음, 400px 스크롤 후에도 번호 칸 고정, textarea 내부 스크롤 0(두 층 정렬 유지). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -241,12 +241,29 @@ def _format_html(source: str, indent: str) -> str:
|
||||
return indent * min(max(level, 0), _MAX_INDENT)
|
||||
|
||||
def flush() -> None:
|
||||
"""모아둔 인라인/텍스트를 한 줄로 내보낸다(빈 줄은 버린다)."""
|
||||
"""모아둔 인라인/텍스트를 내보낸다.
|
||||
|
||||
원문에 이미 있던 줄바꿈은 **그대로 살린다.** 이미지가 한 줄에 하나씩 적혀
|
||||
있으면 그 모양이 저자의 의도이고, 한 줄로 합치면 오히려 읽기 어려워진다.
|
||||
각 줄마다 현재 깊이로 들여쓴다(줄 앞 공백은 렌더링에 영향이 없다).
|
||||
빈 줄은 연속 한 개까지만 남겨 구획을 유지한다.
|
||||
"""
|
||||
nonlocal buffer
|
||||
# 양 끝 공백을 함께 제거한다. `"\n"` 만 벗기면 끝에 남은 `"\n "` 조각이
|
||||
# 빈 줄로 바뀌어 실행마다 빈 줄이 하나씩 늘어난다(멱등 깨짐).
|
||||
# 블록 태그 경계의 공백은 렌더링에 영향이 없으므로 제거해도 안전하다.
|
||||
text = buffer.strip()
|
||||
if text:
|
||||
lines.append(pad(depth) + text)
|
||||
buffer = ""
|
||||
if not text:
|
||||
return
|
||||
for raw_line in text.split("\n"):
|
||||
line = raw_line.strip()
|
||||
if not line:
|
||||
# 문서 맨 앞이나 빈 줄 뒤에는 빈 줄을 더하지 않는다.
|
||||
if lines and lines[-1] != "":
|
||||
lines.append("")
|
||||
continue
|
||||
lines.append(pad(depth) + line)
|
||||
|
||||
position = 0
|
||||
while True:
|
||||
@@ -259,10 +276,12 @@ def _format_html(source: str, indent: str) -> str:
|
||||
position = match.end()
|
||||
raw = match.group(0)
|
||||
|
||||
# 주석·DOCTYPE 등은 한 줄 차지
|
||||
# 주석·DOCTYPE 등은 흐름에 그대로 둔다.
|
||||
# 상세페이지에는 `<!-- 대파_타임랩스 --><img ...>` 처럼 바로 뒤 요소를
|
||||
# 설명하는 주석이 많다. 줄을 강제로 나누면 라벨과 대상이 떨어져 오히려
|
||||
# 읽기 나빠진다. 원문에서 줄이 나뉘어 있었다면 flush 가 그 줄바꿈을 살린다.
|
||||
if match.group("comment") or match.group("cdata") or match.group("decl"):
|
||||
flush()
|
||||
lines.append(pad(depth) + raw.strip())
|
||||
buffer += raw
|
||||
continue
|
||||
|
||||
name = (match.group("name") or "").lower()
|
||||
|
||||
Reference in New Issue
Block a user