From 31cee60cc76e7fc9e46170a3a06946f412ba4826 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 1 May 2026 19:41:31 +0200 Subject: [PATCH] Improve code editor text selection and clean up lint enablement (#37474) 1. Make the content area stretch the box, enabling text selection to start over empty space. 2. Disable linter for markdown, it can never produce lint errors, this hides the unnecessary lint gutter on markdown files. 3. Verified all languages linter enablement, all accurate. 4. Refactor `getLinterExtension` to not rely on file extensions. 5. Include jsonc/json5 extensions in regex. --- This PR was written with the help of Claude Opus 4.7 --------- Co-authored-by: Claude (Opus 4.7) Co-authored-by: Nicolas --- web_src/css/modules/codeeditor.css | 20 +++++++++++--------- web_src/js/modules/codeeditor/main.ts | 19 +++++++++++-------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/web_src/css/modules/codeeditor.css b/web_src/css/modules/codeeditor.css index 11b772c05c9..558ba7a44fc 100644 --- a/web_src/css/modules/codeeditor.css +++ b/web_src/css/modules/codeeditor.css @@ -24,6 +24,8 @@ font-family: var(--fonts-monospace); font-size: 12px; max-height: 90vh; + flex: 1; + min-height: 0; } .code-editor-container .cm-editor, @@ -31,24 +33,22 @@ border-radius: 0 0 var(--border-radius) var(--border-radius); } -.code-editor-container .cm-content, -.code-editor-container .cm-gutter { - min-height: 200px; -} - .code-editor-container .cm-scroller { overflow: auto; line-height: var(--line-height-code); + flex: 1; + min-height: 0; +} + +.code-editor-container .cm-content { + align-self: stretch; + padding: 0; } .code-editor-container .cm-content * { caret-color: inherit; } -.code-editor-container .cm-content { - padding: 0; -} - .code-editor-container .cm-cursor, .code-editor-container .cm-dropCursor { border-left-color: var(--color-caret); @@ -341,6 +341,8 @@ .code-editor-container { position: relative; min-height: 90vh; + display: flex; + flex-direction: column; } .cm-command-palette { diff --git a/web_src/js/modules/codeeditor/main.ts b/web_src/js/modules/codeeditor/main.ts index 320d73dd9ff..e847f357cb3 100644 --- a/web_src/js/modules/codeeditor/main.ts +++ b/web_src/js/modules/codeeditor/main.ts @@ -7,7 +7,7 @@ import type {PaletteCommand} from './command-palette.ts'; import {contextMenu, collectSymbols, selectAllOccurrences} from './context-menu.ts'; import {createJsonLinter, createSyntaxErrorLinter} from './linter.ts'; import {clickableUrls, goToDefinitionAt, trimTrailingWhitespaceFromView} from './utils.ts'; -import type {LanguageDescription} from '@codemirror/language'; +import type {LanguageDescription, LanguageSupport} from '@codemirror/language'; import type {Compartment, Extension} from '@codemirror/state'; import type {EditorView, ViewUpdate} from '@codemirror/view'; @@ -295,16 +295,19 @@ export async function createCodeEditor(textarea: HTMLTextAreaElement, filenameIn return editor; } -// files that are JSONC despite having a .json extension -const jsoncFilesRegex = /^([jt]sconfig.*|devcontainer)\.json$/; +// files that the JSON parser is too strict for (comments, trailing commas) +const jsoncFilesRegex = /^([jt]sconfig.*|devcontainer)\.json$|\.(jsonc|json5)$/i; -async function getLinterExtension(cm: CodemirrorModules, filename: string, loadedLang: {language: unknown} | null): Promise { - const ext = extname(filename).toLowerCase(); - if (ext === '.json' || ext === '.map') { +async function getLinterExtension(cm: CodemirrorModules, filename: string, loadedLang: LanguageSupport | null): Promise { + if (!loadedLang) return []; + const lang = loadedLang.language; + // StreamLanguage (legacy modes) don't produce Lezer error nodes + if (lang instanceof cm.language.StreamLanguage) return []; + if (lang.name === 'json') { return jsoncFilesRegex.test(filename) ? [] : [cm.lint.lintGutter(), await createJsonLinter(cm)]; } - // StreamLanguage (legacy modes) don't produce Lezer error nodes - if (!loadedLang || loadedLang.language instanceof cm.language.StreamLanguage) return []; + // markdown's parser emits no error nodes, and nested code-fence overlays aren't traversed + if (lang.name === 'markdown') return []; return [cm.lint.lintGutter(), createSyntaxErrorLinter(cm)]; }