From 89660b162b8029fa53d7c8731ff81890355017d4 Mon Sep 17 00:00:00 2001 From: Menci Date: Sat, 13 Apr 2019 18:41:16 +0800 Subject: [PATCH] Finish monaco editor --- language-config.json | 18 +- static/self/monaco-editor-tomorrow.js | 332 ++++---- static/self/monaco-editor.css | 107 ++- static/self/monaco-editor.js | 1024 ++++++++++++++++--------- views/admin_raw.ejs | 8 +- views/article.ejs | 28 +- views/article_edit.ejs | 54 +- views/contest_edit.ejs | 41 +- views/header.ejs | 1 - views/monaco-editor.ejs | 31 +- views/problem.ejs | 22 +- views/problem_edit.ejs | 88 ++- views/user_edit.ejs | 31 +- 13 files changed, 1135 insertions(+), 650 deletions(-) diff --git a/language-config.json b/language-config.json index 1ab1396..806ae77 100644 --- a/language-config.json +++ b/language-config.json @@ -3,63 +3,63 @@ "show": "C++", "highlight": "cpp", "version": "GCC 8.2.0", - "editor": "c_cpp", + "editor": "cpp", "format": "cpp" }, "cpp11": { "show": "C++ 11", "highlight": "cpp", "version": "GCC 8.2.0", - "editor": "c_cpp", + "editor": "cpp", "format": "cpp" }, "cpp17": { "show": "C++ 17", "highlight": "cpp", "version": "GCC 8.2.0", - "editor": "c_cpp", + "editor": "cpp", "format": "cpp" }, "cpp-noilinux": { "show": "C++ (NOI)", "highlight": "cpp", "version": "GCC 4.8.4 (NOILinux 1.4.1)", - "editor": "c_cpp", + "editor": "cpp", "format": "cpp" }, "cpp11-noilinux": { "show": "C++ 11 (NOI)", "highlight": "cpp", "version": "GCC 4.8.4 (NOILinux 1.4.1)", - "editor": "c_cpp", + "editor": "cpp", "format": "cpp" }, "cpp11-clang": { "show": "C++ 11 (Clang)", "highlight": "cpp", "version": "Clang 7.0.1", - "editor": "c_cpp", + "editor": "cpp", "format": "cpp" }, "cpp17-clang": { "show": "C++ 17 (Clang)", "highlight": "cpp", "version": "Clang 7.0.1", - "editor": "c_cpp", + "editor": "cpp", "format": "cpp" }, "c": { "show": "C", "highlight": "c", "version": "Clang 7.0.1", - "editor": "c_cpp", + "editor": "c", "format": "c" }, "c-noilinux": { "show": "C (NOI)", "highlight": "c", "version": "GCC 4.8.4 (NOILinux 1.4.1)", - "editor": "c_cpp", + "editor": "c", "format": "c" }, "csharp": { diff --git a/static/self/monaco-editor-tomorrow.js b/static/self/monaco-editor-tomorrow.js index 023f4ca..fae3d55 100644 --- a/static/self/monaco-editor-tomorrow.js +++ b/static/self/monaco-editor-tomorrow.js @@ -1,167 +1,167 @@ -monaco.editor.defineTheme('tomorrow', { - "base": "vs", - "inherit": true, - "rules": [ - { - "foreground": "8e908c", - "token": "comment" - }, - { - "foreground": "666969", - "token": "keyword.operator.class" - }, - { - "foreground": "666969", - "token": "constant.other" - }, - { - "foreground": "666969", - "token": "source.php.embedded.line" - }, - { - "foreground": "c82829", - "token": "variable" - }, - { - "foreground": "c82829", - "token": "support.other.variable" - }, - { - "foreground": "c82829", - "token": "string.other.link" - }, - { - "foreground": "c82829", - "token": "string.regexp" - }, - { - "foreground": "c82829", - "token": "entity.name.tag" - }, - { - "foreground": "c82829", - "token": "entity.other.attribute-name" - }, - { - "foreground": "c82829", - "token": "meta.tag" - }, - { - "foreground": "c82829", - "token": "declaration.tag" - }, - { - "foreground": "f5871f", - "token": "constant.numeric" - }, - { - "foreground": "f5871f", - "token": "constant.language" - }, - { - "foreground": "f5871f", - "token": "support.constant" - }, - { - "foreground": "f5871f", - "token": "constant.character" - }, - { - "foreground": "f5871f", - "token": "variable.parameter" - }, - { - "foreground": "f5871f", - "token": "punctuation.section.embedded" - }, - { - "foreground": "f5871f", - "token": "keyword.other.unit" - }, - { - "foreground": "c99e00", - "token": "entity.name.class" - }, - { - "foreground": "c99e00", - "token": "entity.name.type.class" - }, - { - "foreground": "c99e00", - "token": "support.type" - }, - { - "foreground": "c99e00", - "token": "support.class" - }, - { - "foreground": "718c00", - "token": "string" - }, - { - "foreground": "718c00", - "token": "constant.other.symbol" - }, - { - "foreground": "718c00", - "token": "entity.other.inherited-class" - }, - { - "foreground": "718c00", - "token": "markup.heading" - }, - { - "foreground": "3e999f", - "token": "keyword.operator" - }, - { - "foreground": "3e999f", - "token": "constant.other.color" - }, - { - "foreground": "4271ae", - "token": "entity.name.function" - }, - { - "foreground": "4271ae", - "token": "meta.function-call" - }, - { - "foreground": "4271ae", - "token": "support.function" - }, - { - "foreground": "4271ae", - "token": "keyword.other.special-method" - }, - { - "foreground": "4271ae", - "token": "meta.block-level" - }, - { - "foreground": "8959a8", - "token": "keyword" - }, - { - "foreground": "8959a8", - "token": "storage" - }, - { - "foreground": "8959a8", - "token": "storage.type" - }, - { - "foreground": "373b41", - "background": "e0e0e0", - "token": "meta.separator" - } - ], - "colors": { - "editor.foreground": "#4D4D4C", - "editor.background": "#FFFFFF", - "editor.selectionBackground": "#D6D6D6", - "editor.lineHighlightBackground": "#EFEFEF", - "editorCursor.foreground": "#AEAFAD", - "editorWhitespace.foreground": "#D1D1D1" - } +monaco.editor.defineTheme('tomorrow', { + "base": "vs", + "inherit": true, + "rules": [ + { + "foreground": "8e908c", + "token": "comment" + }, + { + "foreground": "666969", + "token": "keyword.operator.class" + }, + { + "foreground": "666969", + "token": "constant.other" + }, + { + "foreground": "666969", + "token": "source.php.embedded.line" + }, + { + "foreground": "c82829", + "token": "variable" + }, + { + "foreground": "c82829", + "token": "support.other.variable" + }, + { + "foreground": "c82829", + "token": "string.other.link" + }, + { + "foreground": "c82829", + "token": "string.regexp" + }, + { + "foreground": "c82829", + "token": "entity.name.tag" + }, + { + "foreground": "c82829", + "token": "entity.other.attribute-name" + }, + { + "foreground": "c82829", + "token": "meta.tag" + }, + { + "foreground": "c82829", + "token": "declaration.tag" + }, + { + "foreground": "f5871f", + "token": "constant.numeric" + }, + { + "foreground": "f5871f", + "token": "constant.language" + }, + { + "foreground": "f5871f", + "token": "support.constant" + }, + { + "foreground": "f5871f", + "token": "constant.character" + }, + { + "foreground": "f5871f", + "token": "variable.parameter" + }, + { + "foreground": "f5871f", + "token": "punctuation.section.embedded" + }, + { + "foreground": "f5871f", + "token": "keyword.other.unit" + }, + { + "foreground": "c99e00", + "token": "entity.name.class" + }, + { + "foreground": "c99e00", + "token": "entity.name.type.class" + }, + { + "foreground": "c99e00", + "token": "support.type" + }, + { + "foreground": "c99e00", + "token": "support.class" + }, + { + "foreground": "718c00", + "token": "string" + }, + { + "foreground": "718c00", + "token": "constant.other.symbol" + }, + { + "foreground": "718c00", + "token": "entity.other.inherited-class" + }, + { + "foreground": "718c00", + "token": "markup.heading" + }, + { + "foreground": "3e999f", + "token": "keyword.operator" + }, + { + "foreground": "3e999f", + "token": "constant.other.color" + }, + { + "foreground": "4271ae", + "token": "entity.name.function" + }, + { + "foreground": "4271ae", + "token": "meta.function-call" + }, + { + "foreground": "4271ae", + "token": "support.function" + }, + { + "foreground": "4271ae", + "token": "keyword.other.special-method" + }, + { + "foreground": "4271ae", + "token": "meta.block-level" + }, + { + "foreground": "8959a8", + "token": "keyword" + }, + { + "foreground": "8959a8", + "token": "storage" + }, + { + "foreground": "8959a8", + "token": "storage.type" + }, + { + "foreground": "373b41", + "background": "e0e0e0", + "token": "meta.separator" + } + ], + "colors": { + "editor.foreground": "#4D4D4C", + "editor.background": "#FFFFFF", + "editor.selectionBackground": "#D6D6D6", + "editor.lineHighlightBackground": "#EFEFEF", + "editorCursor.foreground": "#AEAFAD", + "editorWhitespace.foreground": "#D1D1D1" + } }); \ No newline at end of file diff --git a/static/self/monaco-editor.css b/static/self/monaco-editor.css index 4ace84b..71b46c3 100644 --- a/static/self/monaco-editor.css +++ b/static/self/monaco-editor.css @@ -1,37 +1,70 @@ -.editor { - background: #fff; - font-family: "Fira Mono", "Bitstream Vera Sans Mono", Menlo, Consolas, "Lucida Console", monospace; -} - -.monaco-editor .inputarea { - min-height: 0 !important; - padding: 0 !important; - border: 0 !important; - color: rgba(0, 0, 0, 0) !important; -} - -.monaco-editor-background.textAreaCover.line-numbers { - visibility: hidden; -} - -.monaco-editor .selected-text, .monaco-editor .monaco-editor-background { - border-radius: 0 !important; -} - -.monaco-editor .mtk1 { - color: #4d4d4c !important; -} - -.monaco-editor .cursor { - color: #000 !important; - border-color: #000 !important; - background-color: #000 !important; -} - -.monaco-editor .line-numbers { - color: #4d4d4c !important; -} - -.monaco-editor .margin-view-overlays .current-line { - background-color: #efefef !important; -} +.editor { + background: #fff; + position: relative; + border: 1px solid rgba(34, 36, 38, 0.15); +} + +.editor.editor-with-border { + border-radius: .28571429rem; + overflow: hidden; + outline: none; +} + +.editor.editor-with-border:focus-within { + border-color: #85b7d9; +} + +.editor.editor-with-border .monaco-editor .margin { + visibility: hidden; +} + +.editor.editor-with-border .monaco-editor .lines-content.monaco-editor-background { + margin-top: 9px; + margin-left: 4px; +} + +.monaco-editor .inputarea { + min-height: 0 !important; + padding: 0 !important; + border: 0 !important; + color: rgba(0, 0, 0, 0) !important; +} + +.monaco-editor-background.textAreaCover.line-numbers { + visibility: hidden; +} + +.monaco-editor .selected-text, .monaco-editor .monaco-editor-background { + border-radius: 0 !important; +} + +.monaco-editor .mtk1 { + color: #4d4d4c !important; +} + +.monaco-editor .cursor { + color: #000 !important; + border-color: #000 !important; + background-color: #000 !important; +} + +.monaco-editor .line-numbers { + color: #575756 !important; +} + +.monaco-editor .margin-view-overlays .current-line ~ .line-numbers { + color: #000 !important; + font-weight: 500; +} + +.editor.editor-with-border .monaco-editor .monaco-scrollable-element .scrollbar.vertical { + background: rgba(0,0,0,.1); + border-radius: 0; +} + +.editor.editor-with-border .monaco-editor .monaco-scrollable-element .scrollbar.vertical .slider { + border-radius: 5px; + background: rgba(0,0,0,.25); + -webkit-transition: color .2s ease; + transition: color .2s ease; +} diff --git a/static/self/monaco-editor.js b/static/self/monaco-editor.js index bbf71fe..3ffc1cd 100644 --- a/static/self/monaco-editor.js +++ b/static/self/monaco-editor.js @@ -1,363 +1,661 @@ -require.config({ - paths: { - vs: window.pathLib + "monaco-editor/0.16.2/min/vs", - tokenizer: window.pathSelfLib + 'vendor/tokenizer' - } -}); - -window.onEditorLoaded = function (fn) { - if (window.editorLoaded) { - fn(); - } else { - if (!window.editorLoadedHandles) window.editorLoadedHandles = []; - window.editorLoadedHandles.push(fn); - } -}; - -require(['vs/editor/editor.main'], function () { - require(['tokenizer/monaco-tokenizer', - 'tokenizer/definitions/c_cpp', - 'tokenizer/definitions/csharp', - 'tokenizer/definitions/haskell', - 'tokenizer/definitions/java', - 'tokenizer/definitions/javascript', - 'tokenizer/definitions/pascal', - 'tokenizer/definitions/python', - 'tokenizer/definitions/ruby'], - function(MonacoAceTokenizer, - c_cppDefinition, - CSharpDefinition, - HaskellDefinition, - JavaDefinition, - JavaScriptDefinition, - PascalDefinition, - PythonDefinition, - RubyDefinition) { - monaco.languages.register({ id: 'ace_c_cpp' }); - MonacoAceTokenizer.registerRulesForLanguage('ace_c_cpp', new c_cppDefinition.default); - monaco.languages.setLanguageConfiguration('ace_c_cpp', { - comments: { - lineComment: '//', - blockComment: ['/*', '*/'], - }, - brackets: [ - ['{', '}'], - ['[', ']'], - ['(', ')'] - ], - autoClosingPairs: [ - { open: '[', close: ']' }, - { open: '{', close: '}' }, - { open: '(', close: ')' }, - { open: '\'', close: '\'', notIn: ['string', 'comment'] }, - { open: '"', close: '"', notIn: ['string'] }, - ], - surroundingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '"', close: '"' }, - { open: '\'', close: '\'' }, - ], - folding: { - markers: { - start: new RegExp("^\\s*#pragma\\s+region\\b"), - end: new RegExp("^\\s*#pragma\\s+endregion\\b") - } - } - }); - - monaco.languages.register({ id: 'ace_csharp' }); - MonacoAceTokenizer.registerRulesForLanguage('ace_csharp', new CSharpDefinition.default); - monaco.languages.setLanguageConfiguration('ace_csharp', { - wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, - comments: { - lineComment: '//', - blockComment: ['/*', '*/'], - }, - brackets: [ - ['{', '}'], - ['[', ']'], - ['(', ')'], - ], - autoClosingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '\'', close: '\'', notIn: ['string', 'comment'] }, - { open: '"', close: '"', notIn: ['string', 'comment'] }, - ], - surroundingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '<', close: '>' }, - { open: '\'', close: '\'' }, - { open: '"', close: '"' }, - ], - folding: { - markers: { - start: new RegExp("^\\s*#region\\b"), - end: new RegExp("^\\s*#endregion\\b") - } - } - }); - - monaco.languages.register({ id: 'ace_haskell' }); - MonacoAceTokenizer.registerRulesForLanguage('ace_haskell', new HaskellDefinition.default); - monaco.languages.setLanguageConfiguration('ace_haskell', { - comments: { - lineComment: '--', - blockComment: ['{-', '-}'] - }, - brackets: [ - ['{', '}'], - ['[', ']'], - ['(', ')'] - ], - autoClosingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '\'', close: '\'', notIn: ['string'] }, - { open: '`', close: '`', notIn: ['string', 'comment'] } - ], - surroundingPairs: [ - ['{', '}'], - ['[', ']'], - ['(', ')'], - ['\'', '\''], - ['"', '"'], - ['`', '`'] - ], - indentationRules: { - decreaseIndentPattern: new RegExp("[\\]})][ \\t]*$/m"), - increaseIndentPattern: new RegExp("((\\b(if\\b.*|then|else|do|of|let|in|where))|=|->|>>=|>=>|=<<|(^(data)( |\t)+(\\w|')+( |\\t)*))( |\\t)*$/") - } - }); - - monaco.languages.register({ id: 'ace_java' }); - MonacoAceTokenizer.registerRulesForLanguage('ace_java', new JavaDefinition.default); - monaco.languages.setLanguageConfiguration('ace_java', { - // the default separators except `@$` - wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, - comments: { - lineComment: '//', - blockComment: ['/*', '*/'], - }, - brackets: [ - ['{', '}'], - ['[', ']'], - ['(', ')'], - ], - autoClosingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '"', close: '"' }, - { open: '\'', close: '\'' }, - ], - surroundingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '"', close: '"' }, - { open: '\'', close: '\'' }, - { open: '<', close: '>' }, - ], - folding: { - markers: { - start: new RegExp("^\\s*//\\s*(?:(?:#?region\\b)|(?:))") - } - } - }); - - monaco.languages.register({ id: 'ace_javascript' }); - MonacoAceTokenizer.registerRulesForLanguage('ace_javascript', new JavaScriptDefinition.default); - monaco.languages.setLanguageConfiguration('ace_javascript', { - wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, - comments: { - lineComment: '//', - blockComment: ['/*', '*/'] - }, - brackets: [ - ['{', '}'], - ['[', ']'], - ['(', ')'] - ], - onEnterRules: [ - { - // e.g. /** | */ - beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, - afterText: /^\s*\*\/$/, - action: { indentAction: monaco.languages.IndentAction.IndentOutdent, appendText: ' * ' } - }, - { - // e.g. /** ...| - beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, - action: { indentAction: monaco.languages.IndentAction.None, appendText: ' * ' } - }, - { - // e.g. * ...| - beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/, - action: { indentAction: monaco.languages.IndentAction.None, appendText: '* ' } - }, - { - // e.g. */| - beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/, - action: { indentAction: monaco.languages.IndentAction.None, removeText: 1 } - } - ], - autoClosingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '"', close: '"', notIn: ['string'] }, - { open: '\'', close: '\'', notIn: ['string', 'comment'] }, - { open: '`', close: '`', notIn: ['string', 'comment'] }, - { open: "/**", close: " */", notIn: ["string"] } - ], - folding: { - markers: { - start: new RegExp("^\\s*//\\s*#?region\\b"), - end: new RegExp("^\\s*//\\s*#?endregion\\b") - } - } - }); - - monaco.languages.register({ id: 'ace_pascal' }); - MonacoAceTokenizer.registerRulesForLanguage('ace_pascal', new PascalDefinition.default); - monaco.languages.setLanguageConfiguration('ace_pascal', { - // the default separators except `@$` - wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, - comments: { - lineComment: '//', - blockComment: ['{', '}'], - }, - brackets: [ - ['{', '}'], - ['[', ']'], - ['(', ')'], - ['<', '>'], - ], - autoClosingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '<', close: '>' }, - { open: '\'', close: '\'' }, - ], - surroundingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '<', close: '>' }, - { open: '\'', close: '\'' }, - ], - folding: { - markers: { - start: new RegExp("^\\s*\\{\\$REGION(\\s\\'.*\\')?\\}"), - end: new RegExp("^\\s*\\{\\$ENDREGION\\}") - } - } - }); - - monaco.languages.register({ id: 'ace_python' }); - MonacoAceTokenizer.registerRulesForLanguage('ace_python', new PythonDefinition.default); - monaco.languages.setLanguageConfiguration('ace_python', { - comments: { - lineComment: '#', - blockComment: ['\'\'\'', '\'\'\''], - }, - brackets: [ - ['{', '}'], - ['[', ']'], - ['(', ')'] - ], - autoClosingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '"', close: '"', notIn: ['string'] }, - { open: '\'', close: '\'', notIn: ['string', 'comment'] }, - ], - surroundingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '"', close: '"' }, - { open: '\'', close: '\'' }, - ], - onEnterRules: [ - { - beforeText: new RegExp("^\\s*(?:def|class|for|if|elif|else|while|try|with|finally|except|async).*?:\\s*$"), - action: { indentAction: monaco.languages.IndentAction.Indent } - } - ], - folding: { - offSide: true, - markers: { - start: new RegExp("^\\s*#region\\b"), - end: new RegExp("^\\s*#endregion\\b") - } - } - }); - - monaco.languages.register({ id: 'ace_ruby' }); - MonacoAceTokenizer.registerRulesForLanguage('ace_ruby', new RubyDefinition.default); - monaco.languages.setLanguageConfiguration('ace_ruby', { - comments: { - lineComment: '#', - blockComment: ['=begin', '=end'], - }, - brackets: [ - ['(', ')'], - ['{', '}'], - ['[', ']'] - ], - autoClosingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '"', close: '"' }, - { open: '\'', close: '\'' }, - ], - surroundingPairs: [ - { open: '{', close: '}' }, - { open: '[', close: ']' }, - { open: '(', close: ')' }, - { open: '"', close: '"' }, - { open: '\'', close: '\'' }, - ], - indentationRules: { - increaseIndentPattern: new RegExp('^\\s*((begin|class|(private|protected)\\s+def|def|else|elsif|ensure|for|if|module|rescue|unless|until|when|while|case)|([^#]*\\sdo\\b)|([^#]*=\\s*(case|if|unless)))\\b([^#\\{;]|("|\'|\/).*\\4)*(#.*)?$'), - decreaseIndentPattern: new RegExp('^\\s*([}\\]]([,)]?\\s*(#|$)|\\.[a-zA-Z_]\\w*\\b)|(end|rescue|ensure|else|elsif|when)\\b)'), - } - }); - - - $.getScript(window.pathSelfLib + "monaco-editor-tomorrow.js", function () { - window.createEditor = function (editorElement, langauge, content) { - return monaco.editor.create(editorElement, { - value: content, - language: langauge, - multicursorModifier: 'ctrlCmd', - cursorWidth: 1, - theme: 'tomorrow', - lineHeight: 22, - fontSize: 14, - fontFamily: "'Fira Mono', 'Bitstream Vera Sans Mono', 'Menlo', 'Consolas', 'Lucida Console', monospace", - lineNumbersMinChars: 4, - glyphMargin: false - }); - }; - - window.editorLoaded = true; - for (var i in window.editorLoadedHandles) { - window.editorLoadedHandles[i](); - } - }); - } - ); -}); +require.config({ + paths: { + vs: window.pathLib + "monaco-editor/0.16.2/min/vs", + tokenizer: window.pathSelfLib + 'vendor/tokenizer' + } +}); + +window.onEditorLoaded = function (fn) { + if (window.editorLoaded) { + fn(); + } else { + if (!window.editorLoadedHandles) window.editorLoadedHandles = []; + window.editorLoadedHandles.push(fn); + } +}; + +require(['vs/editor/editor.main'], function () { + require(['tokenizer/monaco-tokenizer', + 'tokenizer/definitions/c_cpp', + 'tokenizer/definitions/csharp', + 'tokenizer/definitions/haskell', + 'tokenizer/definitions/java', + 'tokenizer/definitions/javascript', + 'tokenizer/definitions/pascal', + 'tokenizer/definitions/python', + 'tokenizer/definitions/ruby'], + function(MonacoAceTokenizer, + c_cppDefinition, + CSharpDefinition, + HaskellDefinition, + JavaDefinition, + JavaScriptDefinition, + PascalDefinition, + PythonDefinition, + RubyDefinition) { + var overrideLangauges = [ + 'cpp', + 'c', + 'csharp', + 'haskell', + 'java', + 'javascript', + 'pascal', + 'python', + 'ruby', + 'markdown' + ]; + + monaco.languages.getLanguages().forEach(function (lang) { + if (overrideLangauges.includes(lang.id)) { + lang.loader = function () { + return { then: function () {} }; + }; + } + }); + + var cppAliases = ['c', 'cpp', 'c++', 'cxx', 'cc']; + for (var i in cppAliases) { + var alias = cppAliases[i]; + + monaco.languages.register({ id: alias }); + MonacoAceTokenizer.registerRulesForLanguage(alias, new c_cppDefinition.default); + monaco.languages.setLanguageConfiguration(alias, { + comments: { + lineComment: '//', + blockComment: ['/*', '*/'], + }, + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'] + ], + autoClosingPairs: [ + { open: '[', close: ']' }, + { open: '{', close: '}' }, + { open: '(', close: ')' }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '"', close: '"', notIn: ['string'] }, + ], + surroundingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: '\'', close: '\'' }, + ], + folding: { + markers: { + start: new RegExp("^\\s*#pragma\\s+region\\b"), + end: new RegExp("^\\s*#pragma\\s+endregion\\b") + } + } + }); + } + + var csharpAliases = ['csharp', 'cs', 'c#']; + for (var i in csharpAliases) { + var alias = csharpAliases[i]; + + monaco.languages.register({ id: alias }); + MonacoAceTokenizer.registerRulesForLanguage(alias, new CSharpDefinition.default); + monaco.languages.setLanguageConfiguration(alias, { + wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, + comments: { + lineComment: '//', + blockComment: ['/*', '*/'], + }, + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'], + ], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '"', close: '"', notIn: ['string', 'comment'] }, + ], + surroundingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '<', close: '>' }, + { open: '\'', close: '\'' }, + { open: '"', close: '"' }, + ], + folding: { + markers: { + start: new RegExp("^\\s*#region\\b"), + end: new RegExp("^\\s*#endregion\\b") + } + } + }); + } + + monaco.languages.register({ id: 'haskell' }); + MonacoAceTokenizer.registerRulesForLanguage('haskell', new HaskellDefinition.default); + monaco.languages.setLanguageConfiguration('haskell', { + comments: { + lineComment: '--', + blockComment: ['{-', '-}'] + }, + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'] + ], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '\'', close: '\'', notIn: ['string'] }, + { open: '`', close: '`', notIn: ['string', 'comment'] } + ], + surroundingPairs: [ + ['{', '}'], + ['[', ']'], + ['(', ')'], + ['\'', '\''], + ['"', '"'], + ['`', '`'] + ], + indentationRules: { + decreaseIndentPattern: new RegExp("[\\]})][ \\t]*$/m"), + increaseIndentPattern: new RegExp("((\\b(if\\b.*|then|else|do|of|let|in|where))|=|->|>>=|>=>|=<<|(^(data)( |\t)+(\\w|')+( |\\t)*))( |\\t)*$/") + } + }); + + monaco.languages.register({ id: 'java' }); + MonacoAceTokenizer.registerRulesForLanguage('java', new JavaDefinition.default); + monaco.languages.setLanguageConfiguration('java', { + // the default separators except `@$` + wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, + comments: { + lineComment: '//', + blockComment: ['/*', '*/'], + }, + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'], + ], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: '\'', close: '\'' }, + ], + surroundingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: '\'', close: '\'' }, + { open: '<', close: '>' }, + ], + folding: { + markers: { + start: new RegExp("^\\s*//\\s*(?:(?:#?region\\b)|(?:))") + } + } + }); + + var javascriptAliases = ['javascript', 'js']; + for (var i in javascriptAliases) { + var alias = javascriptAliases[i]; + monaco.languages.register({ id: alias }); + MonacoAceTokenizer.registerRulesForLanguage(alias, new JavaScriptDefinition.default); + monaco.languages.setLanguageConfiguration(alias, { + wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, + comments: { + lineComment: '//', + blockComment: ['/*', '*/'] + }, + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'] + ], + onEnterRules: [ + { + // e.g. /** | */ + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + afterText: /^\s*\*\/$/, + action: { indentAction: monaco.languages.IndentAction.IndentOutdent, appendText: ' * ' } + }, + { + // e.g. /** ...| + beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/, + action: { indentAction: monaco.languages.IndentAction.None, appendText: ' * ' } + }, + { + // e.g. * ...| + beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/, + action: { indentAction: monaco.languages.IndentAction.None, appendText: '* ' } + }, + { + // e.g. */| + beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/, + action: { indentAction: monaco.languages.IndentAction.None, removeText: 1 } + } + ], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"', notIn: ['string'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + { open: '`', close: '`', notIn: ['string', 'comment'] }, + { open: "/**", close: " */", notIn: ["string"] } + ], + folding: { + markers: { + start: new RegExp("^\\s*//\\s*#?region\\b"), + end: new RegExp("^\\s*//\\s*#?endregion\\b") + } + } + }); + } + + var pascalAliases = ['pascal', 'pas']; + for (var i in pascalAliases) { + var alias = pascalAliases[i]; + + monaco.languages.register({ id: alias }); + MonacoAceTokenizer.registerRulesForLanguage(alias, new PascalDefinition.default); + monaco.languages.setLanguageConfiguration(alias, { + // the default separators except `@$` + wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, + comments: { + lineComment: '//', + blockComment: ['{', '}'], + }, + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'], + ['<', '>'], + ], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '<', close: '>' }, + { open: '\'', close: '\'' }, + ], + surroundingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '<', close: '>' }, + { open: '\'', close: '\'' }, + ], + folding: { + markers: { + start: new RegExp("^\\s*\\{\\$REGION(\\s\\'.*\\')?\\}"), + end: new RegExp("^\\s*\\{\\$ENDREGION\\}") + } + } + }); + } + + var pythonAliases = ['python', 'python2', 'python3', 'py', 'py2', 'py3']; + for (var i in pythonAliases) { + var alias = pythonAliases[i]; + + monaco.languages.register({ id: alias }); + MonacoAceTokenizer.registerRulesForLanguage(alias, new PythonDefinition.default); + monaco.languages.setLanguageConfiguration(alias, { + comments: { + lineComment: '#', + blockComment: ['\'\'\'', '\'\'\''], + }, + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'] + ], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"', notIn: ['string'] }, + { open: '\'', close: '\'', notIn: ['string', 'comment'] }, + ], + surroundingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: '\'', close: '\'' }, + ], + onEnterRules: [ + { + beforeText: new RegExp("^\\s*(?:def|class|for|if|elif|else|while|try|with|finally|except|async).*?:\\s*$"), + action: { indentAction: monaco.languages.IndentAction.Indent } + } + ], + folding: { + offSide: true, + markers: { + start: new RegExp("^\\s*#region\\b"), + end: new RegExp("^\\s*#endregion\\b") + } + } + }); + } + + monaco.languages.register({ id: 'ruby' }); + MonacoAceTokenizer.registerRulesForLanguage('ruby', new RubyDefinition.default); + monaco.languages.setLanguageConfiguration('ruby', { + comments: { + lineComment: '#', + blockComment: ['=begin', '=end'], + }, + brackets: [ + ['(', ')'], + ['{', '}'], + ['[', ']'] + ], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: '\'', close: '\'' }, + ], + surroundingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: '\'', close: '\'' }, + ], + indentationRules: { + increaseIndentPattern: new RegExp('^\\s*((begin|class|(private|protected)\\s+def|def|else|elsif|ensure|for|if|module|rescue|unless|until|when|while|case)|([^#]*\\sdo\\b)|([^#]*=\\s*(case|if|unless)))\\b([^#\\{;]|("|\'|\/).*\\4)*(#.*)?$'), + decreaseIndentPattern: new RegExp('^\\s*([}\\]]([,)]?\\s*(#|$)|\\.[a-zA-Z_]\\w*\\b)|(end|rescue|ensure|else|elsif|when)\\b)'), + } + }); + + var markdownAliases = ['markdown', 'md']; + for (var i in markdownAliases) { + var alias = markdownAliases[i]; + + monaco.languages.register({ id: alias }); + monaco.languages.setLanguageConfiguration(alias, { + comments: { + blockComment: ['',] + }, + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'] + ], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '<', close: '>', notIn: ['string'] } + ], + surroundingPairs: [ + { open: '(', close: ')' }, + { open: '[', close: ']' }, + { open: '`', close: '`' }, + ], + folding: { + markers: { + start: new RegExp("^\\s*"), + end: new RegExp("^\\s*") + } + } + }); + monaco.languages.setMonarchTokensProvider(alias, { + defaultToken: '', + tokenPostfix: '.md', + + // escape codes + control: /[\\`*_\[\]{}()#+\-\.!\$]/, + noncontrol: /[^\\`*_\[\]{}()#+\-\.!\$]/, + escapes: /\\(?:@control)/, + + // escape codes for javascript/CSS strings + jsescapes: /\\(?:[btnfr\\"']|[0-7][0-7]?|[0-3][0-7]{2})/, + + // non matched elements + empty: [ + 'area', 'base', 'basefont', 'br', 'col', 'frame', + 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param' + ], + + tokenizer: { + root: [ + + // headers (with #) + [/^(\s{0,3})(#+)((?:[^\\#]|@escapes)+)((?:#+)?)/, ['white', 'keyword', 'keyword', 'keyword']], + + // headers (with =) + [/^\s*(=+|\-+)\s*$/, 'keyword'], + + // headers (with ***) + [/^\s*((\*[ ]?)+)\s*$/, 'meta.separator'], + + // quote + [/^\s*>+/, 'comment'], + + // list (starting with * or number) + [/^\s*([\*\-+:]|\d+\.)\s/, 'keyword'], + + // code block (4 spaces indent) + [/^(\t|[ ]{4})[^ ].*$/, 'string'], + + // code block (3 tilde) + [/^\s*~~~\s*((?:\w|[\/\-#])+)?\s*$/, { token: 'string', next: '@codeblock' }], + + // display math + [/\$\$/, { token: 'string', next: '@displaymath' }], + + // github style code blocks (with backticks and language) + [/^\s*```\s*((?:\w|[\/\-#\+])+)\s*$/, { token: 'string', next: '@codeblockgh', nextEmbedded: '$1' }], + + // github style code blocks (with backticks but no language) + [/^\s*```\s*$/, { token: 'string', next: '@codeblock' }], + + // markup within lines + { include: '@linecontent' }, + ], + + displaymath: [ + [/\\\$/, 'variable.source'], + [/\$\$/, { token: 'string', next: '@pop' }], + [/./, 'variable.source'] + ], + + codeblock: [ + [/^\s*~~~\s*$/, { token: 'string', next: '@pop' }], + [/^\s*```\s*$/, { token: 'string', next: '@pop' }], + [/.*$/, 'variable.source'], + ], + + // github style code blocks + codeblockgh: [ + [/```\s*$/, { token: 'variable.source', next: '@pop', nextEmbedded: '@pop' }], + [/[^`]+/, 'variable.source'], + ], + + linecontent: [ + + // inline math + [/\$/, { token: 'string', next: '@inlinemath' }], + + // escapes + [/&\w+;/, 'string.escape'], + [/@escapes/, 'escape'], + + // various markup + [/\b__([^\\_]|@escapes|_(?!_))+__\b/, 'strong'], + [/\*\*([^\\*]|@escapes|\*(?!\*))+\*\*/, 'strong'], + [/\b_[^_]+_\b/, 'emphasis'], + [/\*([^\\*]|@escapes)+\*/, 'emphasis'], + [/`([^\\`]|@escapes)+`/, 'variable'], + + // links + [/\{+[^}]+\}+/, 'string.target'], + [/(!?\[)((?:[^\]\\]|@escapes)*)(\]\([^\)]+\))/, ['string.link', '', 'string.link']], + [/(!?\[)((?:[^\]\\]|@escapes)*)(\])/, 'string.link'], + + // or html + { include: 'html' }, + ], + + inlinemath: [ + [/\\\$/, 'variable.source'], + [/\$/, { token: 'string', next: '@pop' }], + [/./, 'variable.source'] + ], + + // Note: it is tempting to rather switch to the real HTML mode instead of building our own here + // but currently there is a limitation in Monarch that prevents us from doing it: The opening + // '<' would start the HTML mode, however there is no way to jump 1 character back to let the + // HTML mode also tokenize the opening angle bracket. Thus, even though we could jump to HTML, + // we cannot correctly tokenize it in that mode yet. + html: [ + // html tags + [/<(\w+)\/>/, 'tag'], + [/<(\w+)/, { + cases: { + '@empty': { token: 'tag', next: '@tag.$1' }, + '@default': { token: 'tag', next: '@tag.$1' } + } + }], + [/<\/(\w+)\s*>/, { token: 'tag' }], + + [//, 'comment', '@pop'], + [/ + + + + +<% +this.showLoadingEditor = () => { +%> +
编辑器加载中 …
+<% +}; +%> diff --git a/views/problem.ejs b/views/problem.ejs index dcecb52..e29c0c7 100644 --- a/views/problem.ejs +++ b/views/problem.ejs @@ -241,15 +241,17 @@ if (contest) {
-
+
<% for (let i = 0; i < cases.length; i++) { %> -
+
+ <%- this.showLoadingEditor(); %> +
<% } %>
<% } %> @@ -258,7 +260,7 @@ if (contest) { window.onEditorLoaded(function () { window.editors = []; for (var i = 0; i < cases.length; i++) { - var editor = window.createEditor(document.getElementById("editor-" + i)); + var editor = window.createCodeEditor(document.getElementById("editor-" + i)); editors[i] = editor; } @@ -305,15 +307,17 @@ if (contest) { } else if (lastLanguage) language = lastLanguage; %> <% for (lang of syzoj.config.enabled_languages) { %> - + <%= syzoj.languages[lang].show %>
<%= syzoj.languages[lang].version %>
<% } %>
-
-
+
+
+ <%- this.showLoadingEditor(); %> +
@@ -341,7 +345,7 @@ if (contest) { var editorElement = document.getElementById('editor'); var content = ''; <% if (state) { %>content = <%- serializejs(state.code) %>;<% } %> - editor = window.createEditor(editorElement, 'ace_' + $('#languages-menu .item.active').data('mode'), content); + editor = window.createCodeEditor(editorElement, $('#languages-menu .item.active').data('mode'), content); window.editor = editor; }); @@ -366,7 +370,7 @@ if (contest) { .not($(this)) .removeClass('active') ; - monaco.editor.setModelLanguage(editor.getModel(), 'ace_' + $(this).data('mode')); + monaco.editor.setModelLanguage(editor.getModel(), $(this).data('mode')); }); }); diff --git a/views/problem_edit.ejs b/views/problem_edit.ejs index 3658478..ab7d1bd 100644 --- a/views/problem_edit.ejs +++ b/views/problem_edit.ejs @@ -5,14 +5,15 @@ text-align: center; } +<% include monaco-editor %>
-
+
-
+
<% if (problem.allowedManage) { %>
+
+ <%- this.showLoadingEditor(); %> +
+ +
+ + +
+
+ <%- this.showLoadingEditor(); %> +
+ +
+ + +
+
+ <%- this.showLoadingEditor(); %> +
+ +
+ + +
+
+ <%- this.showLoadingEditor(); %> +
+ +
+ + +
+
+ <%- this.showLoadingEditor(); %> +
+ +
+