算法评测平台前端。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

667 lines
23 KiB

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)|(?:<editor-fold\\b))"),
end: new RegExp("^\\s*//\\s*(?:(?:#?endregion\\b)|(?:</editor-fold>))")
}
}
});
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*<!--\\s*#?region\\b.*-->"),
end: new RegExp("^\\s*<!--\\s*#?endregion\\b.*-->")
}
}
});
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', '@comment']
],
comment: [
[/[^<\-]+/, 'comment.content'],
[/-->/, 'comment', '@pop'],
[/<!--/, 'comment.content.invalid'],
[/[<\-]/, 'comment.content']
],
// Almost full HTML tag matching, complete with embedded scripts & styles
tag: [
[/[ \t\r\n]+/, 'white'],
[/(type)(\s*=\s*)(")([^"]+)(")/, ['attribute.name.html', 'delimiter.html', 'string.html',
{ token: 'string.html', switchTo: '@tag.$S2.$4' },
'string.html']],
[/(type)(\s*=\s*)(')([^']+)(')/, ['attribute.name.html', 'delimiter.html', 'string.html',
{ token: 'string.html', switchTo: '@tag.$S2.$4' },
'string.html']],
[/(\w+)(\s*=\s*)("[^"]*"|'[^']*')/, ['attribute.name.html', 'delimiter.html', 'string.html']],
[/\w+/, 'attribute.name.html'],
[/\/>/, 'tag', '@pop'],
[/>/, {
cases: {
'$S2==style': { token: 'tag', switchTo: 'embeddedStyle', nextEmbedded: 'text/css' },
'$S2==script': {
cases: {
'$S3': { token: 'tag', switchTo: 'embeddedScript', nextEmbedded: '$S3' },
'@default': { token: 'tag', switchTo: 'embeddedScript', nextEmbedded: 'text/javascript' }
}
},
'@default': { token: 'tag', next: '@pop' }
}
}],
],
embeddedStyle: [
[/[^<]+/, ''],
[/<\/style\s*>/, { token: '@rematch', next: '@pop', nextEmbedded: '@pop' }],
[/</, '']
],
embeddedScript: [
[/[^<]+/, ''],
[/<\/script\s*>/, { token: '@rematch', next: '@pop', nextEmbedded: '@pop' }],
[/</, '']
],
}
});
}
$.getScript(window.pathSelfLib + "monaco-editor-tomorrow.js", function () {
window.createCodeEditor = function (editorElement, langauge, content) {
editorElement.innerHTML = '';
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', 'Source Han Sans SC', 'Noto Sans CJK SC', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft Yahei', monospace",
lineNumbersMinChars: 4,
glyphMargin: false,
renderFinalNewline: true,
scrollbar: {
useShadows: false,
verticalScrollbarSize: 0,
vertical: 'hidden'
},
overviewRulerBorder: false,
hideCursorInOverviewRuler: true,
contextmenu: false
});
};
window.createMarkdownEditor = function (wrapperElement, content, input) {
wrapperElement.innerHTML = '';
var editorElement = document.createElement('div');
editorElement.classList.add('editor-wrapped');
wrapperElement.appendChild(editorElement);
var editor = monaco.editor.create(editorElement, {
value: content,
language: 'markdown',
multicursorModifier: 'ctrlCmd',
cursorWidth: 1,
theme: 'tomorrow',
fontSize: 14,
fontFamily: "'Fira Mono', 'Source Han Sans SC', 'Noto Sans CJK SC', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft Yahei', monospace",
lineNumbersMinChars: 4,
glyphMargin: false,
lineNumbers: false,
folding: false,
minimap: {
enabled: false
},
hover: {
enabled: false
},
wordWrap: "on",
renderIndentGuides: false,
renderFinalNewline: false,
wordBasedSuggestions: false,
renderLineHighlight: false,
occurrencesHighlight: false,
scrollbar: {
useShadows: false,
vertical: 'auto',
verticalScrollbarSize: 10
},
overviewRulerBorder: false,
hideCursorInOverviewRuler: true,
contextmenu: false
});
input.form.addEventListener('submit', function () {
input.value = editor.getValue();
});
return editor;
};
window.editorLoaded = true;
for (var i in window.editorLoadedHandles) {
window.editorLoadedHandles[i]();
}
});
}
);
});