From 87e9bec4f984ea432e87b721b511428a18548076 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Wed, 4 Nov 2026 09:55:32 +0800 Subject: [PATCH] fix(todo): colour TODO comments in the TODO tool window's preview (#1143) The preview is an editor view over the real document but doesn't get the editor contributions, so TODO comments showed in plain comment colour there. It now adds the same TODO colouring; the live item scan stays with the editor contribution. --- src/features/todo/PreviewEditor.test.tsx | 12 ++++++++++++ src/features/todo/PreviewEditor.tsx | 2 ++ src/features/todo/highlight.ts | 12 +++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/features/todo/PreviewEditor.test.tsx b/src/features/todo/PreviewEditor.test.tsx index 5653cf0e6..b0c95ecb6 100644 --- a/src/features/todo/PreviewEditor.test.tsx +++ b/src/features/todo/PreviewEditor.test.tsx @@ -51,6 +51,18 @@ describe("PreviewEditor", () => { expect(document.querySelector(".cm-content")?.textContent).toContain("TODO: fix"); }); + it("colours TODO comments like the editor tabs", async () => { + const docs = new Map([["/p/c.js", { text: "// TODO: fix\nconst x = 1;\n" }]]); + stubAttacher(docs); + render(); + const todo = await waitFor(() => { + const el = document.querySelector(".cm-openidea-todo"); + expect(el).toBeTruthy(); + return el!; + }); + expect(todo.textContent).toBe("TODO: fix"); + }); + it("moves the caret to another item of the same file without a new view", async () => { const docs = new Map([["/p/two.ts", { text: "// TODO: one\nconst x = 1;\n// TODO: two\n" }]]); stubAttacher(docs); diff --git a/src/features/todo/PreviewEditor.tsx b/src/features/todo/PreviewEditor.tsx index a2c634bd4..dfb951a3d 100644 --- a/src/features/todo/PreviewEditor.tsx +++ b/src/features/todo/PreviewEditor.tsx @@ -21,6 +21,7 @@ import { openideaHighlightStyle } from "@/editor/core/cm/highlight"; import { findLanguageDescription, loadSupport } from "@/editor/core/cm/languages"; import { attachDocument, embeddedEditorExtensions, type DocumentAttachment } from "@/editor/api"; import { SourcePreview, T, type SourceHighlight } from "@/ui"; +import { todoHighlightExtension } from "./highlight"; import styles from "./TodoView.module.css"; /** Dirty attachments kept alive after their view unmounted (see header note). */ @@ -95,6 +96,7 @@ export function PreviewEditor({ keymap.of([...historyKeymap, ...searchKeymap, ...defaultKeymap]), att.extension, embeddedEditorExtensions(path), + todoHighlightExtension(), language.of([]), ], }), diff --git a/src/features/todo/highlight.ts b/src/features/todo/highlight.ts index 7fdafd962..d54603872 100644 --- a/src/features/todo/highlight.ts +++ b/src/features/todo/highlight.ts @@ -90,6 +90,16 @@ const theme = EditorView.baseTheme({ }); export function todoEditorExtension(ctx: EditorDocContext): Extension { + return todoPlugin(ctx); +} + +/** The colouring alone, for views outside the editor tabs (the TODO tool window's preview). */ +export function todoHighlightExtension(): Extension { + return todoPlugin(null); +} + +/** `ctx` given: also reports the document's live TODO items to the tool window. */ +function todoPlugin(ctx: EditorDocContext | null): Extension { const plugin = ViewPlugin.fromClass( class { decorations: DecorationSet; @@ -112,7 +122,7 @@ export function todoEditorExtension(ctx: EditorDocContext): Extension { if (u.docChanged) this.scheduleLive(400); } scheduleLive(delay: number) { - if (!ctx.path || ctx.virtual) return; + if (!ctx?.path || ctx.virtual) return; if (this.timer) clearTimeout(this.timer); this.timer = setTimeout(() => { this.timer = null;