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

decoration 메커니즘

~12 min · decoration, mark, widget, cm6

Level 0식은 초고
0 XP0/33 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"decoration 은 소스를 안 바꾸고 위에 칠해. 그 한 속성이 메커니즘 하나가 전부를 할 수 있는 이유야."

두 종류의 decoration

CodeMirror 6 은 소스 위에 시각 레이어를 더하는 방법을 딱 둘 줘. mark decoration 은 텍스트 범위에 스타일을 붙여 — 4–8 문자를 bold, 12–16 문자를 빨간 밑줄. widget decoration 은 위치에 UI 조각을 삽입해 — 단어 뒤 여백 노트, 줄 밑 제안 블록 통째. mark 는 있는 걸 스타일하고, widget 은 없는 걸 삽입해. 둘이 합쳐 기능이 원할 모든 '뭔가 추가로 보여주기' 를 커버해.

소스 위에 칠하지, 절대 mutate 안 해

decoration 을 강력하게 만드는 속성은 그게 안 하는 것이야. 절대 문서를 안 바꿔. bold mark 는 텍스트에 서식을 삽입하지 않아. 이미 거기 있는 문자를 bold 로 렌더할 뿐. widget 은 파일에 안 써. 뷰의 한 지점에 UI 를 칠할 뿐. 소스 문자열은 그대로야. decoration 은 매 편집마다 문서에서 DecorationSet 을 다시 계산하는 StateField 에 살아:

const decoField = StateField.define<DecorationSet>({
  create: () => Decoration.none,
  update: (deco, tr) => buildDecorations(tr.state), // 범위 -> mark + widget
  provide: (f) => EditorView.decorations.from(f),
});

원시 요소 하나, 모든 '추가로 보여주기' 기능

트릭 전체가 여기 있어. decoration 이 모델을 안 건드리고 레이어를 더하니까, '사용자 텍스트 위에 뭔가 추가로 보여주기' 를 뜻하는 어떤 기능도 같은 원시 요소로 줄어들어. 범위 집합을 계산하고, mark 나 widget 을 붙이고, CM6 이 렌더하게 둬. Live Preview 는 범위-to-mark. voice underline 은 범위-to-mark-플러스-widget. CMD+K 는 제안을 담은 widget. 관련 없어 보이는 세 기능이, 밑에선, 입력만 다른 같은 계산이야. 그게 트랙 전체의 씨앗이야.

Code

mark 는 범위를 스타일; widget 은 UI 삽입 — 둘 다 소스 위·typescript
import { Decoration, DecorationSet, EditorView, WidgetType } from "@codemirror/view";
import { StateField } from "@codemirror/state";

// MARK: 있는 소스의 범위를 스타일 (**bold** 를 bold 로 렌더).
const boldMark = Decoration.mark({ class: "cm-strong" });

// WIDGET: 텍스트를 안 바꾸고 위치에 UI 삽입.
class MarginNote extends WidgetType {
  constructor(readonly text: string) { super(); }
  toDOM() {
    const s = document.createElement("span");
    s.className = "cm-margin-note";
    s.textContent = this.text;
    return s;
  }
}

// StateField 가 현재 DecorationSet 을 쥐고 편집마다 다시 계산해.
const decoField = StateField.define<DecorationSet>({
  create: () => Decoration.none,
  update: (deco, tr) => buildDecorations(tr.state), // 범위 -> mark + widget
  provide: (f) => EditorView.decorations.from(f),
});
// 문서는 절대 mutate 안 돼. 칠한 레이어만 바뀌어.

External links

Exercise

Rekindle 의 세 soul 기능 각각이 주로 mark 가 필요한지 widget 이 필요한지 정해봐. (1) **bold** 를 bold 로 렌더, (2) voice 이슈에 밑줄 긋고 옆에 노트 띄우기, (3) 수락 전 선택 줄 밑에 AI 재작성 제안 보여주기. 그다음 왜 셋 중 아무것도 문서를 mutate 할 필요가 없는지 한 문장으로 말해봐.
Hint
렌더와 밑줄은 있는 문자를 스타일 → mark (밑줄 옆 노트는 작은 widget). 제안 블록은 위치에 삽입된 새 UI → widget. 셋 다 문서를 mutate 안 하는 건 decoration 이 소스 위에 칠한 뷰 레이어지 그것에 대한 편집이 아니라서야.

Progress

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

댓글 0

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

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