From fae452cc940504c1efd40eadf507a293fc9ea9ed Mon Sep 17 00:00:00 2001 From: undefined Date: Mon, 13 Sep 2021 21:07:16 +0800 Subject: [PATCH] ui: quick emoji input support --- .../ui-default/components/editor/index.js | 5 +- .../ui-default/components/monaco/index.js | 108 +------------- .../components/monaco/languages/markdown.ts | 138 ++++++++++++++++++ .../components/monaco/languages/typescript.ts | 17 +++ .../components/monaco/languages/yaml.ts | 91 ++++++++++++ packages/ui-default/package.json | 4 +- 6 files changed, 255 insertions(+), 108 deletions(-) create mode 100644 packages/ui-default/components/monaco/languages/markdown.ts create mode 100644 packages/ui-default/components/monaco/languages/typescript.ts create mode 100644 packages/ui-default/components/monaco/languages/yaml.ts diff --git a/packages/ui-default/components/editor/index.js b/packages/ui-default/components/editor/index.js index 3fe2f9ccb..b4f102b87 100644 --- a/packages/ui-default/components/editor/index.js +++ b/packages/ui-default/components/editor/index.js @@ -55,8 +55,7 @@ export default class Editor extends DOMAttachedObject { // eslint-disable-next-line no-nested-ternary this.model = typeof model === 'string' ? monaco.editor.getModel(monaco.Uri.parse(model)) - ? monaco.editor.getModel(monaco.Uri.parse(model)) - : monaco.editor.createModel(value, language, monaco.Uri.parse(model)) + || monaco.editor.createModel(value, language, monaco.Uri.parse(model)) : model; this.model.setValue(value); this.model.updateOptions({ language }); @@ -111,6 +110,8 @@ export default class Editor extends DOMAttachedObject { this.isValid = true; if (hasFocus) this.focus(); if (autoResize) updateEditorHeight(); + window.model = this.model; + window.editor = this.editor; } async initVditor() { diff --git a/packages/ui-default/components/monaco/index.js b/packages/ui-default/components/monaco/index.js index deb89fe3b..eff002523 100644 --- a/packages/ui-default/components/monaco/index.js +++ b/packages/ui-default/components/monaco/index.js @@ -1,111 +1,9 @@ import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'; import loadFormatter from 'vj/components/wastyle/index'; import Notification from 'vj/components/notification'; - -monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({ - noSemanticValidation: false, - noSyntaxValidation: false, -}); -monaco.languages.typescript.javascriptDefaults.setCompilerOptions({ - target: monaco.languages.typescript.ScriptTarget.ES6, - allowNonTsExtensions: true, -}); -const libSource = [ - 'declare function readline(): string;', - 'declare function print(content: string): void;', -].join('\n'); -const libUri = 'ts:filename/basic.d.ts'; -monaco.languages.typescript.javascriptDefaults.addExtraLib(libSource, libUri); -monaco.editor.createModel(libSource, 'typescript', monaco.Uri.parse(libUri)); - -/** @type {Record} */ -const problemConfigSchemaDef = { - cases: { type: 'array', items: { $ref: '#/def/case' } }, - case: { - type: 'object', - properties: { - input: { type: 'string' }, - output: { type: 'string' }, - }, - required: ['input'], - additionalProperties: false, - }, - subtask: { - description: 'Subtask Info', - type: 'object', - properties: { - type: { enum: ['min', 'max', 'sum'] }, - time: { $ref: '#/def/time' }, - memory: { $ref: '#/def/memory' }, - score: { $ref: '#/def/score', description: 'score' }, - cases: { $ref: '#/def/cases' }, - if: { type: 'array', items: { type: 'integer' } }, - id: { type: 'integer' }, - }, - required: ['score'], - additionalProperties: false, - }, - time: { type: 'string', pattern: '^([0-9]+(?:\\.[0-9]*)?)([mu]?)s?$' }, - memory: { type: 'string', pattern: '^([0-9]+(?:\\.[0-9]*)?)([kmg])b?$' }, - score: { type: 'integer', maximum: 100, minimum: 1 }, -}; - -/** @type {import('json-schema').JSONSchema7Definition} */ -const problemConfigSchema = { - type: 'object', - def: problemConfigSchemaDef, - properties: { - key: { type: 'string', pattern: '[0-9a-f]{32}' }, - type: { enum: ['default', 'interactive', 'submit_answer', 'objective', 'remote_judge'] }, - subType: { type: 'string' }, - langs: { type: 'array', items: { type: 'string' } }, - target: { type: 'string' }, - checker_type: { enum: ['default', 'lemon', 'syzoj', 'hustoj', 'testlib', 'strict', 'qduoj'] }, - checker: { type: 'string', pattern: '\\.' }, - interactor: { type: 'string', pattern: '\\.' }, - user_extra_files: { type: 'array', items: { type: 'string' } }, - judge_extra_files: { type: 'array', items: { type: 'string' } }, - cases: { $ref: '#/def/cases' }, - subtasks: { type: 'array', items: { $ref: '#/def/subtask' } }, - filename: { type: 'string' }, - detail: { type: 'boolean' }, - time: { $ref: '#/def/time' }, - memory: { $ref: '#/def/memory' }, - score: { $ref: '#/def/score' }, - template: { - type: 'object', - patternProperties: { - '^.*$': { - type: 'array', - minLength: 2, - maxLength: 2, - items: { type: 'string' }, - }, - }, - additionalProperties: false, - }, - outputs: { - type: 'array', - minLength: 1, - }, - }, - additionalProperties: false, -}; - -monaco.languages.yaml.yamlDefaults.setDiagnosticsOptions({ - validate: true, - enableSchemaRequest: true, - hover: true, - completion: true, - format: true, - schemas: [ - { - uri: 'https://hydro.js.org/schema/problemConfig.json', - fileMatch: ['hydro://problem/file/config.yaml'], - schema: problemConfigSchema, - }, - ], -}); +import './languages/markdown'; +import './languages/typescript'; +import './languages/yaml'; export default monaco; diff --git a/packages/ui-default/components/monaco/languages/markdown.ts b/packages/ui-default/components/monaco/languages/markdown.ts new file mode 100644 index 000000000..fe751d45c --- /dev/null +++ b/packages/ui-default/components/monaco/languages/markdown.ts @@ -0,0 +1,138 @@ +import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'; +import list from 'emojis-list'; +import keyword from 'emojis-keywords'; + +const qqEmojies = [ + 'weixiao', + 'piezui', + 'se', + 'fadai', + 'deyi', + 'liulei', + 'haixiu', + 'bizui', + 'shui', + 'daku', + 'ganga', + 'fanu', + 'tiaopi', + 'ciya', + 'jingya', + 'nanguo', + 'ku', + 'lenghan', + 'zhuakuang', + 'tu', + 'touxiao', + 'keai', + 'baiyan', + 'aoman', + 'jie', + 'kun', + 'jingkong', + 'liuhan', + 'hanxiao', + 'dabing', + 'fendou', + 'zhouma', + 'yiwen', + 'xu', + 'yun', + 'zhemo', + 'shuai', + 'kulou', + 'qiaoda', + 'zaijian', + 'cahan', + 'koubi', + 'guzhang', + 'qiudale', + 'huaixiao', + 'zuohengheng', + 'youhengheng', + 'haqian', + 'bishi', + 'weiqu', + 'kuaikule', + 'yinxian', + 'qinqin', + 'xia', + 'kelian', + 'caidao', + 'xigua', + 'pijiu', + 'lanqiu', + 'pingpang', + 'kafei', + 'fan', + 'zhutou', + 'meigui', + 'diaoxie', + 'shiai', + 'aixin', + 'xinsui', + 'dangao', + 'shandian', + 'zhadan', + 'dao', + 'zuqiu', + 'piaochong', + 'bianbian', + 'yueliang', + 'taiyang', + 'liwu', + 'yongbao', + 'qiang', + 'ruo', + 'woshou', + 'shengli', + 'baoquan', + 'gouyin', + 'quantou', + 'chajin', + 'aini', + 'no', + 'ok', +]; + +function emoji(range) { + return keyword.map((i, index) => ({ + label: `${list[index]} ${i}`, + kind: monaco.languages.CompletionItemKind.Keyword, + documentation: i, + insertText: list[index], + range, + })); +} + +function qqEmoji(range) { + return qqEmojies.map((i, index) => ({ + label: `/${i}`, + kind: monaco.languages.CompletionItemKind.Keyword, + documentation: `/${i}`, + insertText: `![${i}](//qq-face.vercel.app/gif/s${index}.gif =32x32) `, + range, + })); +} + +monaco.languages.registerCompletionItemProvider('markdown', { + provideCompletionItems(model, position) { + const word = model.getWordAtPosition(position); + const prefix = model.getValueInRange({ + startLineNumber: position.lineNumber, + endLineNumber: position.lineNumber, + startColumn: word.startColumn - 1, + endColumn: position.column - 1, + }); + if (![':', '/'].includes(prefix)) return { suggestions: [] }; + const range = { + startLineNumber: position.lineNumber, + endLineNumber: position.lineNumber, + startColumn: word.startColumn - 1, + endColumn: word.endColumn, + }; + return { + suggestions: prefix === ':' ? emoji(range) : qqEmoji(range), + }; + }, +}); diff --git a/packages/ui-default/components/monaco/languages/typescript.ts b/packages/ui-default/components/monaco/languages/typescript.ts new file mode 100644 index 000000000..827c05b56 --- /dev/null +++ b/packages/ui-default/components/monaco/languages/typescript.ts @@ -0,0 +1,17 @@ +import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'; + +monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions({ + noSemanticValidation: false, + noSyntaxValidation: false, +}); +monaco.languages.typescript.javascriptDefaults.setCompilerOptions({ + target: monaco.languages.typescript.ScriptTarget.ES2020, + allowNonTsExtensions: true, +}); +const libSource = [ + 'declare function readline(): string;', + 'declare function print(content: string): void;', +].join('\n'); +const libUri = 'ts:filename/basic.d.ts'; +monaco.languages.typescript.javascriptDefaults.addExtraLib(libSource, libUri); +monaco.editor.createModel(libSource, 'typescript', monaco.Uri.parse(libUri)); diff --git a/packages/ui-default/components/monaco/languages/yaml.ts b/packages/ui-default/components/monaco/languages/yaml.ts new file mode 100644 index 000000000..65d2ec6bc --- /dev/null +++ b/packages/ui-default/components/monaco/languages/yaml.ts @@ -0,0 +1,91 @@ +import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'; + +/** @type {Record} */ +const problemConfigSchemaDef = { + cases: { type: 'array', items: { $ref: '#/def/case' } }, + case: { + type: 'object', + properties: { + input: { type: 'string' }, + output: { type: 'string' }, + }, + required: ['input'], + additionalProperties: false, + }, + subtask: { + description: 'Subtask Info', + type: 'object', + properties: { + type: { enum: ['min', 'max', 'sum'] }, + time: { $ref: '#/def/time' }, + memory: { $ref: '#/def/memory' }, + score: { $ref: '#/def/score', description: 'score' }, + cases: { $ref: '#/def/cases' }, + if: { type: 'array', items: { type: 'integer' } }, + id: { type: 'integer' }, + }, + required: ['score'], + additionalProperties: false, + }, + time: { type: 'string', pattern: '^([0-9]+(?:\\.[0-9]*)?)([mu]?)s?$' }, + memory: { type: 'string', pattern: '^([0-9]+(?:\\.[0-9]*)?)([kmg])b?$' }, + score: { type: 'integer', maximum: 100, minimum: 1 }, +}; + +/** @type {import('json-schema').JSONSchema7Definition} */ +const problemConfigSchema = { + type: 'object', + def: problemConfigSchemaDef, + properties: { + key: { type: 'string', pattern: '[0-9a-f]{32}' }, + type: { enum: ['default', 'interactive', 'submit_answer', 'objective', 'remote_judge'] }, + subType: { type: 'string' }, + langs: { type: 'array', items: { type: 'string' } }, + target: { type: 'string' }, + checker_type: { enum: ['default', 'lemon', 'syzoj', 'hustoj', 'testlib', 'strict', 'qduoj'] }, + checker: { type: 'string', pattern: '\\.' }, + interactor: { type: 'string', pattern: '\\.' }, + user_extra_files: { type: 'array', items: { type: 'string' } }, + judge_extra_files: { type: 'array', items: { type: 'string' } }, + cases: { $ref: '#/def/cases' }, + subtasks: { type: 'array', items: { $ref: '#/def/subtask' } }, + filename: { type: 'string' }, + detail: { type: 'boolean' }, + time: { $ref: '#/def/time' }, + memory: { $ref: '#/def/memory' }, + score: { $ref: '#/def/score' }, + template: { + type: 'object', + patternProperties: { + '^.*$': { + type: 'array', + minLength: 2, + maxLength: 2, + items: { type: 'string' }, + }, + }, + additionalProperties: false, + }, + outputs: { + type: 'array', + minLength: 1, + }, + }, + additionalProperties: false, +}; + +// @ts-ignore +monaco.languages.yaml.yamlDefaults.setDiagnosticsOptions({ + validate: true, + enableSchemaRequest: true, + hover: true, + completion: true, + format: true, + schemas: [ + { + uri: 'https://hydro.js.org/schema/problemConfig.json', + fileMatch: ['hydro://problem/file/config.yaml'], + schema: problemConfigSchema, + }, + ], +}); diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index 11ba1549a..871e1b849 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -1,6 +1,6 @@ { "name": "@hydrooj/ui-default", - "version": "4.20.1", + "version": "4.20.2", "author": "undefined ", "license": "AGPL-3.0", "main": "hydro.js", @@ -32,6 +32,8 @@ "diff-dom": "^4.2.2", "echarts": "^5.2.0", "emojify.js": "^1.1.0", + "emojis-keywords": "2.0.0", + "emojis-list": "2.1.0", "esbuild-loader": "^2.15.1", "eslint": "^7.32.0", "eslint-config-airbnb": "^18.2.1",