diff --git a/src/monaco/env.ts b/src/monaco/env.ts index a58d60ad..08415ff4 100644 --- a/src/monaco/env.ts +++ b/src/monaco/env.ts @@ -7,6 +7,7 @@ import type { Store } from '../store' import { getOrCreateModel } from './utils' import type { CreateData } from './vue.worker' import vueWorker from './vue.worker?worker' +import * as languageConfigs from './language-configs' let initted = false export function initMonaco(store: Store) { @@ -36,26 +37,6 @@ export function initMonaco(store: Store) { } }) - // Support for go to definition - editor.registerEditorOpener({ - openCodeEditor(_, resource) { - if (resource.toString().startsWith(jsDelivrUriBase + '/')) { - return true - } - - const path = resource.path - if (/^\//.test(path)) { - const fileName = path.replace('/', '') - if (fileName !== store.activeFile.filename) { - store.setActive(fileName) - return true - } - } - - return false - }, - }) - initted = true } @@ -166,7 +147,32 @@ export function loadMonacoEnv(store: Store) { languages.register({ id: 'vue', extensions: ['.vue'] }) languages.register({ id: 'javascript', extensions: ['.js'] }) languages.register({ id: 'typescript', extensions: ['.ts'] }) + languages.register({ id: 'css', extensions: ['.css'] }) + languages.setLanguageConfiguration('vue', languageConfigs.vue) + languages.setLanguageConfiguration('javascript', languageConfigs.js) + languages.setLanguageConfiguration('typescript', languageConfigs.ts) + languages.setLanguageConfiguration('css', languageConfigs.css) store.reloadLanguageTools = () => reloadLanguageTools(store) languages.onLanguage('vue', () => store.reloadLanguageTools!()) + + // Support for go to definition + editor.registerEditorOpener({ + openCodeEditor(_, resource) { + if (resource.toString().startsWith(jsDelivrUriBase + '/')) { + return true + } + + const path = resource.path + if (/^\//.test(path)) { + const fileName = path.replace('/', '') + if (fileName !== store.activeFile.filename) { + store.setActive(fileName) + return true + } + } + + return false + }, + }) } diff --git a/src/monaco/language-configs.ts b/src/monaco/language-configs.ts new file mode 100644 index 00000000..6a8e7cc5 --- /dev/null +++ b/src/monaco/language-configs.ts @@ -0,0 +1,529 @@ +import { languages } from 'monaco-editor-core' + +// export const html: languages.LanguageConfiguration = { +// comments: { +// blockComment: [''], +// }, +// brackets: [ +// [''], +// ['{', '}'], +// ['(', ')'], +// ], +// autoClosingPairs: [ +// { open: '{', close: '}' }, +// { open: '[', close: ']' }, +// { open: '(', close: ')' }, +// { open: "'", close: "'" }, +// { open: '"', close: '"' }, +// { open: '', notIn: ['comment', 'string'] }, +// ], +// surroundingPairs: [ +// { open: "'", close: "'" }, +// { open: '"', close: '"' }, +// { open: '{', close: '}' }, +// { open: '[', close: ']' }, +// { open: '(', close: ')' }, +// { open: '<', close: '>' }, +// ], +// colorizedBracketPairs: [], +// folding: { +// markers: { +// start: /^\s*/, +// end: /^\s*/, +// }, +// }, +// wordPattern: new RegExp( +// '(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\$\\^\\&\\*\\(\\)\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\\'\\"\\,\\.\\<\\>\\/\\s]+)', +// ), +// onEnterRules: [ +// { +// beforeText: new RegExp( +// '<(?!(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr))([_:\\w][_:\\w-.\\d]*)(?:(?:[^\'"/>]|"[^"]*"|\'[^\']*\')*?(?!\\/)>)[^<]*$', +// 'i', +// ), +// afterText: new RegExp('^<\\/([_:\\w][_:\\w-.\\d]*)\\s*>', 'i'), +// action: { +// indentAction: languages.IndentAction.IndentOutdent, +// }, +// }, +// { +// beforeText: new RegExp( +// '<(?!(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr))([_:\\w][_:\\w-.\\d]*)(?:(?:[^\'"/>]|"[^"]*"|\'[^\']*\')*?(?!\\/)>)[^<]*$', +// 'i', +// ), +// action: { +// indentAction: languages.IndentAction.Indent, +// }, +// }, +// ], +// indentationRules: { +// increaseIndentPattern: new RegExp( +// '<(?!\\?|(?:area|base|br|col|frame|hr|html|img|input|keygen|link|menuitem|meta|param|source|track|wbr)\\b|[^>]*\\/>)([-_\\.A-Za-z0-9]+)(?=\\s|>)\\b[^>]*>(?!.*<\\/\\1>)|)|\\{[^}"\']*$', +// ), +// decreaseIndentPattern: new RegExp( +// '^\\s*(<\\/(?!html)[-_\\.A-Za-z0-9]+\\b[^>]*>|-->|\\})', +// ), +// }, +// } + +export const css: languages.LanguageConfiguration = { + comments: { + blockComment: ['/*', '*/'], + }, + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'], + ], + autoClosingPairs: [ + { open: '{', close: '}', notIn: ['string', 'comment'] }, + { open: '[', close: ']', notIn: ['string', 'comment'] }, + { open: '(', close: ')', notIn: ['string', 'comment'] }, + { open: '"', close: '"', notIn: ['string', 'comment'] }, + { open: "'", close: "'", notIn: ['string', 'comment'] }, + ], + surroundingPairs: [ + { + open: "'", + close: "'", + }, + { + open: '"', + close: '"', + }, + { + open: '{', + close: '}', + }, + { + open: '[', + close: ']', + }, + { + open: '(', + close: ')', + }, + ], + folding: { + markers: { + start: new RegExp('^\\s*\\/\\*\\s*#region\\b\\s*(.*?)\\s*\\*\\/'), + end: new RegExp('^\\s*\\/\\*\\s*#endregion\\b.*\\*\\/'), + }, + }, + indentationRules: { + increaseIndentPattern: new RegExp('(^.*\\{[^}]*$)'), + decreaseIndentPattern: new RegExp('^\\s*\\}'), + }, + wordPattern: new RegExp( + '(#?-?\\d*\\.\\d\\w*%?)|(::?[\\w-]*(?=[^,{;]*[,{]))|(([@#.!])?[\\w-?]+%?|[@#!.])', + ), +} + +export const vue: languages.LanguageConfiguration = { + comments: { + blockComment: [''], + }, + brackets: [ + [''], + ['<', '>'], + ['{', '}'], + ['(', ')'], + ], + autoClosingPairs: [ + { + open: '{', + close: '}', + }, + { + open: '[', + close: ']', + }, + { + open: '(', + close: ')', + }, + { + open: "'", + close: "'", + }, + { + open: '"', + close: '"', + }, + { + open: '', + notIn: ['comment', 'string'], + }, + { + open: '`', + close: '`', + notIn: ['string', 'comment'], + }, + { + open: '/**', + close: ' */', + notIn: ['string'], + }, + ], + autoCloseBefore: ';:.,=}])><`\'" \n\t', + surroundingPairs: [ + { + open: "'", + close: "'", + }, + { + open: '"', + close: '"', + }, + { + open: '{', + close: '}', + }, + { + open: '[', + close: ']', + }, + { + open: '(', + close: ')', + }, + { + open: '<', + close: '>', + }, + { + open: '`', + close: '`', + }, + ], + colorizedBracketPairs: [], + folding: { + markers: { + start: /^\s*/, + end: /^\s*/, + }, + }, + wordPattern: + /(-?\d*\.\d\w*)|([^\`\@\~\!\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>/\?\s]+)/, + onEnterRules: [ + { + beforeText: + /<(?!(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr|script|style))([_:\w][_:\w-.\d]*)(?:(?:[^'"/>]|"[^"]*"|'[^']*')*?(?!\/)>)[^<]*$/i, + afterText: /^<\/([_:\w][_:\w-.\d]*)\s*>/i, + action: { + indentAction: languages.IndentAction.IndentOutdent, + }, + }, + { + beforeText: + /<(?!(?:area|base|br|col|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr|script|style))([_:\w][_:\w-.\d]*)(?:(?:[^'"/>]|"[^"]*"|'[^']*')*?(?!\/)>)[^<]*$/i, + action: { + indentAction: languages.IndentAction.Indent, + }, + }, + ], + indentationRules: { + increaseIndentPattern: + /<(?!\?|(?:area|base|br|col|frame|hr|html|img|input|keygen|link|menuitem|meta|param|source|track|wbr|script|style)\b|[^>]*\/>)([-_\.A-Za-z0-9]+)(?=\s|>)\b[^>]*>(?!\s*\()(?!.*<\/\1>)|)|\{[^}"']*$/i, + decreaseIndentPattern: /^\s*(<\/(?!html)[-_\.A-Za-z0-9]+\b[^>]*>|-->|\})/, + }, +} + +export const js: languages.LanguageConfiguration = { + comments: { + lineComment: '//', + blockComment: ['/*', '*/'], + }, + brackets: [ + ['${', '}'], + ['{', '}'], + ['[', ']'], + ['(', ')'], + ], + autoClosingPairs: [ + { + open: '{', + close: '}', + }, + { + open: '[', + close: ']', + }, + { + open: '(', + close: ')', + }, + { + open: "'", + close: "'", + notIn: ['string', 'comment'], + }, + { + open: '"', + close: '"', + notIn: ['string'], + }, + { + open: '`', + close: '`', + notIn: ['string', 'comment'], + }, + { + open: '/**', + close: ' */', + notIn: ['string'], + }, + ], + surroundingPairs: [ + { + open: "'", + close: "'", + }, + { + open: '"', + close: '"', + }, + { + open: '{', + close: '}', + }, + { + open: '[', + close: ']', + }, + { + open: '(', + close: ')', + }, + { + open: '<', + close: '>', + }, + { + open: '`', + close: '`', + }, + ], + autoCloseBefore: ';:.,=}])>` \n\t', + folding: { + markers: { + start: /^\s*\/\/\s*#?region\b/, + end: /^\s*\/\/\s*#?endregion\b/, + }, + }, + wordPattern: + /(-?\d*\.\d\w*)|([^\`\~\@\!\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>/\?\s]+)/, + indentationRules: { + decreaseIndentPattern: /^((?!.*?\/\*).*\*\/)?\s*[\}\]].*$/, + increaseIndentPattern: + /^((?!\/\/).)*(\{([^}"'`/]*|(\t|[ ])*\/\/.*)|\([^)"'`/]*|\[[^\]"'`/]*)$/, + unIndentedLinePattern: + /^(\t|[ ])*[ ]\*[^/]*\*\/\s*$|^(\t|[ ])*[ ]\*\/\s*$|^(\t|[ ])*[ ]\*([ ]([^\*]|\*(?!\/))*)?$/, + }, + onEnterRules: [ + { + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + afterText: /^\s*\*\/$/, + action: { + indentAction: languages.IndentAction.IndentOutdent, + appendText: ' * ', + }, + }, + { + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + action: { + indentAction: languages.IndentAction.None, + appendText: ' * ', + }, + }, + { + beforeText: /^(\t|[ ])*[ ]\*([ ]([^\*]|\*(?!\/))*)?$/, + previousLineText: /(?=^(\s*(\/\*\*|\*)).*)(?=(?!(\s*\*\/)))/, + action: { + indentAction: languages.IndentAction.None, + appendText: '* ', + }, + }, + { + beforeText: /^(\t|[ ])*[ ]\*\/\s*$/, + action: { + indentAction: languages.IndentAction.None, + removeText: 1, + }, + }, + { + beforeText: /^(\t|[ ])*[ ]\*[^/]*\*\/\s*$/, + action: { + indentAction: languages.IndentAction.None, + removeText: 1, + }, + }, + { + beforeText: /^\s*(\bcase\s.+:|\bdefault:)$/, + afterText: /^(?!\s*(\bcase\b|\bdefault\b))/, + action: { + indentAction: languages.IndentAction.Indent, + }, + }, + { + previousLineText: /^\s*(((else ?)?if|for|while)\s*\(.*\)\s*|else\s*)$/, + beforeText: /^\s+([^{i\s]|i(?!f\b))/, + action: { + indentAction: languages.IndentAction.Outdent, + }, + }, + ], +} + +export const ts: languages.LanguageConfiguration = { + comments: { + lineComment: '//', + blockComment: ['/*', '*/'], + }, + brackets: [ + ['${', '}'], + ['{', '}'], + ['[', ']'], + ['(', ')'], + ], + autoClosingPairs: [ + { + open: '{', + close: '}', + }, + { + open: '[', + close: ']', + }, + { + open: '(', + close: ')', + }, + { + open: "'", + close: "'", + notIn: ['string', 'comment'], + }, + { + open: '"', + close: '"', + notIn: ['string'], + }, + { + open: '`', + close: '`', + notIn: ['string', 'comment'], + }, + { + open: '/**', + close: ' */', + notIn: ['string'], + }, + ], + surroundingPairs: [ + { + open: "'", + close: "'", + }, + { + open: '"', + close: '"', + }, + { + open: '{', + close: '}', + }, + { + open: '[', + close: ']', + }, + { + open: '(', + close: ')', + }, + { + open: '<', + close: '>', + }, + { + open: '`', + close: '`', + }, + ], + colorizedBracketPairs: [ + ['(', ')'], + ['[', ']'], + ['{', '}'], + ['<', '>'], + ], + autoCloseBefore: ';:.,=}])>` \n\t', + folding: { + markers: { + start: /^\s*\/\/\s*#?region\b/, + end: /^\s*\/\/\s*#?endregion\b/, + }, + }, + wordPattern: + /(-?\d*\.\d\w*)|([^\`\~\@\!\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>/\?\s]+)/, + indentationRules: { + decreaseIndentPattern: /^((?!.*?\/\*).*\*\/)?\s*[\}\]].*$/, + increaseIndentPattern: + /^((?!\/\/).)*(\{([^}"'`/]*|(\t|[ ])*\/\/.*)|\([^)"'`/]*|\[[^\]"'`/]*)$/, + unIndentedLinePattern: + /^(\t|[ ])*[ ]\*[^/]*\*\/\s*$|^(\t|[ ])*[ ]\*\/\s*$|^(\t|[ ])*[ ]\*([ ]([^\*]|\*(?!\/))*)?$/, + }, + onEnterRules: [ + { + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + afterText: /^\s*\*\/$/, + action: { + indentAction: languages.IndentAction.IndentOutdent, + appendText: ' * ', + }, + }, + { + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + action: { + indentAction: languages.IndentAction.None, + appendText: ' * ', + }, + }, + { + beforeText: /^(\t|[ ])*[ ]\*([ ]([^\*]|\*(?!\/))*)?$/, + previousLineText: /(?=^(\s*(\/\*\*|\*)).*)(?=(?!(\s*\*\/)))/, + action: { + indentAction: languages.IndentAction.None, + appendText: '* ', + }, + }, + { + beforeText: /^(\t|[ ])*[ ]\*\/\s*$/, + action: { + indentAction: languages.IndentAction.None, + removeText: 1, + }, + }, + { + beforeText: /^(\t|[ ])*[ ]\*[^/]*\*\/\s*$/, + action: { + indentAction: languages.IndentAction.None, + removeText: 1, + }, + }, + { + beforeText: /^\s*(\bcase\s.+:|\bdefault:)$/, + afterText: /^(?!\s*(\bcase\b|\bdefault\b))/, + action: { + indentAction: languages.IndentAction.Indent, + }, + }, + { + previousLineText: /^\s*(((else ?)?if|for|while)\s*\(.*\)\s*|else\s*)$/, + beforeText: /^\s+([^{i\s]|i(?!f\b))/, + action: { + indentAction: languages.IndentAction.Outdent, + }, + }, + ], +}