From 3fa1c3487c6a1aec450eb08621ff7440f7d6e23c Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Wed, 25 Feb 2026 23:39:46 +0200 Subject: [PATCH 1/9] language editor support --- src/livecodes/editor/codejar/codejar.ts | 3 +- src/livecodes/editor/codemirror/codemirror.ts | 18 +- .../editor/codemirror/editor-languages.ts | 4 - src/livecodes/editor/monaco/monaco.ts | 223 +++++++++--------- src/livecodes/languages/python/lang-python.ts | 9 +- src/livecodes/languages/utils.ts | 10 +- src/livecodes/languages/vue/lang-vue.ts | 23 +- src/livecodes/vendors.ts | 7 +- src/sdk/models.ts | 26 +- 9 files changed, 192 insertions(+), 131 deletions(-) diff --git a/src/livecodes/editor/codejar/codejar.ts b/src/livecodes/editor/codejar/codejar.ts index 400684159a..4f0663673e 100644 --- a/src/livecodes/editor/codejar/codejar.ts +++ b/src/livecodes/editor/codejar/codejar.ts @@ -38,7 +38,8 @@ export const createEditor = async (options: EditorOptions): Promise let { value, language } = options; let currentPosition: EditorPosition = { lineNumber: 1 }; - const mapLanguage = options.mapLanguage || ((lang: Language) => lang); + const mapLanguage = (lang: Language) => + options.mapLanguage?.(lang, 'codejar') || ((lang: Language) => lang); let mappedLanguage = language === 'wat' ? 'wasm' : mapLanguage(language); let editorOptions: ReturnType; diff --git a/src/livecodes/editor/codemirror/codemirror.ts b/src/livecodes/editor/codemirror/codemirror.ts index 9d48d8a80e..8d9a20661b 100644 --- a/src/livecodes/editor/codemirror/codemirror.ts +++ b/src/livecodes/editor/codemirror/codemirror.ts @@ -29,6 +29,7 @@ import { colorPicker } from '@replit/codemirror-css-color-picker'; // these are imported normally import { getEditorModeNode } from '../../UI/selectors'; +import { getLanguageSpecs } from '../../languages'; import type { CodeEditor, CodemirrorTheme, @@ -68,14 +69,25 @@ export const createEditor = async (options: EditorOptions): Promise let editorSettings: EditorConfig = { ...options }; if (!container) throw new Error('editor container not found'); - const getLanguageSupport = async (language: Language): Promise => - editorLanguages[language]?.() || (editorLanguages.html?.() as Promise); + const getLanguageSupport = async (lang: Language): Promise => { + const langSupport = getLanguageSpecs(lang)?.editorSupport?.codemirror?.languageSupport; + if (!langSupport) { + return editorLanguages[language]?.() || editorLanguages.html?.() || []; + } + const loadLanguage: () => Promise = + typeof langSupport === 'string' + ? (await import(langSupport)).default + : typeof langSupport === 'function' + ? langSupport + : async () => []; + return loadLanguage(); + }; const mapLanguage = (lang: Language) => { if (lang.startsWith('vue')) return 'vue'; if (lang.startsWith('svelte')) return 'svelte'; if (lang === 'liquid') return 'liquid'; - return options.mapLanguage?.(lang) || lang; + return options.mapLanguage?.(lang, 'codemirror') || lang; }; const themes: Partial> = { diff --git a/src/livecodes/editor/codemirror/editor-languages.ts b/src/livecodes/editor/codemirror/editor-languages.ts index 9a3c6731f1..b8189d79dd 100644 --- a/src/livecodes/editor/codemirror/editor-languages.ts +++ b/src/livecodes/editor/codemirror/editor-languages.ts @@ -20,12 +20,10 @@ const legacy = (parser: StreamParser) => const getPath = (mod: string) => codeMirrorBaseUrl + mod; const moduleUrls = { - vue: getPath('codemirror-lang-vue.js'), svelte: getPath('codemirror-lang-svelte.js'), liquid: getPath('codemirror-lang-liquid.js'), json: getPath('codemirror-lang-json.js'), markdown: getPath('codemirror-lang-markdown.js'), - python: getPath('codemirror-lang-python.js'), php: getPath('codemirror-lang-php.js'), java: getPath('codemirror-lang-java.js'), clike: getPath('codemirror-lang-clike.js'), @@ -61,11 +59,9 @@ export const editorLanguages: Partial<{ [key in Language]: () => Promise javascript({ jsx: true }), tsx: async () => javascript({ jsx: true, typescript: true }), json: async () => json(), - vue: async () => (await import(moduleUrls.vue)).vue(), svelte: async () => (await import(moduleUrls.svelte)).svelte(), liquid: async () => (await import(moduleUrls.liquid)).liquid(), markdown: async () => (await import(moduleUrls.markdown)).markdown(), - python: async () => (await import(moduleUrls.python)).python(), php: async () => (await import(moduleUrls.php)).php(), go: async () => (await import(moduleUrls.go)).go(), java: async () => (await import(moduleUrls.java)).java(), diff --git a/src/livecodes/editor/monaco/monaco.ts b/src/livecodes/editor/monaco/monaco.ts index 13a244c096..f0b7fcb83c 100644 --- a/src/livecodes/editor/monaco/monaco.ts +++ b/src/livecodes/editor/monaco/monaco.ts @@ -2,6 +2,7 @@ import type * as Monaco from 'monaco-editor'; import { getEditorModeNode } from '../../UI/selectors'; import { getImports } from '../../compiler/import-map'; +import { getLanguageSpecs } from '../../languages'; import type { APIError, CodeEditor, @@ -24,7 +25,7 @@ import { monacoBaseUrl, monacoEmacsUrl, monacoVimUrl, - monacoVolarUrl, + typescriptVersion, vendorsBaseUrl, } from '../../vendors'; import { getEditorTheme } from '../themes'; @@ -37,17 +38,15 @@ type Options = Monaco.editor.IStandaloneEditorConstructionOptions; let monacoGloballyLoaded = false; const disposeEmmet: { html?: any; css?: any; jsx?: any; disabled?: boolean } = {}; let monaco: typeof Monaco; +const loadedLanguages = new Set(); const loadedThemes = new Set(); // let codeiumProvider: { dispose: () => void } | undefined; let editors: Monaco.editor.IStandaloneCodeEditor[] = []; let tailwindcssConfig: any; -let vueRegistered = false; -let shikiThemes: Record = {}; export const createEditor = async (options: EditorOptions): Promise => { const { container, - baseUrl, readonly, theme, editorTheme, @@ -64,8 +63,6 @@ export const createEditor = async (options: EditorOptions): Promise const loadMonaco = () => import(monacoBaseUrl + 'monaco.js'); let editorMode: any | undefined; - let currentTheme = theme; - let currentEditorTheme = editorTheme; const convertOptions = (opt: EditorConfig): Options => ({ fontFamily: getFontFamily(opt.fontFamily), @@ -82,17 +79,6 @@ export const createEditor = async (options: EditorOptions): Promise const baseOptions = convertOptions(options); - const monacoMapLanguage = (language: Language): Language => - language === 'livescript' - ? 'coffeescript' - : ['rescript', 'reason', 'ocaml'].includes(language) - ? 'csharp' - : language.startsWith('vue') - ? 'vue' - : ['svelte', 'malina', 'riot'].includes(language) - ? ('razor' as Language) // avoid mixing code between markup & script editors when formatting - : mapLanguage(language); - try { (window as any).monaco = (window as any).monaco || (await loadMonaco()).monaco; monaco = (window as any).monaco; @@ -134,9 +120,7 @@ export const createEditor = async (options: EditorOptions): Promise const setTheme = (theme: Theme, editorTheme: Config['editorTheme']) => { loadTheme(theme, editorTheme).then((newTheme) => { - monaco.editor.setTheme(shikiThemes[newTheme] ?? newTheme); - currentTheme = theme; - currentEditorTheme = editorTheme; + monaco.editor.setTheme(newTheme); }); }; @@ -219,7 +203,7 @@ export const createEditor = async (options: EditorOptions): Promise const isJSLang = JSLangs.includes(language); if ( !['script', 'tests', 'editorSettings'].includes(editorId) || - !['javascript', 'typescript'].includes(monacoMapLanguage(language)) + !['javascript', 'typescript'].includes(mapLanguage(language, 'monaco')) ) { return; } @@ -249,53 +233,32 @@ export const createEditor = async (options: EditorOptions): Promise listeners.forEach((fn) => editor.getModel()?.onDidChangeContent(fn)); }; - const customLanguages: Partial> = { - astro: baseUrl + '{{hash:monaco-lang-astro.js}}', - clio: baseUrl + '{{hash:monaco-lang-clio.js}}', - imba: baseUrl + '{{hash:monaco-lang-imba.js}}', - minizinc: baseUrl + '{{hash:monaco-lang-minizinc.js}}', - prolog: baseUrl + '{{hash:monaco-lang-prolog.js}}', - // sql: baseUrl + '{{hash:monaco-lang-sql.js}}', // TODO: add autocomplete - wat: baseUrl + '{{hash:monaco-lang-wat.js}}', + const loadMonacoLanguage = async (lang: Language) => { + const langSupport = getLanguageSpecs(lang)?.editorSupport?.monaco?.languageSupport; + if (langSupport && !loadedLanguages.has(lang)) { + loadedLanguages.add(lang); + const loadLanguage = + typeof langSupport === 'string' + ? (await import(langSupport)).default + : typeof langSupport === 'function' + ? langSupport + : () => undefined; + await loadLanguage(monaco); + } }; - interface CustomLanguageDefinition { - config?: Monaco.languages.LanguageConfiguration; - tokens?: Monaco.languages.IMonarchLanguage; - completions?: Monaco.languages.CompletionItemProvider; - } - - const addVueSupport = async () => { - if (vueRegistered) return; - vueRegistered = true; - const { registerVue, registerHighlighter } = await import(monacoVolarUrl); - const tsCompilerOptions = { ...getCompilerOptions('vue'), jsx: 'preserve' }; - await registerVue({ editor, monaco, tsCompilerOptions, silent: true }); - shikiThemes = registerHighlighter(monaco); - shikiThemes['custom-vs-light'] = shikiThemes.vs; - shikiThemes['custom-vs-dark'] = shikiThemes['vs-dark']; - setTheme(currentTheme, currentEditorTheme); - }; + await loadMonacoLanguage(language); - const loadMonacoLanguage = async (lang: Language) => { - if (monacoMapLanguage(lang) === 'vue') { - await addVueSupport(); - return; - } - const langUrl = customLanguages[lang]; - if (langUrl && !monaco.languages.getLanguages().find((l) => l.id === lang)) { - const mod: CustomLanguageDefinition = (await import(langUrl)).default; - monaco.languages.register({ id: lang }); - if (mod.config) { - monaco.languages.setLanguageConfiguration(lang, mod.config); - } - if (mod.tokens) { - monaco.languages.setMonarchTokensProvider(lang, mod.tokens); - } - if (mod.completions) { - monaco.languages.registerCompletionItemProvider(lang, mod.completions); + const getOrCreateModel = (value: string, lang: string | undefined, uri: Monaco.Uri) => { + const model = monaco.editor.getModel(uri); + if (model) { + if (model.getLanguageId() === mapLanguage(lang as Language, 'monaco')) { + model.setValue(value); + return model; } + model.dispose(); } + return monaco.editor.createModel(value, lang, uri); }; let modelUri = ''; @@ -307,14 +270,18 @@ export const createEditor = async (options: EditorOptions): Promise const random = getRandomString(); const ext = getLanguageExtension(language); const extension = - monacoMapLanguage(language) === 'typescript' && !ext?.endsWith('ts') && !ext?.endsWith('tsx') + mapLanguage(language, 'monaco') === 'typescript' && + !ext?.endsWith('ts') && + !ext?.endsWith('tsx') ? ext + '.tsx' : ext; - modelUri = `file:///${editorId}.${random}.${extension}`; + modelUri = editorId.includes('.') + ? `file:///${editorId}` + : `file:///${editorId}.${random}.${extension}`; const oldModel = editor.getModel(); - const model = monaco.editor.createModel( + const model = getOrCreateModel( value || '', - monacoMapLanguage(language), + mapLanguage(language, 'monaco'), monaco.Uri.parse(modelUri), ); editor.setModel(model); @@ -325,29 +292,11 @@ export const createEditor = async (options: EditorOptions): Promise const editor = monaco.editor.create(container, { ...editorOptions, - language: language.startsWith('vue') ? 'html' : monacoMapLanguage(language), + language: mapLanguage(language, 'monaco'), }); - setModel(editor, options.value, language.startsWith('vue') ? 'html' : language); - loadMonacoLanguage(language); - - // avoid a race condition that prevents loading vue worker - if (language.startsWith('vue')) { - setTimeout(() => { - setLanguage(language); - }, 50); - } + setModel(editor, options.value, mapLanguage(language, 'monaco')); - const getOrCreateModel = (value: string, lang: string | undefined, uri: Monaco.Uri) => { - const model = monaco.editor.getModel(uri); - if (model) { - model.setValue(value); - return model; - } - return monaco.editor.createModel(value, lang, uri); - }; - - const contentEditors: Array = ['markup', 'style', 'script', 'tests']; - if (contentEditors.includes(editorId)) { + if (editorId.includes('.')) { editors.push(editor); } @@ -452,19 +401,12 @@ export const createEditor = async (options: EditorOptions): Promise const getLanguage = () => language; const setLanguage = (lang: Language, value?: string) => { + if (!lang) return; language = lang; clearTypes(false); const valueToInsert = value ?? editor.getValue(); - if (monacoMapLanguage(lang) === 'vue') { - // avoid race condition of value changing while valor is loading - setValue(valueToInsert); - } else { - setModel(editor, valueToInsert, language); - } loadMonacoLanguage(lang).then(() => { - if (monacoMapLanguage(lang) === 'vue') { - setModel(editor, editor.getValue(), language); - } + setModel(editor, valueToInsert, language); }); }; @@ -556,25 +498,15 @@ export const createEditor = async (options: EditorOptions): Promise configureEditorMode(options.editorMode); const registerFormatter = (formatFn: FormatFn | undefined) => { - let editorModel = editor.getModel(); - if (!formatFn || !editorModel) return; - - monaco.languages.registerDocumentFormattingEditProvider(monacoMapLanguage(language), { - provideDocumentFormattingEdits: async () => { - let currentEditor = editor; - // avoid referring to editors destroyed after closing modals - if (!editor.getModel()) { - currentEditor = - editors.find((ed) => ed.getModel()?.getLanguageId() === monacoMapLanguage(language)) || - editor; - } - editorModel = currentEditor.getModel(); - if (!editorModel) return []; - const val = currentEditor.getValue() || ''; + if (!formatFn) return; + monaco.languages.registerDocumentFormattingEditProvider(mapLanguage(language, 'monaco'), { + provideDocumentFormattingEdits: async (model) => { + if (!model || model.isDisposed()) return []; + const val = model.getValue() || ''; const prettyVal = await formatFn(val, 0, getFormatterConfig()); return [ { - range: editorModel.getFullModelRange(), + range: model.getFullModelRange(), text: prettyVal.formatted, }, ]; @@ -744,8 +676,8 @@ export const createEditor = async (options: EditorOptions): Promise const model = editor.getModel(); if ( !model || - !addCloseLanguages.includes(monacoMapLanguage(language)) || - (monacoMapLanguage(language) === 'typescript' && !hasJsx.includes(language)) || // avoid autocompleting TS generics + !addCloseLanguages.includes(mapLanguage(language, 'monaco')) || + (mapLanguage(language, 'monaco') === 'typescript' && !hasJsx.includes(language)) || // avoid autocompleting TS generics editorOptions.autoClosingBrackets === 'never' ) { return; @@ -899,8 +831,69 @@ export const createEditor = async (options: EditorOptions): Promise monaco.languages.registerHoverProvider('html', npmPackageHoverProvider); }; + const enableGoToDefinition = () => { + // https://github.com/microsoft/vscode/pull/177064 + monaco.editor.registerEditorOpener({ + async openCodeEditor(_source, resource, selectionOrPosition) { + const lineNumber = !selectionOrPosition + ? null + : 'lineNumber' in selectionOrPosition + ? selectionOrPosition.lineNumber + : selectionOrPosition.startLineNumber; + + if (resource.path.startsWith('/lib.')) { + const lib = resource.path.replace('/lib.', ''); + window.open( + `https://app.unpkg.com/typescript@${typescriptVersion}/files/lib/lib.${lib}${lineNumber ? '#L' + lineNumber : ''}`, + '_blank', + ); + return true; + } + + if (resource.path.startsWith('/node_modules/')) { + const [part1, part2, ...rest] = resource.path.replace('/node_modules/', '').split('/'); + const lib = part1.startsWith('@') ? `${part1}/${part2}` : part1; + const path = part1.startsWith('@') ? rest.join('/') : `${part2}/${rest.join('/')}`; + window.open( + `https://app.unpkg.com/${lib}/files/${path}${lineNumber ? '#L' + lineNumber : ''}`, + '_blank', + ); + return true; + } + + const targetEditor = editors.find((e) => e.getModel()?.uri.path === resource.path); + if (targetEditor) { + const targetEditorId = resource.path.slice(1); // remove leading slash + + if (targetEditorId) { + // const targetEditorTab = getEditorTab(targetEditorId); + // targetEditorTab?.click(); + + if (monaco.Range.isIRange(selectionOrPosition)) { + targetEditor?.revealRangeInCenterIfOutsideViewport( + selectionOrPosition, + monaco.editor.ScrollType.Smooth, + ); + targetEditor?.setSelection(selectionOrPosition); + } else if (selectionOrPosition) { + targetEditor?.revealPositionInCenterIfOutsideViewport( + selectionOrPosition, + monaco.editor.ScrollType.Smooth, + ); + targetEditor?.setPosition(selectionOrPosition); + } + return true; + } + } + + return false; + }, + }); + }; + if (!monacoGloballyLoaded) { registerShowPackageInfo(); + enableGoToDefinition(); } monacoGloballyLoaded = true; diff --git a/src/livecodes/languages/python/lang-python.ts b/src/livecodes/languages/python/lang-python.ts index 7d66c78c73..110d013785 100644 --- a/src/livecodes/languages/python/lang-python.ts +++ b/src/livecodes/languages/python/lang-python.ts @@ -1,6 +1,6 @@ import type { LanguageSpecs } from '../../models'; import { getLanguageCustomSettings } from '../../utils/utils'; -import { brythonBaseUrl } from '../../vendors'; +import { brythonBaseUrl, codeMirrorBaseUrl, monacoLanguagesBaseUrl } from '../../vendors'; const brythonUrl = brythonBaseUrl + 'brython.min.js'; const stdlibUrl = brythonBaseUrl + 'brython_stdlib.js'; @@ -21,4 +21,11 @@ export const python: LanguageSpecs = { }, extensions: ['py'], editor: 'script', + editorSupport: { + monaco: { languageSupport: monacoLanguagesBaseUrl + 'python.js' }, + codemirror: { + languageSupport: async () => + (await import(codeMirrorBaseUrl + 'codemirror-lang-python.js')).python(), + }, + }, }; diff --git a/src/livecodes/languages/utils.ts b/src/livecodes/languages/utils.ts index 903ca3aa17..39b1adeee8 100644 --- a/src/livecodes/languages/utils.ts +++ b/src/livecodes/languages/utils.ts @@ -36,8 +36,14 @@ export const getLanguageCompiler = (alias: string = ''): Compiler | undefined => return compiler; }; -export const mapLanguage = (language: Language): Language => - getLanguageSpecs(language)?.editorLanguage || language; +export const mapLanguage = ( + language: Language, + editor?: Exclude, +): Language => + (editor ? getLanguageSpecs(language)?.editorSupport?.[editor]?.language : undefined) || + getLanguageSpecs(language)?.editorLanguage || + getLanguageByAlias(language) || + 'html'; export const languageIsEnabled = (language: Language, config: Config) => { const lang = getLanguageByAlias(language); diff --git a/src/livecodes/languages/vue/lang-vue.ts b/src/livecodes/languages/vue/lang-vue.ts index aca5efd655..6b027706aa 100644 --- a/src/livecodes/languages/vue/lang-vue.ts +++ b/src/livecodes/languages/vue/lang-vue.ts @@ -1,5 +1,11 @@ import type { LanguageSpecs } from '../../models'; -import { vendorsBaseUrl, vueRuntimeUrl, vueSDKUrl } from '../../vendors'; +import { + codeMirrorBaseUrl, + monacoLanguagesBaseUrl, + vendorsBaseUrl, + vueRuntimeUrl, + vueSDKUrl, +} from '../../vendors'; import { parserPlugins } from '../prettier'; const compilerUrl = vendorsBaseUrl + 'vue-compiler-sfc/vue-compiler-sfc.js'; @@ -25,7 +31,18 @@ export const vue: LanguageSpecs = { }, extensions: ['vue', 'vue3'], editor: 'script', - editorLanguage: 'html', + editorSupport: { + monaco: { + languageSupport: monacoLanguagesBaseUrl + 'vue.js', + }, + codemirror: { + languageSupport: async () => + (await import(codeMirrorBaseUrl + 'codemirror-lang-vue.js')).vue(), + }, + codejar: { + language: 'html', + }, + }, }; export const vueApp: LanguageSpecs = { @@ -34,5 +51,5 @@ export const vueApp: LanguageSpecs = { compiler: 'vue', extensions: ['app.vue'], editor: 'markup', - editorLanguage: 'html', + editorSupport: { ...vue.editorSupport, monaco: { language: 'vue' } }, }; diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 844ed86c29..e48b0713d1 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -306,6 +306,10 @@ export const monacoBaseUrl = /* @__PURE__ */ getUrl('@live-codes/monaco-editor@0 export const monacoEmacsUrl = /* @__PURE__ */ getUrl('monaco-emacs@0.3.0/dist/monaco-emacs.js'); +export const monacoLanguagesBaseUrl = /* @__PURE__ */ getUrl( + '@live-codes/monaco-languages@0.2.0/dist/', +); + export const monacoThemesBaseUrl = /* @__PURE__ */ getUrl('monaco-themes@0.4.4/themes/'); export const monacoVimUrl = /* @__PURE__ */ getUrl('monaco-vim@0.4.1/dist/monaco-vim.js'); @@ -448,7 +452,8 @@ export const tesseractUrl = /* @__PURE__ */ getUrl('tesseract.js@6.0.1/dist/tess export const twigUrl = /* @__PURE__ */ getUrl('twig@1.17.1/twig.min.js'); -export const typescriptUrl = /* @__PURE__ */ getUrl(`typescript@5.9.3/lib/typescript.js`); +export const typescriptVersion = '5.9.3'; +export const typescriptUrl = getUrl(`typescript@${typescriptVersion}/lib/typescript.js`); export const uniterUrl = /* @__PURE__ */ getUrl('uniter@2.18.0/dist/uniter.js'); diff --git a/src/sdk/models.ts b/src/sdk/models.ts index 7195f0f6dd..d2c789227f 100644 --- a/src/sdk/models.ts +++ b/src/sdk/models.ts @@ -1188,6 +1188,26 @@ export interface EditorLanguages { script: Language; } +export type LanguageEditorSupport = { + monaco?: { + language?: Language; + languageSupport?: + | string + | (( + monaco: any, + ) => void | Promise | { dispose: () => void } | Promise<{ dispose: () => void }>); + }; + codemirror?: { + language?: Language; + languageSupport?: string | (() => void | Promise); + }; + codejar?: { + language?: Language; + }; +} & { + compilerOptions?: Record; +}; + export interface Types { [key: string]: | string @@ -1210,6 +1230,7 @@ export interface LanguageSpecs { extensions: Language[]; editor: EditorId; editorLanguage?: Language; + editorSupport?: LanguageEditorSupport; preset?: CssPresetId; largeDownload?: boolean; } @@ -1619,7 +1640,10 @@ export interface EditorOptions extends EditorConfig { isLite: boolean; isHeadless: boolean; getLanguageExtension: (alias: string) => Language | undefined; - mapLanguage: (language: Language) => Language; + mapLanguage: ( + language: Language, + editor?: Exclude, + ) => Language; getFormatterConfig: () => Partial; getFontFamily: (font: string | undefined) => string; } From 25d6cfda143be2f8842d3705043c000df0ebb784 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Thu, 26 Feb 2026 15:07:51 +0200 Subject: [PATCH 2/9] add cpp & lua language support --- src/livecodes/editor/codemirror/editor-languages.ts | 4 ---- src/livecodes/editor/codemirror/utils.ts | 6 ++++++ src/livecodes/languages/cpp/lang-cpp.ts | 9 ++++++++- src/livecodes/languages/lua/lang-lua.ts | 12 +++++++++++- src/livecodes/languages/vue/lang-vue.ts | 2 +- 5 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 src/livecodes/editor/codemirror/utils.ts diff --git a/src/livecodes/editor/codemirror/editor-languages.ts b/src/livecodes/editor/codemirror/editor-languages.ts index b8189d79dd..ef059ab5ec 100644 --- a/src/livecodes/editor/codemirror/editor-languages.ts +++ b/src/livecodes/editor/codemirror/editor-languages.ts @@ -28,7 +28,6 @@ const moduleUrls = { java: getPath('codemirror-lang-java.js'), clike: getPath('codemirror-lang-clike.js'), mllike: getPath('codemirror-lang-mllike.js'), - cpp: getPath('codemirror-lang-cpp.js'), sql: getPath('codemirror-lang-sql.js'), wast: getPath('codemirror-lang-wast.js'), scss: getPath('codemirror-lang-scss.js'), @@ -39,7 +38,6 @@ const moduleUrls = { ruby: getPath('codemirror-lang-ruby.js'), go: getPath('codemirror-lang-go.js'), perl: getPath('codemirror-lang-perl.js'), - lua: getPath('codemirror-lang-lua.js'), r: getPath('codemirror-lang-r.js'), julia: getPath('codemirror-lang-julia.js'), scheme: getPath('codemirror-lang-scheme.js'), @@ -65,7 +63,6 @@ export const editorLanguages: Partial<{ [key in Language]: () => Promise (await import(moduleUrls.php)).php(), go: async () => (await import(moduleUrls.go)).go(), java: async () => (await import(moduleUrls.java)).java(), - cpp: async () => (await import(moduleUrls.cpp)).cpp(), sql: async () => (await import(moduleUrls.sql)).sql(), wat: async () => (await import(moduleUrls.wast)).wast(), scss: async () => (await import(moduleUrls.scss)).sass(), @@ -76,7 +73,6 @@ export const editorLanguages: Partial<{ [key in Language]: () => Promise legacy((await import(moduleUrls.livescript)).liveScript), ruby: async () => legacy((await import(moduleUrls.ruby)).ruby), perl: async () => legacy((await import(moduleUrls.perl)).perl), - lua: async () => legacy((await import(moduleUrls.lua)).lua), r: async () => legacy((await import(moduleUrls.r)).r), julia: async () => legacy((await import(moduleUrls.julia)).julia), scheme: async () => legacy((await import(moduleUrls.scheme)).scheme), diff --git a/src/livecodes/editor/codemirror/utils.ts b/src/livecodes/editor/codemirror/utils.ts new file mode 100644 index 0000000000..6cf830ba3f --- /dev/null +++ b/src/livecodes/editor/codemirror/utils.ts @@ -0,0 +1,6 @@ +export const codemirrorLegacy = async (parser: any) => { + // @ts-ignore + // eslint-disable-next-line import/no-unresolved + const { LanguageSupport, StreamLanguage } = await import('@codemirror/language'); + return new LanguageSupport(StreamLanguage.define(parser)); +}; diff --git a/src/livecodes/languages/cpp/lang-cpp.ts b/src/livecodes/languages/cpp/lang-cpp.ts index 725dabdfff..4e55562b23 100644 --- a/src/livecodes/languages/cpp/lang-cpp.ts +++ b/src/livecodes/languages/cpp/lang-cpp.ts @@ -1,5 +1,5 @@ import type { LanguageSpecs } from '../../models'; -import { vendorsBaseUrl } from '../../vendors'; +import { codeMirrorBaseUrl, monacoLanguagesBaseUrl, vendorsBaseUrl } from '../../vendors'; export const cdnUrl = vendorsBaseUrl + 'jscpp/JSCPP.es5.min.js'; @@ -14,4 +14,11 @@ export const cpp: LanguageSpecs = { }, extensions: ['cpp', 'c', 'C', 'cp', 'cxx', 'c++', 'cppm', 'ixx', 'ii', 'hpp', 'h'], editor: 'script', + editorSupport: { + monaco: { languageSupport: monacoLanguagesBaseUrl + 'cpp.js' }, + codemirror: { + languageSupport: async () => + (await import(codeMirrorBaseUrl + 'codemirror-lang-cpp.js')).cpp(), + }, + }, }; diff --git a/src/livecodes/languages/lua/lang-lua.ts b/src/livecodes/languages/lua/lang-lua.ts index 73789c52fe..91f9336b30 100644 --- a/src/livecodes/languages/lua/lang-lua.ts +++ b/src/livecodes/languages/lua/lang-lua.ts @@ -1,5 +1,6 @@ +import { codemirrorLegacy } from '../../editor/codemirror/utils'; import type { LanguageFormatter, LanguageSpecs } from '../../models'; -import { luaUrl, vendorsBaseUrl } from '../../vendors'; +import { codeMirrorBaseUrl, luaUrl, monacoLanguagesBaseUrl, vendorsBaseUrl } from '../../vendors'; const luaFmtUrl = vendorsBaseUrl + 'lua-fmt/lua-fmt.js'; @@ -25,4 +26,13 @@ export const lua: LanguageSpecs = { }, extensions: ['lua'], editor: 'script', + editorSupport: { + monaco: { + languageSupport: monacoLanguagesBaseUrl + 'lua.js', + }, + codemirror: { + languageSupport: async () => + codemirrorLegacy((await import(codeMirrorBaseUrl + 'codemirror-lang-lua.js')).lua), + }, + }, }; diff --git a/src/livecodes/languages/vue/lang-vue.ts b/src/livecodes/languages/vue/lang-vue.ts index 6b027706aa..dae6b8d3fc 100644 --- a/src/livecodes/languages/vue/lang-vue.ts +++ b/src/livecodes/languages/vue/lang-vue.ts @@ -51,5 +51,5 @@ export const vueApp: LanguageSpecs = { compiler: 'vue', extensions: ['app.vue'], editor: 'markup', - editorSupport: { ...vue.editorSupport, monaco: { language: 'vue' } }, + editorSupport: { ...vue.editorSupport, monaco: { language: 'vue' } }, // avoid duplicate registration }; From eceaa87d7efbdd91bb5fb379b774762298650506 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Thu, 26 Feb 2026 22:20:32 +0200 Subject: [PATCH 3/9] fix monaco overlays --- src/livecodes/styles/app.scss | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/livecodes/styles/app.scss b/src/livecodes/styles/app.scss index 5d5bd5c654..3325fa20b7 100644 --- a/src/livecodes/styles/app.scss +++ b/src/livecodes/styles/app.scss @@ -2211,10 +2211,6 @@ body { z-index: 49; // keep under monaco hover menu } - #toolbar { - z-index: 500; - } - .copy-button { z-index: 900; } From 16a9e0275c35c775aee80823ddc93929d169522e Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Fri, 27 Feb 2026 00:40:23 +0200 Subject: [PATCH 4/9] monaco languages --- .../editor/codemirror/editor-languages.ts | 18 ------------------ src/livecodes/editor/monaco/monaco.ts | 2 +- .../languages/commonlisp/lang-commonlisp.ts | 8 ++++++-- .../languages/csharp-wasm/lang-csharp-wasm.ts | 9 +++++++++ src/livecodes/languages/go/lang-go.ts | 8 +++++++- src/livecodes/languages/java/lang-java.ts | 8 ++++++++ src/livecodes/languages/php/lang-php.ts | 9 ++++++++- src/livecodes/languages/r/lang-r.ts | 9 +++++++++ src/livecodes/languages/ruby/lang-ruby.ts | 10 +++++++++- src/livecodes/languages/scheme/lang-scheme.ts | 10 +++++++++- src/livecodes/languages/sql/lang-sql.ts | 14 +++++++++++++- src/livecodes/languages/svelte/lang-svelte.ts | 13 +++++++++++-- src/livecodes/languages/vue/lang-vue.ts | 8 ++------ 13 files changed, 92 insertions(+), 34 deletions(-) diff --git a/src/livecodes/editor/codemirror/editor-languages.ts b/src/livecodes/editor/codemirror/editor-languages.ts index ef059ab5ec..884e51a384 100644 --- a/src/livecodes/editor/codemirror/editor-languages.ts +++ b/src/livecodes/editor/codemirror/editor-languages.ts @@ -20,27 +20,18 @@ const legacy = (parser: StreamParser) => const getPath = (mod: string) => codeMirrorBaseUrl + mod; const moduleUrls = { - svelte: getPath('codemirror-lang-svelte.js'), liquid: getPath('codemirror-lang-liquid.js'), json: getPath('codemirror-lang-json.js'), markdown: getPath('codemirror-lang-markdown.js'), - php: getPath('codemirror-lang-php.js'), - java: getPath('codemirror-lang-java.js'), - clike: getPath('codemirror-lang-clike.js'), mllike: getPath('codemirror-lang-mllike.js'), - sql: getPath('codemirror-lang-sql.js'), wast: getPath('codemirror-lang-wast.js'), scss: getPath('codemirror-lang-scss.js'), minizinc: getPath('codemirror-lang-minizinc.js'), prolog: getPath('codemirror-lang-prolog.js'), coffeescript: getPath('codemirror-lang-coffeescript.js'), livescript: getPath('codemirror-lang-livescript.js'), - ruby: getPath('codemirror-lang-ruby.js'), - go: getPath('codemirror-lang-go.js'), perl: getPath('codemirror-lang-perl.js'), - r: getPath('codemirror-lang-r.js'), julia: getPath('codemirror-lang-julia.js'), - scheme: getPath('codemirror-lang-scheme.js'), clojure: getPath('codemirror-lang-clojure.js'), tcl: getPath('codemirror-lang-tcl.js'), less: getPath('codemirror-lang-less.js'), @@ -57,13 +48,8 @@ export const editorLanguages: Partial<{ [key in Language]: () => Promise javascript({ jsx: true }), tsx: async () => javascript({ jsx: true, typescript: true }), json: async () => json(), - svelte: async () => (await import(moduleUrls.svelte)).svelte(), liquid: async () => (await import(moduleUrls.liquid)).liquid(), markdown: async () => (await import(moduleUrls.markdown)).markdown(), - php: async () => (await import(moduleUrls.php)).php(), - go: async () => (await import(moduleUrls.go)).go(), - java: async () => (await import(moduleUrls.java)).java(), - sql: async () => (await import(moduleUrls.sql)).sql(), wat: async () => (await import(moduleUrls.wast)).wast(), scss: async () => (await import(moduleUrls.scss)).sass(), sass: async () => (await import(moduleUrls.scss)).sass({ indented: true }), @@ -71,16 +57,12 @@ export const editorLanguages: Partial<{ [key in Language]: () => Promise (await import(moduleUrls.prolog)).prolog(), coffeescript: async () => legacy((await import(moduleUrls.coffeescript)).coffeeScript), livescript: async () => legacy((await import(moduleUrls.livescript)).liveScript), - ruby: async () => legacy((await import(moduleUrls.ruby)).ruby), perl: async () => legacy((await import(moduleUrls.perl)).perl), - r: async () => legacy((await import(moduleUrls.r)).r), julia: async () => legacy((await import(moduleUrls.julia)).julia), - scheme: async () => legacy((await import(moduleUrls.scheme)).scheme), clojure: async () => legacy((await import(moduleUrls.clojure)).clojure), tcl: async () => legacy((await import(moduleUrls.tcl)).tcl), less: async () => legacy((await import(moduleUrls.less)).less), stylus: async () => legacy((await import(moduleUrls.stylus)).stylus), - csharp: async () => legacy((await import(moduleUrls.clike)).csharp), ocaml: async () => legacy((await import(moduleUrls.mllike)).oCaml), // fsharp: async () => legacy((await import(moduleUrls.mllike)).fSharp), // @ts-ignore diff --git a/src/livecodes/editor/monaco/monaco.ts b/src/livecodes/editor/monaco/monaco.ts index f0b7fcb83c..c6c4ee87e6 100644 --- a/src/livecodes/editor/monaco/monaco.ts +++ b/src/livecodes/editor/monaco/monaco.ts @@ -243,7 +243,7 @@ export const createEditor = async (options: EditorOptions): Promise : typeof langSupport === 'function' ? langSupport : () => undefined; - await loadLanguage(monaco); + await loadLanguage(monaco, () => editor); } }; diff --git a/src/livecodes/languages/commonlisp/lang-commonlisp.ts b/src/livecodes/languages/commonlisp/lang-commonlisp.ts index eb033cc31f..c348a637a0 100644 --- a/src/livecodes/languages/commonlisp/lang-commonlisp.ts +++ b/src/livecodes/languages/commonlisp/lang-commonlisp.ts @@ -1,5 +1,5 @@ import type { LanguageSpecs } from '../../models'; -import { jsclUrl, parinferUrl } from '../../vendors'; +import { jsclUrl, monacoLanguagesBaseUrl, parinferUrl } from '../../vendors'; export const parenFormatter = () => { const url = parinferUrl; @@ -25,5 +25,9 @@ export const commonlisp: LanguageSpecs = { }, extensions: ['lisp', 'common-lisp'], editor: 'script', - editorLanguage: 'scheme', + editorSupport: { + monaco: { languageSupport: monacoLanguagesBaseUrl + 'commonlisp.js' }, + codemirror: { language: 'scheme' }, + codejar: { language: 'scheme' }, + }, }; diff --git a/src/livecodes/languages/csharp-wasm/lang-csharp-wasm.ts b/src/livecodes/languages/csharp-wasm/lang-csharp-wasm.ts index 77049be033..320531a7b6 100644 --- a/src/livecodes/languages/csharp-wasm/lang-csharp-wasm.ts +++ b/src/livecodes/languages/csharp-wasm/lang-csharp-wasm.ts @@ -1,4 +1,6 @@ +import { codemirrorLegacy } from '../../editor/codemirror/utils'; import type { LanguageSpecs } from '../../models'; +import { codeMirrorBaseUrl, monacoLanguagesBaseUrl } from '../../vendors'; import { parserPlugins } from '../prettier'; export const csharpWasm: LanguageSpecs = { @@ -18,5 +20,12 @@ export const csharpWasm: LanguageSpecs = { extensions: ['cs', 'csharp', 'wasm.cs', 'cs-wasm'], editor: 'script', editorLanguage: 'csharp', + editorSupport: { + monaco: { languageSupport: monacoLanguagesBaseUrl + 'csharp.js' }, + codemirror: { + languageSupport: async () => + codemirrorLegacy((await import(codeMirrorBaseUrl + 'codemirror-lang-clike.js')).csharp), + }, + }, largeDownload: true, }; diff --git a/src/livecodes/languages/go/lang-go.ts b/src/livecodes/languages/go/lang-go.ts index ffb9f63515..1eee686d1d 100644 --- a/src/livecodes/languages/go/lang-go.ts +++ b/src/livecodes/languages/go/lang-go.ts @@ -1,5 +1,5 @@ import type { LanguageSpecs } from '../../models'; -import { go2jsBaseUrl } from '../../vendors'; +import { codeMirrorBaseUrl, go2jsBaseUrl, monacoLanguagesBaseUrl } from '../../vendors'; declare const importScripts: (...args: string[]) => void; @@ -46,4 +46,10 @@ export const go: LanguageSpecs = { }, extensions: ['go', 'golang'], editor: 'script', + editorSupport: { + monaco: { languageSupport: monacoLanguagesBaseUrl + 'go.js' }, + codemirror: { + languageSupport: async () => (await import(codeMirrorBaseUrl + 'codemirror-lang-go.js')).go(), + }, + }, }; diff --git a/src/livecodes/languages/java/lang-java.ts b/src/livecodes/languages/java/lang-java.ts index 3d1e03723d..911d5fc12f 100644 --- a/src/livecodes/languages/java/lang-java.ts +++ b/src/livecodes/languages/java/lang-java.ts @@ -1,4 +1,5 @@ import type { LanguageSpecs } from '../../models'; +import { codeMirrorBaseUrl, monacoLanguagesBaseUrl } from '../../vendors'; import { parserPlugins } from '../prettier'; export const java: LanguageSpecs = { @@ -17,5 +18,12 @@ export const java: LanguageSpecs = { }, extensions: ['java'], editor: 'script', + editorSupport: { + monaco: { languageSupport: monacoLanguagesBaseUrl + 'java.js' }, + codemirror: { + languageSupport: async () => + (await import(codeMirrorBaseUrl + 'codemirror-lang-java.js')).java(), + }, + }, largeDownload: true, }; diff --git a/src/livecodes/languages/php/lang-php.ts b/src/livecodes/languages/php/lang-php.ts index 6b1a36b6d0..4446d99a77 100644 --- a/src/livecodes/languages/php/lang-php.ts +++ b/src/livecodes/languages/php/lang-php.ts @@ -1,5 +1,5 @@ import type { LanguageSpecs } from '../../models'; -import { uniterUrl } from '../../vendors'; +import { codeMirrorBaseUrl, monacoLanguagesBaseUrl, uniterUrl } from '../../vendors'; import { parserPlugins } from '../prettier'; export const php: LanguageSpecs = { @@ -27,4 +27,11 @@ export const php: LanguageSpecs = { }, extensions: ['php'], editor: 'script', + editorSupport: { + monaco: { languageSupport: monacoLanguagesBaseUrl + 'php.js' }, + codemirror: { + languageSupport: async () => + (await import(codeMirrorBaseUrl + 'codemirror-lang-php.js')).php(), + }, + }, }; diff --git a/src/livecodes/languages/r/lang-r.ts b/src/livecodes/languages/r/lang-r.ts index c36df5574a..03dab7ba55 100644 --- a/src/livecodes/languages/r/lang-r.ts +++ b/src/livecodes/languages/r/lang-r.ts @@ -1,4 +1,6 @@ +import { codemirrorLegacy } from '../../editor/codemirror/utils'; import type { LanguageSpecs } from '../../models'; +import { codeMirrorBaseUrl, monacoLanguagesBaseUrl } from '../../vendors'; export const r: LanguageSpecs = { name: 'r', @@ -26,5 +28,12 @@ export const r: LanguageSpecs = { }, extensions: ['r', 'rlang', 'rstats', 'r-wasm'], editor: 'script', + editorSupport: { + monaco: { languageSupport: monacoLanguagesBaseUrl + 'r.js' }, + codemirror: { + languageSupport: async () => + codemirrorLegacy((await import(codeMirrorBaseUrl + 'codemirror-lang-r.js')).r), + }, + }, largeDownload: true, }; diff --git a/src/livecodes/languages/ruby/lang-ruby.ts b/src/livecodes/languages/ruby/lang-ruby.ts index 888622cca7..6da7830bd7 100644 --- a/src/livecodes/languages/ruby/lang-ruby.ts +++ b/src/livecodes/languages/ruby/lang-ruby.ts @@ -1,6 +1,7 @@ +import { codemirrorLegacy } from '../../editor/codemirror/utils'; import type { LanguageSpecs } from '../../models'; import { getLanguageCustomSettings } from '../../utils'; -import { opalBaseUrl } from '../../vendors'; +import { codeMirrorBaseUrl, monacoLanguagesBaseUrl, opalBaseUrl } from '../../vendors'; declare const importScripts: (...args: string[]) => void; @@ -43,4 +44,11 @@ export const ruby: LanguageSpecs = { }, extensions: ['rb'], editor: 'script', + editorSupport: { + monaco: { languageSupport: monacoLanguagesBaseUrl + 'ruby.js' }, + codemirror: { + languageSupport: async () => + codemirrorLegacy((await import(codeMirrorBaseUrl + 'codemirror-lang-ruby.js')).ruby), + }, + }, }; diff --git a/src/livecodes/languages/scheme/lang-scheme.ts b/src/livecodes/languages/scheme/lang-scheme.ts index 5a167988de..4fc33a02a9 100644 --- a/src/livecodes/languages/scheme/lang-scheme.ts +++ b/src/livecodes/languages/scheme/lang-scheme.ts @@ -1,5 +1,6 @@ +import { codemirrorLegacy } from '../../editor/codemirror/utils'; import type { LanguageSpecs } from '../../models'; -import { biwaschemeUrl } from '../../vendors'; +import { biwaschemeUrl, codeMirrorBaseUrl, monacoLanguagesBaseUrl } from '../../vendors'; import { parenFormatter } from '../commonlisp'; export const scheme: LanguageSpecs = { @@ -16,4 +17,11 @@ export const scheme: LanguageSpecs = { }, extensions: ['scm'], editor: 'script', + editorSupport: { + monaco: { languageSupport: monacoLanguagesBaseUrl + 'scheme.js' }, + codemirror: { + languageSupport: async () => + codemirrorLegacy((await import(codeMirrorBaseUrl + 'codemirror-lang-scheme.js')).scheme), + }, + }, }; diff --git a/src/livecodes/languages/sql/lang-sql.ts b/src/livecodes/languages/sql/lang-sql.ts index d2444753cd..62c2446cba 100644 --- a/src/livecodes/languages/sql/lang-sql.ts +++ b/src/livecodes/languages/sql/lang-sql.ts @@ -1,5 +1,10 @@ import type { LanguageSpecs } from '../../models'; -import { sqlFormatterUrl, sqljsBaseUrl } from '../../vendors'; +import { + codeMirrorBaseUrl, + monacoLanguagesBaseUrl, + sqlFormatterUrl, + sqljsBaseUrl, +} from '../../vendors'; declare const importScripts: (...args: string[]) => void; @@ -29,4 +34,11 @@ export const sql: LanguageSpecs = { }, extensions: ['sql', 'sqlite', 'sqlite3'], editor: 'script', + editorSupport: { + monaco: { languageSupport: monacoLanguagesBaseUrl + 'sql.js' }, + codemirror: { + languageSupport: async () => + (await import(codeMirrorBaseUrl + 'codemirror-lang-sql.js')).sql(), + }, + }, }; diff --git a/src/livecodes/languages/svelte/lang-svelte.ts b/src/livecodes/languages/svelte/lang-svelte.ts index 9af5eb0a2e..08c8077929 100644 --- a/src/livecodes/languages/svelte/lang-svelte.ts +++ b/src/livecodes/languages/svelte/lang-svelte.ts @@ -1,7 +1,8 @@ import type { LanguageSpecs } from '../../models'; import { modulesService } from '../../services'; -import { svelteBaseUrl } from '../../vendors'; +import { codeMirrorBaseUrl, monacoLanguagesBaseUrl, svelteBaseUrl } from '../../vendors'; import { parserPlugins } from '../prettier'; +import { vue } from '../vue/lang-vue'; export const svelte: LanguageSpecs = { name: 'svelte', @@ -45,6 +46,14 @@ export const svelte: LanguageSpecs = { }, extensions: ['svelte'], editor: 'script', + editorSupport: { + monaco: { languageSupport: monacoLanguagesBaseUrl + 'svelte.js' }, + codemirror: { + languageSupport: async () => + (await import(codeMirrorBaseUrl + 'codemirror-lang-svelte.js')).svelte(), + }, + codejar: { language: 'html' }, + }, }; export const svelteApp: LanguageSpecs = { @@ -53,5 +62,5 @@ export const svelteApp: LanguageSpecs = { compiler: 'svelte', extensions: ['app.svelte'], editor: 'markup', - editorLanguage: 'html', + editorSupport: { ...vue.editorSupport, monaco: { language: 'svelte' } }, // avoid duplicate registration }; diff --git a/src/livecodes/languages/vue/lang-vue.ts b/src/livecodes/languages/vue/lang-vue.ts index dae6b8d3fc..50b2d9b36a 100644 --- a/src/livecodes/languages/vue/lang-vue.ts +++ b/src/livecodes/languages/vue/lang-vue.ts @@ -32,16 +32,12 @@ export const vue: LanguageSpecs = { extensions: ['vue', 'vue3'], editor: 'script', editorSupport: { - monaco: { - languageSupport: monacoLanguagesBaseUrl + 'vue.js', - }, + monaco: { languageSupport: monacoLanguagesBaseUrl + 'vue.js' }, codemirror: { languageSupport: async () => (await import(codeMirrorBaseUrl + 'codemirror-lang-vue.js')).vue(), }, - codejar: { - language: 'html', - }, + codejar: { language: 'html' }, }, }; From e806dbffb61a30f0f0ede16672813298dc6b705c Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Sat, 28 Feb 2026 00:59:20 +0200 Subject: [PATCH 5/9] convert all languages to use `editorSupport` --- scripts/build.js | 7 - .../editor/codemirror/editor-languages.ts | 62 +- .../monaco/languages/monaco-lang-astro.ts | 222 --- .../monaco/languages/monaco-lang-clio.ts | 120 -- .../monaco/languages/monaco-lang-imba.ts | 1522 ----------------- .../monaco/languages/monaco-lang-minizinc.ts | 381 ----- .../monaco/languages/monaco-lang-prolog.ts | 126 -- .../monaco/languages/monaco-lang-sql.ts | 1401 --------------- .../monaco/languages/monaco-lang-wat.ts | 710 -------- .../clojurescript/lang-clojurescript.ts | 9 +- .../coffeescript/lang-coffeescript.ts | 11 +- .../languages/csharp-wasm/lang-csharp-wasm.ts | 2 +- src/livecodes/languages/css/lang-css.ts | 10 + src/livecodes/languages/gleam/lang-gleam.ts | 13 +- src/livecodes/languages/html/lang-html.ts | 10 + .../languages/javascript/lang-javascript.ts | 10 + src/livecodes/languages/jsx/lang-jsx.ts | 10 + src/livecodes/languages/jsx/lang-tsx.ts | 10 + src/livecodes/languages/julia/lang-julia.ts | 8 + src/livecodes/languages/less/lang-less.ts | 9 +- src/livecodes/languages/liquid/lang-liquid.ts | 8 +- .../languages/livescript/lang-livescript.ts | 12 +- src/livecodes/languages/malina/lang-malina.ts | 1 + .../languages/markdown/lang-markdown.ts | 8 +- .../languages/minizinc/lang-minizinc.ts | 8 + src/livecodes/languages/ocaml/lang-ocaml.ts | 10 +- src/livecodes/languages/perl/lang-perl.ts | 9 +- src/livecodes/languages/prolog/lang-prolog.ts | 9 +- src/livecodes/languages/reason/lang-reason.ts | 1 + .../languages/rescript/lang-rescript.ts | 1 + src/livecodes/languages/riot/lang-riot.ts | 1 + src/livecodes/languages/scss/lang-sass.ts | 7 + src/livecodes/languages/scss/lang-scss.ts | 8 +- src/livecodes/languages/stylus/lang-stylus.ts | 9 +- src/livecodes/languages/tcl/lang-tcl.ts | 9 +- .../languages/typescript/lang-typescript.ts | 10 + src/livecodes/languages/wat/lang-wat.ts | 15 +- src/sdk/models.ts | 1 + 38 files changed, 214 insertions(+), 4566 deletions(-) delete mode 100644 src/livecodes/editor/monaco/languages/monaco-lang-astro.ts delete mode 100644 src/livecodes/editor/monaco/languages/monaco-lang-clio.ts delete mode 100644 src/livecodes/editor/monaco/languages/monaco-lang-imba.ts delete mode 100644 src/livecodes/editor/monaco/languages/monaco-lang-minizinc.ts delete mode 100644 src/livecodes/editor/monaco/languages/monaco-lang-prolog.ts delete mode 100644 src/livecodes/editor/monaco/languages/monaco-lang-sql.ts delete mode 100644 src/livecodes/editor/monaco/languages/monaco-lang-wat.ts diff --git a/scripts/build.js b/scripts/build.js index 90e5b6023f..d7bfa8b37c 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -157,13 +157,6 @@ const esmBuild = () => 'headless.ts', 'templates/starter/index.ts', 'editor/monaco/monaco.ts', - 'editor/monaco/languages/monaco-lang-astro.ts', - 'editor/monaco/languages/monaco-lang-clio.ts', - 'editor/monaco/languages/monaco-lang-imba.ts', - 'editor/monaco/languages/monaco-lang-minizinc.ts', - 'editor/monaco/languages/monaco-lang-prolog.ts', - // 'editor/monaco/languages/monaco-lang-sql.ts', - 'editor/monaco/languages/monaco-lang-wat.ts', 'editor/codemirror/codemirror.ts', 'editor/codejar/codejar.ts', 'editor/blockly/blockly.ts', diff --git a/src/livecodes/editor/codemirror/editor-languages.ts b/src/livecodes/editor/codemirror/editor-languages.ts index 884e51a384..b921ceb36b 100644 --- a/src/livecodes/editor/codemirror/editor-languages.ts +++ b/src/livecodes/editor/codemirror/editor-languages.ts @@ -1,71 +1,11 @@ /* eslint-disable import/no-unresolved */ - -// @ts-ignore -import { LanguageSupport, StreamLanguage, type StreamParser } from '@codemirror/language'; -// @ts-ignore -import { html } from '@codemirror/lang-html'; -// @ts-ignore -import { css } from '@codemirror/lang-css'; // @ts-ignore -import { javascript } from '@codemirror/lang-javascript'; +import type { LanguageSupport } from '@codemirror/language'; // @ts-ignore import { json } from '@codemirror/lang-json'; import type { Language } from '../../models'; -import { codeMirrorBaseUrl } from '../../vendors'; - -const legacy = (parser: StreamParser) => - new LanguageSupport(StreamLanguage.define(parser)); - -const getPath = (mod: string) => codeMirrorBaseUrl + mod; - -const moduleUrls = { - liquid: getPath('codemirror-lang-liquid.js'), - json: getPath('codemirror-lang-json.js'), - markdown: getPath('codemirror-lang-markdown.js'), - mllike: getPath('codemirror-lang-mllike.js'), - wast: getPath('codemirror-lang-wast.js'), - scss: getPath('codemirror-lang-scss.js'), - minizinc: getPath('codemirror-lang-minizinc.js'), - prolog: getPath('codemirror-lang-prolog.js'), - coffeescript: getPath('codemirror-lang-coffeescript.js'), - livescript: getPath('codemirror-lang-livescript.js'), - perl: getPath('codemirror-lang-perl.js'), - julia: getPath('codemirror-lang-julia.js'), - clojure: getPath('codemirror-lang-clojure.js'), - tcl: getPath('codemirror-lang-tcl.js'), - less: getPath('codemirror-lang-less.js'), - stylus: getPath('codemirror-lang-stylus.js'), - rust: getPath('codemirror-lang-rust.js'), - swift: getPath('codemirror-lang-swift.js'), -}; export const editorLanguages: Partial<{ [key in Language]: () => Promise }> = { - html: async () => html(), - css: async () => css(), - javascript: async () => javascript(), - typescript: async () => javascript({ typescript: true }), - jsx: async () => javascript({ jsx: true }), - tsx: async () => javascript({ jsx: true, typescript: true }), json: async () => json(), - liquid: async () => (await import(moduleUrls.liquid)).liquid(), - markdown: async () => (await import(moduleUrls.markdown)).markdown(), - wat: async () => (await import(moduleUrls.wast)).wast(), - scss: async () => (await import(moduleUrls.scss)).sass(), - sass: async () => (await import(moduleUrls.scss)).sass({ indented: true }), - minizinc: async () => (await import(moduleUrls.minizinc)).MiniZinc(), - prolog: async () => (await import(moduleUrls.prolog)).prolog(), - coffeescript: async () => legacy((await import(moduleUrls.coffeescript)).coffeeScript), - livescript: async () => legacy((await import(moduleUrls.livescript)).liveScript), - perl: async () => legacy((await import(moduleUrls.perl)).perl), - julia: async () => legacy((await import(moduleUrls.julia)).julia), - clojure: async () => legacy((await import(moduleUrls.clojure)).clojure), - tcl: async () => legacy((await import(moduleUrls.tcl)).tcl), - less: async () => legacy((await import(moduleUrls.less)).less), - stylus: async () => legacy((await import(moduleUrls.stylus)).stylus), - ocaml: async () => legacy((await import(moduleUrls.mllike)).oCaml), - // fsharp: async () => legacy((await import(moduleUrls.mllike)).fSharp), - // @ts-ignore - rust: async () => legacy((await import(moduleUrls.rust)).rust), - swift: async () => legacy((await import(moduleUrls.swift)).swift), }; diff --git a/src/livecodes/editor/monaco/languages/monaco-lang-astro.ts b/src/livecodes/editor/monaco/languages/monaco-lang-astro.ts deleted file mode 100644 index 5f15506a50..0000000000 --- a/src/livecodes/editor/monaco/languages/monaco-lang-astro.ts +++ /dev/null @@ -1,222 +0,0 @@ -export default { - config: { - comments: { - blockComment: [''], - }, - brackets: [ - ['---', '---'], - [''], - ['<', '>'], - ['{', '}'], - ['(', ')'], - ], - autoClosingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: "'", close: "'" }, - { open: '"', close: '"' }, - { open: '', notIn: ['comment', 'string'] }, - { open: '/**', close: ' */', notIn: ['string'] }, - { open: '<', close: '>', notIn: ['string'] }, - ], - autoCloseBefore: ';:.,=}])>` \n\t', - surroundingPairs: [ - { open: "'", close: "'" }, - { open: '"', close: '"' }, - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '<', close: '>' }, - ], - folding: { - markers: { - start: /^\\s*/, - end: /^\\s*/, - }, - }, - }, - - tokens: { - defaultToken: '', - tokenPostfix: '.astro', - ignoreCase: false, - - // non matched elements - empty: [ - 'area', - 'base', - 'basefont', - 'br', - 'col', - 'frame', - 'hr', - 'img', - 'input', - 'isindex', - 'link', - 'meta', - 'param', - ], - - // The main tokenizer for our languages - tokenizer: { - root: [ - [/)/, ['delimiter', 'tag', '', 'delimiter']], - [/(<)(script)/, ['delimiter', { token: 'tag', next: '@script' }]], - [/(<)(style)/, ['delimiter', { token: 'tag', next: '@style' }]], - [/(<)((?:[\w\-]+:)?[\w\-]+)/, ['delimiter', { token: 'tag', next: '@otherTag' }]], - [/(<\/)((?:[\w\-]+:)?[\w\-]+)/, ['delimiter', { token: 'tag', next: '@otherTag' }]], - [/]+/, 'metatag.content'], - [/>/, 'metatag', '@pop'], - ], - - frontmatter: [ - [/^---/, { token: 'comment', next: '@pop', nextEmbedded: '@pop' }], - [/./, { token: '@rematch', next: '@frontmatterEmbedded', nextEmbedded: 'text/javascript' }], - ], - - frontmatterEmbedded: [ - [/[^-]+|-[^-][^-]+/, { token: '@rematch', next: '@pop' }], - [/^---/, { token: 'comment', next: '@root', nextEmbedded: '@pop' }], - ], - - expression: [ - [ - /[^<{}]/, - { token: '@rematch', next: '@expressionEmbedded', nextEmbedded: 'text/javascript' }, - ], - [//, 'comment', '@pop'], - [/[^-]+/, 'comment.content'], - [/./, 'comment.content'], - ], - - otherTag: [ - [/\/?>/, 'delimiter', '@pop'], - [/"([^"]*)"/, 'attribute.value'], - [/'([^']*)'/, 'attribute.value'], - [/[\w\-]+/, 'attribute.name'], - [/=/, 'delimiter'], - [/[ \t\r\n]+/], // whitespace - ], - - // -- BEGIN