diff --git a/web_src/css/modules/codeeditor.css b/web_src/css/modules/codeeditor.css index 11b772c05c..558ba7a44f 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 320d73dd9f..e847f357cb 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)]; }