C.W.K.
Stream
Lesson 03 of 05 · published

역할 둘 — voice underline

~12 min · voice-underline, voice-doctrine, mark-decoration, job-two

Level 0식은 초고
0 XP0/33 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"맞춤법 검사기는 사전을 알아. voice 검사기는 너를 알아. Rekindle 의 두 번째 decoration 역할이 후자야."

역할 둘 — 맞춤법 검사기가 아니라 voice 검사기

decoration 엔진의 두 번째 역할은 세상 어디에도 없는 거야. 라이브 voice 검사기. 쓰는 동안, voice 규칙을 건드리는 구절 — register 미끄러짐, token-mirror 함정, 지나치게 센 단어 선택 — 에 밑줄을 긋고, 왜인지 설명하는 작은 여백 노트를 띄워. 맞춤법 검사기는 네 텍스트를 모두가 공유하는 사전에 대고 재. voice 검사기는 독트린에 대고 재. 한 작가가 중요하다고 정한 특정 함정과 선호. 맞춤법 검사와 같은 제자리-밑줄 UX 인데, 사적인 무언가를 겨눈 거야.

독트린의 구체적 예: 문서화된 한국어 규칙 하나가 register 에 더 부드러운 선택이 맞는 자리의 박다 — 지나치게 센 동사 — 를 표시해. 문법 오류가 아냐. 어떤 범용 도구도 절대 못 잡아. voice 규칙이고, 한 작가의 독트린을 중심으로 지은 voice 검사기만 그걸 강제할 수 있어.

단일 탐지 경계

메커니즘적으론 mark 플러스 widget 이야. 문제 범위에 밑줄 (mark) 을 긋고 옆에 노트 (widget) 를 붙여. 모든 지능은 함수 하나 detectVoiceIssues(doc) 뒤에 숨어. 문자 범위와 노트를 반환하지. 오늘 탐지는 TypeScript 의 결정론적 규칙이고, 나중에 Rust voice-엔진 substrate 로 옮기거나 AI-판단 레이어를 키울 수 있어 — 그래도 decoration 코드는 안 바뀌어. 오직 범위만 소비하니까. 경계가 트릭 전부야. '뭐가 이슈냐' 를 함수 하나 뒤에 두면, '어떻게 그리냐' 는 탐지가 어떻게 진화하든 동일하게 남아.

type VoiceIssue = { from: number; to: number; note: string };

// 탐지는 경계 하나. 오늘 규칙; 나중에 Rust 나 AI-판단 —
// decoration 레이어는 절대 안 바뀌어, 범위만 소비하니까.
function detectVoiceIssues(doc: string): VoiceIssue[] { /* ... */ }

같은 엔진, 새 목적

물러서서 봐. 이건 Live Preview 의 정확히 그 기계장치를, 다른 질문에 겨눈 거야. Live Preview 는 '마크업이 어디?' 를 묻고 mark 를 그렸어. voice underline 은 'voice 이슈가 어디?' 를 묻고 mark 플러스 노트를 그려. 같은 원시 요소, 새 입력. 트랙의 thesis 가 두 번째로 도착한 거고 — 진짜 새로운 기능 (어디에도 없는 voice 검사기) 이 새 기계장치를 거의 안 들이고 지어진 이유야.

Code

탐지는 경계 하나 뒤; decoration 은 범위를 소비·typescript
type VoiceIssue = { from: number; to: number; note: string };

// 뭐가 voice 이슈인지 아는 유일한 것.
// 오늘 결정론적 규칙; 나중에 Rust substrate 나 AI-판단 레이어.
function detectVoiceIssues(doc: string): VoiceIssue[] {
  // 예: register 가 더 부드러운 걸 원하는 자리의 지나치게 센 동사 표시
  return scanVoiceRules(doc);
}

// decoration 빌더는 탐지가 진화해도 절대 안 바뀌어:
function buildVoiceDecorations(state) {
  return detectVoiceIssues(state.doc.toString()).flatMap((issue) => [
    Decoration.mark({ class: "cm-voice-issue" }).range(issue.from, issue.to),
    Decoration.widget({ widget: new MarginNote(issue.note), side: 1 }).range(issue.to),
  ]);
}

External links

Exercise

네 글쓰기용 voice 규칙 하나를 발명해봐 — 남용하는 단어, 미끄러져 들어가는 register, 잡고 싶은 표현. 이제 그게 decoration 으로 어떻게 드러날지 서술해. 어느 범위에 밑줄이 가고, 여백 노트는 뭐라고 해? 방금 Live Preview 와 같은 메커니즘으로 어떤 범용 도구도 안 싣는 기능을 명세했다는 걸 봐.
Hint
규칙을 범위 + 노트를 반환하는 함수로 틀 잡아. 문서 텍스트가 주어지면, 이슈가 어디 (from/to) 고 한 줄 이유가 뭐야? 그게 네 voice 의 detectVoiceIssues — decoration 코드는 이미 쓰여 있어.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.