From 8e37b454edb68bf4573b75a6a4f2855e1db4ea08 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Mar 2026 09:24:02 +0000 Subject: [PATCH 1/2] Initial plan From e84c148daa89e46c81b8233027ccfb52bd5bc6d0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Mar 2026 09:30:05 +0000 Subject: [PATCH 2/2] Improve code quality: stale-doc guard, style fixes, DRY CSS injection, expanded tests Co-authored-by: cyanzhong <6745066+cyanzhong@users.noreply.github.com> --- src/card.ts | 8 ++------ src/extension.ts | 9 ++------- src/menu.ts | 9 +++++++-- src/panel.ts | 7 ++----- src/settings.ts | 2 +- src/styling.ts | 9 +++++++++ src/tooltip.ts | 9 ++------- tests/card.test.ts | 37 +++++++++++++++++++++++++++++++++++++ tests/kinds.test.ts | 28 ++++++++++++++++++++++++++++ tests/rules.test.ts | 36 ++++++++++++++++++++++++++++++++++++ tests/styling.test.ts | 24 +++++++++++++++++++++++- 11 files changed, 149 insertions(+), 29 deletions(-) create mode 100644 tests/card.test.ts create mode 100644 tests/kinds.test.ts create mode 100644 tests/rules.test.ts diff --git a/src/card.ts b/src/card.ts index ea225cc..bd43f6d 100644 --- a/src/card.ts +++ b/src/card.ts @@ -13,7 +13,7 @@ import { EditorView } from '@codemirror/view'; import { diagnosticsField, setDiagnosticsEffect } from './decoration'; import type { Diagnostic } from './decoration'; import { addToDictionary, shouldAddToDict } from './lint'; -import { kindColors, kindColorsDark, fallback, fallbackDark } from './styling'; +import { kindColors, kindColorsDark, fallback, fallbackDark, injectStyleSheet } from './styling'; /** Set `--harper-kind-color` / `--harper-kind-color-dark` CSS custom properties on an element. */ export function setAccentColor(el: HTMLElement, lintKind: string) { @@ -188,9 +188,5 @@ export function cardContentCSS(): string { /** Inject the shared card content CSS once. */ export function injectCardCSS() { - if (document.getElementById('harper-card-base-styles')) return; - const style = document.createElement('style'); - style.id = 'harper-card-base-styles'; - style.textContent = cardContentCSS(); - document.head.appendChild(style); + injectStyleSheet('harper-card-base-styles', cardContentCSS()); } diff --git a/src/extension.ts b/src/extension.ts index 3166f1c..d6b08e7 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,19 +6,14 @@ import { MarkEdit } from 'markedit-api'; import { diagnosticsField, setDiagnosticsEffect, lintToDiagnostic } from './decoration'; import { clickTooltipField, tooltipHandlers } from './tooltip'; import { panelExtension } from './panel'; -import { baseTheme, kindCSS } from './styling'; +import { baseTheme, kindCSS, injectStyleSheet } from './styling'; import { lint } from './lint'; import { getProofreadingSettings } from './settings'; const { autoLintDelay } = getProofreadingSettings(MarkEdit.userSettings); const kindStyleInjector = ViewPlugin.define(() => { - if (!document.getElementById('harper-kind-styles')) { - const style = document.createElement('style'); - style.id = 'harper-kind-styles'; - style.textContent = kindCSS(); - document.head.appendChild(style); - } + injectStyleSheet('harper-kind-styles', kindCSS()); return {}; }); diff --git a/src/menu.ts b/src/menu.ts index 4f57212..2604fdd 100644 --- a/src/menu.ts +++ b/src/menu.ts @@ -26,7 +26,7 @@ export function buildMenuItem(): MenuItem { }, { title: 'Reset Dictionary', - action: async() => { + action: async () => { const result = await MarkEdit.showAlert({ title: 'Are you sure you want to reset the dictionary?', message: 'All custom words you have added will be removed. This action cannot be undone.', @@ -54,8 +54,13 @@ export function buildMenuItem(): MenuItem { async function proofreadNow() { const view = MarkEdit.editorView; - const text = view.state.doc.toString(); + const doc = view.state.doc; + const text = doc.toString(); const lints = await lint(text); + + // Bail out if the document changed during linting + if (view.state.doc !== doc) return; + view.dispatch({ effects: setDiagnosticsEffect.of(lints.map(lintToDiagnostic)) }); } diff --git a/src/panel.ts b/src/panel.ts index 7bf8151..6d3a403 100644 --- a/src/panel.ts +++ b/src/panel.ts @@ -5,6 +5,7 @@ import type { ViewUpdate } from '@codemirror/view'; import { diagnosticsField, setDiagnosticsEffect } from './decoration'; import type { Diagnostic } from './decoration'; import { setAccentColor, findDiagnostic, buildCardContent, injectCardCSS } from './card'; +import { injectStyleSheet } from './styling'; const paneWidth = 290; @@ -562,9 +563,5 @@ export function paneCSS(): string { function injectPaneCSS() { injectCardCSS(); - if (document.getElementById('harper-pane-styles')) return; - const style = document.createElement('style'); - style.id = 'harper-pane-styles'; - style.textContent = paneCSS(); - document.head.appendChild(style); + injectStyleSheet('harper-pane-styles', paneCSS()); } diff --git a/src/settings.ts b/src/settings.ts index 5bae35c..ceb2369 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -39,7 +39,7 @@ export function getProofreadingSettings(userSettings: JSONObject | undefined): P ) as LintConfig; const disabledLintKinds = parseStringArray(raw.disabledLintKinds); - const addToDict = raw.addToDict === false ? false : true; + const addToDict = raw.addToDict !== false; return { autoLintDelay, lintPreset, lintRuleOverrides, disabledLintKinds, addToDict }; } diff --git a/src/styling.ts b/src/styling.ts index 68c4fc6..133789d 100644 --- a/src/styling.ts +++ b/src/styling.ts @@ -92,3 +92,12 @@ export const baseTheme = EditorView.baseTheme({ transition: 'text-decoration-color 0.15s, background-color 0.15s', }, }); + +/** Inject a `