From 0dffad814a64ac736a30cdbfda6bfb51b5f8c61c Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Wed, 4 Nov 2026 03:01:03 +0800 Subject: [PATCH] fix(editor): show wavy and dotted underlines on macOS (#1086) Error, warning, weak-warning and typo underlines never showed on macOS, nor did underline effects of syntax tokens from a colour scheme: WebKit rejects a text-decoration shorthand with a style or colour (underline wavy ), so the declaration fell back to none. The editor's diagnostic and token styles also set -webkit-text-decoration, which WebKit takes the full value through; the red wavy underlines of the Problems, Build, Project and Database views use the longhand properties. --- src/editor/core/cm/highlight.ts | 2 ++ src/editor/lsp/diagnostics.ts | 8 ++++++++ src/features/build/Build.module.css | 4 +++- src/features/code-insight/ProblemsView.module.css | 4 +++- src/features/database/Database.module.css | 4 +++- src/features/project-tree/ProjectView.module.css | 4 +++- src/features/settings/pages/editor/colorScheme.tsx | 2 ++ 7 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/editor/core/cm/highlight.ts b/src/editor/core/cm/highlight.ts index 472c5e848..d46306da1 100644 --- a/src/editor/core/cm/highlight.ts +++ b/src/editor/core/cm/highlight.ts @@ -18,6 +18,8 @@ function token( fontWeight: `var(--syn-${name}-bold, ${defaults.bold ?? "inherit"})`, backgroundColor: `var(--syn-${name}-bg, transparent)`, textDecoration: `var(--syn-${name}-effect, ${defaults.effect ?? "none"})`, + // WebKit takes a decoration with a style or colour only through the prefixed property. + WebkitTextDecoration: `var(--syn-${name}-effect, ${defaults.effect ?? "none"})`, }; } diff --git a/src/editor/lsp/diagnostics.ts b/src/editor/lsp/diagnostics.ts index 656912926..5bef06e08 100644 --- a/src/editor/lsp/diagnostics.ts +++ b/src/editor/lsp/diagnostics.ts @@ -213,21 +213,26 @@ const diagnosticsSync = ViewPlugin.fromClass( // Effects follow the IDEA schemes: errors wavy red; warnings wavy yellow (dark) or // a yellow background (light, via --editor-warning-*); weak warnings dotted; typos wavy green. +// WebKit drops a `text-decoration` with a style or colour; `-webkit-text-decoration`, set after +// it, takes the whole value there. const lintTheme = EditorView.theme({ ".cm-lintRange": { backgroundImage: "none", paddingBottom: "0" }, ".cm-lintRange-error": { textDecoration: "var(--editor-error-decoration, underline wavy var(--danger))", + WebkitTextDecoration: "var(--editor-error-decoration, underline wavy var(--danger))", textDecorationSkipInk: "none", textUnderlineOffset: "3px", }, ".cm-lintRange-warning": { textDecoration: "var(--editor-warning-decoration, underline wavy var(--warning))", + WebkitTextDecoration: "var(--editor-warning-decoration, underline wavy var(--warning))", backgroundColor: "var(--editor-warning-background, transparent)", textDecorationSkipInk: "none", textUnderlineOffset: "3px", }, ".cm-lintRange-info": { textDecoration: "underline dotted color-mix(in srgb, var(--fg-muted) 80%, transparent)", + WebkitTextDecoration: "underline dotted color-mix(in srgb, var(--fg-muted) 80%, transparent)", textDecorationSkipInk: "none", textUnderlineOffset: "3px", }, @@ -235,6 +240,7 @@ const lintTheme = EditorView.theme({ // Typo level: IDEA's green wavy underline. ".cm-lintRange.cm-lsp-typo": { textDecoration: "underline wavy color-mix(in srgb, var(--success) 85%, transparent)", + WebkitTextDecoration: "underline wavy color-mix(in srgb, var(--success) 85%, transparent)", textDecorationSkipInk: "none", textUnderlineOffset: "3px", }, @@ -248,9 +254,11 @@ const lintTheme = EditorView.theme({ // An error or warning on the same range (merged into one mark) keeps its underline. ".cm-lintRange-error.cm-lsp-typo, .cm-lintRange-error.cm-lsp-unnecessary": { textDecoration: "var(--editor-error-decoration, underline wavy var(--danger))", + WebkitTextDecoration: "var(--editor-error-decoration, underline wavy var(--danger))", }, ".cm-lintRange-warning.cm-lsp-typo, .cm-lintRange-warning.cm-lsp-unnecessary": { textDecoration: "var(--editor-warning-decoration, underline wavy var(--warning))", + WebkitTextDecoration: "var(--editor-warning-decoration, underline wavy var(--warning))", }, ".cm-lintRange-active": { backgroundColor: "transparent" }, ".cm-lintRange-warning.cm-lintRange-active": { backgroundColor: "var(--editor-warning-background, transparent)" }, diff --git a/src/features/build/Build.module.css b/src/features/build/Build.module.css index be0f0c465..708d9504a 100644 --- a/src/features/build/Build.module.css +++ b/src/features/build/Build.module.css @@ -42,7 +42,9 @@ color: var(--fg-muted); } .fileError { - text-decoration: underline wavy var(--danger); + text-decoration-line: underline; + text-decoration-style: wavy; + text-decoration-color: var(--danger); text-decoration-skip-ink: none; text-underline-offset: 3px; } diff --git a/src/features/code-insight/ProblemsView.module.css b/src/features/code-insight/ProblemsView.module.css index be2e71b68..936c9d650 100644 --- a/src/features/code-insight/ProblemsView.module.css +++ b/src/features/code-insight/ProblemsView.module.css @@ -42,7 +42,9 @@ color: var(--fg-strong); } .fileError { - text-decoration: underline wavy var(--danger); + text-decoration-line: underline; + text-decoration-style: wavy; + text-decoration-color: var(--danger); text-decoration-skip-ink: none; text-underline-offset: 3px; } diff --git a/src/features/database/Database.module.css b/src/features/database/Database.module.css index 909df5869..7f47f5591 100644 --- a/src/features/database/Database.module.css +++ b/src/features/database/Database.module.css @@ -292,7 +292,9 @@ /* Inline statement errors in consoles. */ :global(.cm-openidea-db-error) { - text-decoration: underline wavy var(--danger); + text-decoration-line: underline; + text-decoration-style: wavy; + text-decoration-color: var(--danger); text-underline-offset: 3px; } diff --git a/src/features/project-tree/ProjectView.module.css b/src/features/project-tree/ProjectView.module.css index d499db233..96ec9a6c9 100644 --- a/src/features/project-tree/ProjectView.module.css +++ b/src/features/project-tree/ProjectView.module.css @@ -51,7 +51,9 @@ background: color-mix(in srgb, var(--vcs-ignored) 14%, transparent); } .error { - text-decoration: underline wavy var(--danger); + text-decoration-line: underline; + text-decoration-style: wavy; + text-decoration-color: var(--danger); text-decoration-skip-ink: none; text-underline-offset: 3px; } diff --git a/src/features/settings/pages/editor/colorScheme.tsx b/src/features/settings/pages/editor/colorScheme.tsx index 75aa54df1..16024a1e8 100644 --- a/src/features/settings/pages/editor/colorScheme.tsx +++ b/src/features/settings/pages/editor/colorScheme.tsx @@ -89,6 +89,8 @@ function tokenStyle(attr: AttributeDef | undefined): CSSProperties { fontStyle: `var(--syn-${t}-italic, ${t === "comment" ? "var(--syn-comment-style)" : t === "doc-comment" || t === "docstring" ? "italic" : "inherit"})`, backgroundColor: `var(--syn-${t}-bg, transparent)`, textDecoration: `var(--syn-${t}-effect, none)`, + // WebKit takes a decoration with a style or colour only through the prefixed property. + ...({ WebkitTextDecoration: `var(--syn-${t}-effect, none)` } as CSSProperties), }; }