mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
ui: monaco: use monaco-vscode-api
This commit is contained in:
11 files changed
+280
-461
No files matched your search
@@ -5,7 +5,6 @@ import CopyWebpackPlugin from 'copy-webpack-plugin';
|
|||||||
import { EsbuildPlugin } from 'esbuild-loader';
|
import { EsbuildPlugin } from 'esbuild-loader';
|
||||||
import { DuplicatesPlugin } from 'inspectpack/plugin';
|
import { DuplicatesPlugin } from 'inspectpack/plugin';
|
||||||
import ExtractCssPlugin from 'mini-css-extract-plugin';
|
import ExtractCssPlugin from 'mini-css-extract-plugin';
|
||||||
import MonacoWebpackPlugin from 'monaco-editor-webpack-plugin';
|
|
||||||
import { dirname } from 'path';
|
import { dirname } from 'path';
|
||||||
import webpack from 'webpack';
|
import webpack from 'webpack';
|
||||||
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
||||||
@@ -14,17 +13,6 @@ import WebpackBar from 'webpackbar';
|
|||||||
import root from '../utils/root';
|
import root from '../utils/root';
|
||||||
|
|
||||||
export default function (env: { watch?: boolean, production?: boolean, measure?: boolean } = {}) {
|
export default function (env: { watch?: boolean, production?: boolean, measure?: boolean } = {}) {
|
||||||
function esbuildLoader() {
|
|
||||||
return {
|
|
||||||
loader: 'esbuild-loader',
|
|
||||||
options: {
|
|
||||||
loader: 'tsx',
|
|
||||||
target: 'es2015',
|
|
||||||
sourcemap: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function cssLoader() {
|
function cssLoader() {
|
||||||
return {
|
return {
|
||||||
loader: 'css-loader',
|
loader: 'css-loader',
|
||||||
@@ -97,10 +85,14 @@ export default function (env: { watch?: boolean, production?: boolean, measure?:
|
|||||||
chunkFilename: '[name].[chunkhash:6].chunk.js',
|
chunkFilename: '[name].[chunkhash:6].chunk.js',
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.js', '.jsx', '.ts', '.tsx', '.cjs'],
|
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||||
alias: {
|
alias: {
|
||||||
vj: root(),
|
vj: root(),
|
||||||
},
|
},
|
||||||
|
fallback: {
|
||||||
|
url: require.resolve('url/'),
|
||||||
|
util: require.resolve('util/'),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
@@ -153,14 +145,7 @@ export default function (env: { watch?: boolean, production?: boolean, measure?:
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.[mc]?[jt]sx?$/,
|
test: /\.m?(jsx|tsx|ts)?$/,
|
||||||
exclude: [/@types\//, /components\/message\//, /entry\.js/],
|
|
||||||
type: 'javascript/auto',
|
|
||||||
use: [esbuildLoader()],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.[mc]?[jt]sx?$/,
|
|
||||||
include: [/components\/message\//, /entry\.js/],
|
|
||||||
type: 'javascript/auto',
|
type: 'javascript/auto',
|
||||||
use: [{
|
use: [{
|
||||||
loader: 'ts-loader',
|
loader: 'ts-loader',
|
||||||
@@ -185,6 +170,7 @@ export default function (env: { watch?: boolean, production?: boolean, measure?:
|
|||||||
},
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
splitChunks: {
|
splitChunks: {
|
||||||
|
chunks: 'async',
|
||||||
minSize: 256000,
|
minSize: 256000,
|
||||||
maxAsyncRequests: 5,
|
maxAsyncRequests: 5,
|
||||||
maxInitialRequests: 3,
|
maxInitialRequests: 3,
|
||||||
@@ -198,12 +184,15 @@ export default function (env: { watch?: boolean, production?: boolean, measure?:
|
|||||||
enforce: true,
|
enforce: true,
|
||||||
},
|
},
|
||||||
vendors: {
|
vendors: {
|
||||||
test: /[\\/]node_modules[\\/].+\.([jt]sx?|json|yaml)$/,
|
test: /[\\/]node_modules[\\/].+\.([jt]sx?|json|yaml|txt|mp3|md)$/,
|
||||||
priority: -10,
|
priority: -10,
|
||||||
name(module) {
|
name(module) {
|
||||||
const packageName = module.context.replace(/\\/g, '/').split('node_modules/').pop().split('/')[0];
|
const packageName = module.context.replace(/\\/g, '/').split('node_modules/').pop().split('/')[0];
|
||||||
if (packageName === 'monaco-editor-nls') {
|
if (packageName.startsWith('@codingame')) {
|
||||||
return `i.monaco.${module.userRequest.replace(/\\/g, '/').split('/').pop().split('.')[0]}`;
|
const subName = module.context.replace(/\\/g, '/').split('node_modules/').pop().split('/')[1];
|
||||||
|
if (subName.startsWith('monaco-vscode-language-pack-')) {
|
||||||
|
return `i.${subName.split('pack-').pop()}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return `n.${packageName.replace('@', '')}`;
|
return `n.${packageName.replace('@', '')}`;
|
||||||
},
|
},
|
||||||
@@ -239,7 +228,6 @@ export default function (env: { watch?: boolean, production?: boolean, measure?:
|
|||||||
jQuery: 'jquery',
|
jQuery: 'jquery',
|
||||||
'window.jQuery': 'jquery',
|
'window.jQuery': 'jquery',
|
||||||
React: 'react',
|
React: 'react',
|
||||||
monaco: 'monaco-editor/esm/vs/editor/editor.api',
|
|
||||||
}),
|
}),
|
||||||
new ExtractCssPlugin({
|
new ExtractCssPlugin({
|
||||||
filename: '[name].css?[fullhash:6]',
|
filename: '[name].css?[fullhash:6]',
|
||||||
@@ -257,31 +245,26 @@ export default function (env: { watch?: boolean, production?: boolean, measure?:
|
|||||||
{ from: `${dirname(require.resolve('monaco-themes/package.json'))}/themes`, to: 'monaco/themes/' },
|
{ from: `${dirname(require.resolve('monaco-themes/package.json'))}/themes`, to: 'monaco/themes/' },
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
sentryWebpackPlugin({
|
|
||||||
authToken: process.env.SENTRY_AUTH_TOKEN,
|
|
||||||
org: 'hydro-dev',
|
|
||||||
project: 'hydro-web',
|
|
||||||
url: 'https://sentry.hydro.ac',
|
|
||||||
}),
|
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env.VERSION': JSON.stringify(require('@hydrooj/ui-default/package.json').version),
|
'process.env.VERSION': JSON.stringify(require('@hydrooj/ui-default/package.json').version),
|
||||||
}),
|
}),
|
||||||
new webpack.optimize.MinChunkSizePlugin({
|
new webpack.optimize.MinChunkSizePlugin({
|
||||||
minChunkSize: 128000,
|
minChunkSize: 128000,
|
||||||
}),
|
}),
|
||||||
new webpack.NormalModuleReplacementPlugin(/\/(vscode-)?nls\.js/, require.resolve('../../components/monaco/nls')),
|
new webpack.NormalModuleReplacementPlugin(/^node:/, (r) => { r.request = r.request.replace(/^node:/, ''); }),
|
||||||
new webpack.NormalModuleReplacementPlugin(/^prettier[$/]/, root('../../modules/nop.ts')),
|
new webpack.NormalModuleReplacementPlugin(/^prettier[$/]/, root('../../modules/nop.ts')),
|
||||||
new MonacoWebpackPlugin({
|
new webpack.NormalModuleReplacementPlugin(
|
||||||
filename: '[name].[hash:6].worker.js',
|
/@codingame\/monaco-vscode-(css|fsharp|html|groovy|scss|xml)-default-extension/,
|
||||||
customLanguages: [{
|
root('../../modules/nop.ts'),
|
||||||
label: 'yaml',
|
),
|
||||||
entry: require.resolve('monaco-yaml/index.js'),
|
...(env.production ? [
|
||||||
worker: {
|
sentryWebpackPlugin({
|
||||||
id: 'vs/language/yaml/yamlWorker',
|
authToken: process.env.SENTRY_AUTH_TOKEN,
|
||||||
entry: require.resolve('monaco-yaml/yaml.worker.js'),
|
org: 'hydro-dev',
|
||||||
},
|
project: 'hydro-web',
|
||||||
}],
|
url: 'https://sentry.hydro.ac',
|
||||||
}),
|
}),
|
||||||
|
] : []),
|
||||||
...env.measure ? [
|
...env.measure ? [
|
||||||
new BundleAnalyzerPlugin({ analyzerPort: 'auto' }),
|
new BundleAnalyzerPlugin({ analyzerPort: 'auto' }),
|
||||||
new DuplicatesPlugin(),
|
new DuplicatesPlugin(),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
import type { editor } from 'monaco-editor';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import DOMAttachedObject from 'vj/components/DOMAttachedObject';
|
import DOMAttachedObject from 'vj/components/DOMAttachedObject';
|
||||||
import Notification from 'vj/components/notification';
|
import Notification from 'vj/components/notification';
|
||||||
@@ -49,8 +50,8 @@ type Options = MonacoOptions & VditorOptions;
|
|||||||
|
|
||||||
export default class Editor extends DOMAttachedObject {
|
export default class Editor extends DOMAttachedObject {
|
||||||
static DOMAttachKey = 'vjEditorInstance';
|
static DOMAttachKey = 'vjEditorInstance';
|
||||||
model: import('../monaco').default.editor.IModel;
|
model: editor.IModel;
|
||||||
editor: import('../monaco').default.editor.IStandaloneCodeEditor;
|
editor: editor.IStandaloneCodeEditor;
|
||||||
vditor: import('vditor').default;
|
vditor: import('vditor').default;
|
||||||
isValid: boolean;
|
isValid: boolean;
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ export default class Editor extends DOMAttachedObject {
|
|||||||
autoResize = true, autoLayout = true,
|
autoResize = true, autoLayout = true,
|
||||||
hide = [], lineNumbers = 'on',
|
hide = [], lineNumbers = 'on',
|
||||||
} = this.options;
|
} = this.options;
|
||||||
const { monaco, registerAction } = await load([language]);
|
const { monaco } = await load([language]);
|
||||||
const { $dom } = this;
|
const { $dom } = this;
|
||||||
const hasFocus = $dom.is(':focus') || $dom.hasClass('autofocus');
|
const hasFocus = $dom.is(':focus') || $dom.hasClass('autofocus');
|
||||||
const origin = $dom.get(0);
|
const origin = $dom.get(0);
|
||||||
@@ -85,7 +86,7 @@ export default class Editor extends DOMAttachedObject {
|
|||||||
|| monaco.editor.createModel(value, language === 'auto' ? undefined : language, monaco.Uri.parse(model))
|
|| monaco.editor.createModel(value, language === 'auto' ? undefined : language, monaco.Uri.parse(model))
|
||||||
: model;
|
: model;
|
||||||
if (!this.options.model) this.model.setValue(value);
|
if (!this.options.model) this.model.setValue(value);
|
||||||
const cfg: import('../monaco').default.editor.IStandaloneEditorConstructionOptions = {
|
const cfg: editor.IStandaloneEditorConstructionOptions = {
|
||||||
theme,
|
theme,
|
||||||
lineNumbers,
|
lineNumbers,
|
||||||
glyphMargin: true,
|
glyphMargin: true,
|
||||||
@@ -146,7 +147,7 @@ export default class Editor extends DOMAttachedObject {
|
|||||||
}
|
}
|
||||||
this.editor.deltaDecorations([], ranges.map((range) => ({ range, options: { inlineClassName: 'decoration-hide' } })));
|
this.editor.deltaDecorations([], ranges.map((range) => ({ range, options: { inlineClassName: 'decoration-hide' } })));
|
||||||
}
|
}
|
||||||
registerAction(this.editor, this.model, this.$dom);
|
// registerAction(this.editor, this.model, this.$dom);
|
||||||
if (autoResize) {
|
if (autoResize) {
|
||||||
this.editor.onDidChangeModelDecorations(() => {
|
this.editor.onDidChangeModelDecorations(() => {
|
||||||
updateEditorHeight(); // typing
|
updateEditorHeight(); // typing
|
||||||
|
|||||||
@@ -1,176 +0,0 @@
|
|||||||
import './monaco.styl';
|
|
||||||
|
|
||||||
import $ from 'jquery';
|
|
||||||
import { EditorAction, registerEditorAction } from 'monaco-editor/esm/vs/editor/browser/editorExtensions';
|
|
||||||
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
|
|
||||||
import { IQuickInputService } from 'monaco-editor/esm/vs/platform/quickinput/common/quickInput';
|
|
||||||
import list from 'monaco-themes/themes/themelist.json';
|
|
||||||
import { nanoid } from 'nanoid';
|
|
||||||
import { i18n, request } from 'vj/utils';
|
|
||||||
|
|
||||||
export default monaco;
|
|
||||||
export const customOptions: monaco.editor.IStandaloneDiffEditorConstructionOptions = JSON.parse(localStorage.getItem('editor.config') || '{}');
|
|
||||||
export function saveCustomOptions() {
|
|
||||||
localStorage.setItem('editor.config', JSON.stringify(customOptions));
|
|
||||||
}
|
|
||||||
|
|
||||||
const loaded = {};
|
|
||||||
async function fetchTheme(id: string, label: string) {
|
|
||||||
if (loaded[id]) return;
|
|
||||||
const res = await fetch(`${UiContext.cdn_prefix}monaco/themes/${label}.json`);
|
|
||||||
const data = await res.json();
|
|
||||||
monaco.editor.defineTheme(id, data);
|
|
||||||
loaded[id] = true;
|
|
||||||
}
|
|
||||||
export const loadThemePromise = customOptions.theme
|
|
||||||
? fetchTheme(customOptions.theme, list[customOptions.theme])
|
|
||||||
: Promise.resolve();
|
|
||||||
|
|
||||||
// 这破烂 monaco 能不能给个 typings 啊
|
|
||||||
// 我翻源码真的很累的好吧
|
|
||||||
class ChangeThemeAction extends EditorAction {
|
|
||||||
constructor() {
|
|
||||||
super({
|
|
||||||
id: 'hydro.changeEditorTheme',
|
|
||||||
label: i18n('Change Theme'),
|
|
||||||
alias: 'Change Theme',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async run(accessor, editor: monaco.editor.IStandaloneCodeEditor) {
|
|
||||||
const items = Object.keys(list).map((key) => ({
|
|
||||||
label: list[key],
|
|
||||||
command: key,
|
|
||||||
}));
|
|
||||||
const quickInputService = accessor.get(IQuickInputService);
|
|
||||||
const oldTheme = (editor as any)._themeService._theme;
|
|
||||||
let focus = '';
|
|
||||||
const selected = await quickInputService.pick(items, {
|
|
||||||
canPickMany: false,
|
|
||||||
async onDidFocus(item) {
|
|
||||||
focus = item.command;
|
|
||||||
await fetchTheme(item.command, item.label);
|
|
||||||
if (focus === item.command) monaco.editor.setTheme(item.command);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!selected) {
|
|
||||||
const themeId = oldTheme.type ? `${oldTheme.base}-${oldTheme.type}` : oldTheme.id;
|
|
||||||
return monaco.editor.setTheme(themeId);
|
|
||||||
}
|
|
||||||
await fetchTheme(selected.command, selected.label);
|
|
||||||
customOptions.theme = selected.command;
|
|
||||||
saveCustomOptions();
|
|
||||||
return monaco.editor.setTheme(selected.command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
registerEditorAction(ChangeThemeAction);
|
|
||||||
|
|
||||||
const pagename = document.documentElement.getAttribute('data-page');
|
|
||||||
const isProblemPage = ['problem_create', 'problem_edit'].includes(pagename);
|
|
||||||
const isProblemEdit = pagename === 'problem_edit';
|
|
||||||
function handlePasteEvent(editor: monaco.editor.IStandaloneCodeEditor) {
|
|
||||||
window.addEventListener('paste', (ev: ClipboardEvent) => {
|
|
||||||
if (!editor.hasTextFocus()) return;
|
|
||||||
const selection = editor.getSelection();
|
|
||||||
const { items } = ev.clipboardData;
|
|
||||||
let wrapper = ['', ''];
|
|
||||||
let ext;
|
|
||||||
const matches = items[0].type.match(/^image\/(png|jpg|jpeg|gif)$/i);
|
|
||||||
if (matches) {
|
|
||||||
wrapper = [''];
|
|
||||||
[, ext] = matches;
|
|
||||||
} else if (items[0].type === 'application/x-zip-compressed') {
|
|
||||||
wrapper = ['[file](', ')'];
|
|
||||||
ext = 'zip';
|
|
||||||
}
|
|
||||||
if (!ext) return;
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
const filename = `${nanoid()}.${ext}`;
|
|
||||||
const data = new FormData();
|
|
||||||
data.append('filename', filename);
|
|
||||||
data.append('file', items[0].getAsFile());
|
|
||||||
data.append('operation', 'upload_file');
|
|
||||||
if (isProblemEdit) data.append('type', 'additional_file');
|
|
||||||
let range: monaco.Range = null;
|
|
||||||
editor.executeEdits('', [{
|
|
||||||
range: new monaco.Range(selection.endLineNumber, selection.endColumn, selection.endLineNumber, selection.endColumn),
|
|
||||||
text: `}) `,
|
|
||||||
}], (inverseOp) => { range = inverseOp[0].range; return null; });
|
|
||||||
editor.setPosition(editor.getSelection().getEndPosition());
|
|
||||||
|
|
||||||
function updateText(text: string) {
|
|
||||||
const pos = editor.getSelection();
|
|
||||||
const rangeBefore = range;
|
|
||||||
editor.executeEdits('', [{ range, text: `${wrapper[0]}${text}${wrapper[1]} ` }], (inverseOp) => {
|
|
||||||
range = inverseOp[0].range;
|
|
||||||
if (pos.endLineNumber !== pos.startLineNumber || pos.endLineNumber !== range.endLineNumber) return null;
|
|
||||||
const delta = rangeBefore.endColumn - range.endColumn;
|
|
||||||
editor.setPosition(new monaco.Position(pos.endLineNumber, pos.endColumn - delta));
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let progress = 0;
|
|
||||||
request.postFile(isProblemEdit ? './files' : '/file', data, {
|
|
||||||
xhr() {
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
xhr.upload.addEventListener('loadstart', () => updateText(i18n('Uploading...')));
|
|
||||||
xhr.upload.addEventListener('progress', (e) => {
|
|
||||||
if (!e.lengthComputable) return;
|
|
||||||
const percentComplete = Math.round((e.loaded / e.total) * 100);
|
|
||||||
if (percentComplete === progress) return;
|
|
||||||
progress = percentComplete;
|
|
||||||
updateText(`${i18n('Uploading...')} ${percentComplete}%`);
|
|
||||||
}, false);
|
|
||||||
return xhr;
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then(() => updateText(`${isProblemPage ? 'file://' : `/file/${UserContext._id}/`}${filename}`))
|
|
||||||
.catch((e) => {
|
|
||||||
console.error(e);
|
|
||||||
updateText(`${i18n('Upload Failed')}: ${e.message}`);
|
|
||||||
});
|
|
||||||
}, { capture: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
export function registerAction(
|
|
||||||
editor: monaco.editor.IStandaloneCodeEditor,
|
|
||||||
model: monaco.editor.IModel,
|
|
||||||
element?,
|
|
||||||
) {
|
|
||||||
if (element) {
|
|
||||||
editor.addAction({
|
|
||||||
id: 'hydro.submitForm',
|
|
||||||
label: 'Submit',
|
|
||||||
keybindings: [
|
|
||||||
monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter,
|
|
||||||
monaco.KeyMod.WinCtrl | monaco.KeyCode.Enter,
|
|
||||||
],
|
|
||||||
run: () => {
|
|
||||||
const form = $(element).closest('form');
|
|
||||||
if (form.find('[data-default-submit]').length) form.find('[data-default-submit]').click();
|
|
||||||
else form.submit();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KeyP, () => {
|
|
||||||
editor.getAction('editor.action.quickCommand').run();
|
|
||||||
});
|
|
||||||
editor.addCommand(monaco.KeyMod.Alt | monaco.KeyMod.Shift | monaco.KeyCode.KeyF, () => {
|
|
||||||
const action = editor.getAction('editor.action.format') || editor.getAction('editor.action.formatDocument');
|
|
||||||
if (action) action.run();
|
|
||||||
});
|
|
||||||
editor.onDidChangeConfiguration(() => {
|
|
||||||
const current = editor.getOption(monaco.editor.EditorOptions.fontSize.id);
|
|
||||||
customOptions.fontSize = current;
|
|
||||||
saveCustomOptions();
|
|
||||||
});
|
|
||||||
if (model.getLanguageId() === 'markdown') {
|
|
||||||
const suggestWidget = (editor.getContribution('editor.contrib.suggestController') as any).widget?.value;
|
|
||||||
if (suggestWidget?._setDetailsVisible) suggestWidget._setDetailsVisible(true);
|
|
||||||
handlePasteEvent(editor);
|
|
||||||
}
|
|
||||||
if (!customOptions.theme) return null;
|
|
||||||
return loadThemePromise.then(() => editor.updateOptions({ theme: customOptions.theme }));
|
|
||||||
}
|
|
||||||
@@ -1,109 +1,131 @@
|
|||||||
|
import 'vscode/localExtensionHost';
|
||||||
|
|
||||||
import keyword from 'emojis-keywords';
|
import keyword from 'emojis-keywords';
|
||||||
import list from 'emojis-list';
|
import list from 'emojis-list';
|
||||||
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
|
|
||||||
import qface from 'qface';
|
import qface from 'qface';
|
||||||
import { api, gql } from 'vj/utils';
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
function emoji(range) {
|
vscode.commands.registerCommand('hydro.openUserPage', (accesser, uid) => {
|
||||||
return keyword.map((i, index) => ({
|
|
||||||
label: `${list[index]} ${i}`,
|
|
||||||
kind: monaco.languages.CompletionItemKind.Keyword,
|
|
||||||
documentation: i,
|
|
||||||
insertText: list[index],
|
|
||||||
range,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
function qqEmoji(range) {
|
|
||||||
return qface.data.flatMap((i) => {
|
|
||||||
const url = qface.getUrl(i.QSid, 'https://qq-face.vercel.app');
|
|
||||||
return [i.QDes.substring(1), ...(i.Input || [])].map((input) => ({
|
|
||||||
label: `/${input}`,
|
|
||||||
kind: monaco.languages.CompletionItemKind.Keyword,
|
|
||||||
documentation: { value: ``, isTrusted: true },
|
|
||||||
insertText: `![${i.Input ? i.Input[0] : i.QDes.substring(1)}](${url} =32x32) `,
|
|
||||||
range,
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
monaco.editor.registerCommand('hydro.openUserPage', (accesser, uid) => {
|
|
||||||
window.open(`/user/${uid}`);
|
window.open(`/user/${uid}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
monaco.languages.registerCodeLensProvider('markdown', {
|
class CodelensProvider implements vscode.CodeLensProvider {
|
||||||
async provideCodeLenses(model) {
|
private regex: RegExp;
|
||||||
const users = model.findMatches('\\[\\]\\(/user/(\\d+)\\)', true, true, true, null, true);
|
private _onDidChangeCodeLenses: vscode.EventEmitter<void> = new vscode.EventEmitter<void>();
|
||||||
if (!users.length) {
|
public readonly onDidChangeCodeLenses: vscode.Event<void> = this._onDidChangeCodeLenses.event;
|
||||||
return {
|
|
||||||
lenses: [],
|
|
||||||
dispose: () => { },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const { data } = await api(gql`
|
|
||||||
users(ids: ${users.map((i) => +i.matches[1])}) {
|
|
||||||
_id
|
|
||||||
uname
|
|
||||||
}
|
|
||||||
`);
|
|
||||||
return {
|
|
||||||
lenses: users.map((i, index) => ({
|
|
||||||
range: i.range,
|
|
||||||
id: `${index}.${i.matches[1]}`,
|
|
||||||
command: {
|
|
||||||
id: 'hydro.openUserPage',
|
|
||||||
arguments: [i.matches[1]],
|
|
||||||
title: `@${data.users.find((doc) => doc._id.toString() === i.matches[1])?.uname || i.matches[1]}`,
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
dispose: () => { },
|
|
||||||
};
|
|
||||||
},
|
|
||||||
resolveCodeLens(model, codeLens) {
|
|
||||||
return codeLens;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
monaco.languages.registerCompletionItemProvider('markdown', {
|
constructor() {
|
||||||
async provideCompletionItems(model, position) {
|
this.regex = /\[\]\(\/user\/(\d+)\)/g;
|
||||||
const word = model.getWordAtPosition(position);
|
console.log('aaa', vscode);
|
||||||
if (word.word.length < 2) return { suggestions: [] };
|
|
||||||
const prefix = model.getValueInRange({
|
vscode.workspace.onDidChangeConfiguration((_) => {
|
||||||
startLineNumber: position.lineNumber,
|
this._onDidChangeCodeLenses.fire();
|
||||||
endLineNumber: position.lineNumber,
|
|
||||||
startColumn: word.startColumn - 1,
|
|
||||||
endColumn: word.startColumn,
|
|
||||||
});
|
});
|
||||||
if (![':', '/', '@'].includes(prefix)) return { suggestions: [] };
|
}
|
||||||
const range = {
|
|
||||||
startLineNumber: position.lineNumber,
|
public async provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken) {
|
||||||
endLineNumber: position.lineNumber,
|
const codeLenses: vscode.CodeLens[] = [];
|
||||||
startColumn: word.startColumn - 1,
|
console.log('cl', 123);
|
||||||
endColumn: word.endColumn,
|
const regex = new RegExp(this.regex);
|
||||||
};
|
const text = document.getText();
|
||||||
if (prefix === '@') {
|
let matches;
|
||||||
const users = await api(gql`
|
const users = [];
|
||||||
users(search: ${word.word}) {
|
while ((matches = regex.exec(text)) !== null) {
|
||||||
_id
|
const line = document.lineAt(document.positionAt(matches.index).line);
|
||||||
uname
|
const indexOf = line.text.indexOf(matches[0]);
|
||||||
avatarUrl
|
const position = new vscode.Position(line.lineNumber, indexOf);
|
||||||
priv
|
const range = document.getWordRangeAtPosition(position, new RegExp(this.regex));
|
||||||
}
|
if (range) users.push({ matches, range });
|
||||||
`, ['data', 'users']);
|
|
||||||
return {
|
|
||||||
suggestions: users.map((i) => ({
|
|
||||||
label: { label: `@${i.uname}`, description: `UID=${i._id}` },
|
|
||||||
kind: monaco.languages.CompletionItemKind.Property,
|
|
||||||
documentation: { value: `[](#loader) })`, isTrusted: true },
|
|
||||||
insertText: `@[](/user/${i._id}) `,
|
|
||||||
range,
|
|
||||||
sortText: i.priv === 0 ? '0' : '1',
|
|
||||||
tags: i.priv === 0 ? [1] : [],
|
|
||||||
})),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return {
|
// const { data } = await api(gql`
|
||||||
suggestions: prefix === ':' ? emoji(range) : qqEmoji(range),
|
// users(ids: ${users.map((i) => +i.matches[1])}) {
|
||||||
};
|
// _id
|
||||||
|
// uname
|
||||||
|
// }
|
||||||
|
// `);
|
||||||
|
for (const { matches, range } of users) {
|
||||||
|
codeLenses.push(new vscode.CodeLens(range, {
|
||||||
|
command: 'hydro.openUserPage',
|
||||||
|
arguments: [matches[1]],
|
||||||
|
title: `@${matches[1]}`,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return codeLenses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public resolveCodeLens(codeLens: vscode.CodeLens, token: vscode.CancellationToken) {
|
||||||
|
return codeLens;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vscode.languages.registerCodeLensProvider({ language: 'markdown' }, new CodelensProvider());
|
||||||
|
|
||||||
|
vscode.languages.registerCompletionItemProvider({ language: 'markdown' }, {
|
||||||
|
async provideCompletionItems(document, position, token, context) {
|
||||||
|
const range = new vscode.Range(new vscode.Position(position.line, position.character - 1), position);
|
||||||
|
return context.triggerCharacter === ':'
|
||||||
|
? keyword.map((i, index) => {
|
||||||
|
const c = new vscode.CompletionItem(`${list[index]} ${i}`, vscode.CompletionItemKind.Keyword);
|
||||||
|
c.insertText = list[index];
|
||||||
|
c.documentation = i;
|
||||||
|
c.range = range;
|
||||||
|
return c;
|
||||||
|
})
|
||||||
|
: qface.data.flatMap((i) => {
|
||||||
|
const url = qface.getUrl(i.QSid, 'https://qq-face.vercel.app');
|
||||||
|
return [i.QDes.substring(1), ...(i.Input || [])].map((input) => {
|
||||||
|
const c = new vscode.CompletionItem(`/${input}`, vscode.CompletionItemKind.Keyword);
|
||||||
|
c.insertText = `![${i.Input ? i.Input[0] : i.QDes.substring(1)}](${url} =32x32) `;
|
||||||
|
c.documentation = new vscode.MarkdownString(``);
|
||||||
|
c.range = range;
|
||||||
|
return c;
|
||||||
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
}, ':', '/');
|
||||||
|
|
||||||
|
vscode.languages.registerCompletionItemProvider('*', {
|
||||||
|
async provideCompletionItems(document, position, token, context) {
|
||||||
|
return [];
|
||||||
|
const range = document.getWordRangeAtPosition(position);
|
||||||
|
const word = document.getText(range);
|
||||||
|
if (word.length < 2) return [];
|
||||||
|
// const prefix = document.getValueInRange({
|
||||||
|
// startLineNumber: position.lineNumber,
|
||||||
|
// endLineNumber: position.lineNumber,
|
||||||
|
// startColumn: word.startColumn - 1,
|
||||||
|
// endColumn: word.startColumn,
|
||||||
|
// });
|
||||||
|
// if (![':', '/', '@'].includes(prefix)) return { suggestions: [] };
|
||||||
|
// const range = {
|
||||||
|
// startLineNumber: position.lineNumber,
|
||||||
|
// endLineNumber: position.lineNumber,
|
||||||
|
// startColumn: word.startColumn - 1,
|
||||||
|
// endColumn: word.endColumn,
|
||||||
|
// };
|
||||||
|
// if (prefix === '@') {
|
||||||
|
// const users = await api(gql`
|
||||||
|
// users(search: ${word.word}) {
|
||||||
|
// _id
|
||||||
|
// uname
|
||||||
|
// avatarUrl
|
||||||
|
// priv
|
||||||
|
// }
|
||||||
|
// `, ['data', 'users']);
|
||||||
|
// return {
|
||||||
|
// suggestions: users.map((i) => ({
|
||||||
|
// label: { label: `@${i.uname}`, description: `UID=${i._id}` },
|
||||||
|
// kind: monaco.languages.CompletionItemKind.Property,
|
||||||
|
// documentation: { value: `[](#loader) })`, isTrusted: true },
|
||||||
|
// insertText: `@[](/user/${i._id}) `,
|
||||||
|
// range,
|
||||||
|
// sortText: i.priv === 0 ? '0' : '1',
|
||||||
|
// tags: i.priv === 0 ? [1] : [],
|
||||||
|
// })),
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// return {
|
||||||
|
// suggestions: prefix === ':' ? emoji(range) : qqEmoji(range),
|
||||||
|
// };
|
||||||
|
},
|
||||||
|
}, '@');
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
|
|
||||||
|
|
||||||
const types = require.context('@types/node/', true, /\.d\.ts$/, 'lazy-once');
|
|
||||||
|
|
||||||
const diagnosticsOptions: monaco.languages.typescript.DiagnosticsOptions = {
|
|
||||||
noSemanticValidation: false,
|
|
||||||
noSyntaxValidation: false,
|
|
||||||
noSuggestionDiagnostics: true,
|
|
||||||
};
|
|
||||||
const compilerOptions: monaco.languages.typescript.CompilerOptions = {
|
|
||||||
target: monaco.languages.typescript.ScriptTarget.ES2020,
|
|
||||||
module: monaco.languages.typescript.ModuleKind.ESNext,
|
|
||||||
allowNonTsExtensions: true,
|
|
||||||
};
|
|
||||||
monaco.languages.typescript.javascriptDefaults.setDiagnosticsOptions(diagnosticsOptions);
|
|
||||||
monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions(diagnosticsOptions);
|
|
||||||
monaco.languages.typescript.javascriptDefaults.setCompilerOptions(compilerOptions);
|
|
||||||
monaco.languages.typescript.typescriptDefaults.setCompilerOptions(compilerOptions);
|
|
||||||
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));
|
|
||||||
const modules = [];
|
|
||||||
|
|
||||||
export async function loadTypes() {
|
|
||||||
for (const key of types.keys()) {
|
|
||||||
if (!key.startsWith('.')) continue;
|
|
||||||
const m = await types(key);
|
|
||||||
const val = m.replace('declare var require: NodeRequire;', '');
|
|
||||||
if (val.includes('declare module ')) {
|
|
||||||
modules.push(val.toString().split('declare module \'')[1].split('\'')[0]);
|
|
||||||
}
|
|
||||||
const uri = `ts:node/${key.split('./')[1]}`;
|
|
||||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(val, uri);
|
|
||||||
monaco.editor.createModel(val, 'typescript', monaco.Uri.parse(uri));
|
|
||||||
}
|
|
||||||
let val = 'declare var require:';
|
|
||||||
for (const m of modules) val += `((id:'${m}')=>(typeof import('${m}')))&`;
|
|
||||||
val += '((id:string)=>any)';
|
|
||||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(val, 'ts:node/require.d.ts');
|
|
||||||
monaco.editor.createModel(val, 'typescript', monaco.Uri.parse('ts:node/require.d.ts'));
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
|
|
||||||
import { configureMonacoYaml } from 'monaco-yaml';
|
|
||||||
import problemConfigSchema from '../schema/problemconfig';
|
|
||||||
|
|
||||||
configureMonacoYaml(monaco, {
|
|
||||||
validate: true,
|
|
||||||
enableSchemaRequest: true,
|
|
||||||
hover: true,
|
|
||||||
completion: true,
|
|
||||||
format: false,
|
|
||||||
schemas: [
|
|
||||||
{
|
|
||||||
uri: 'https://hydro.js.org/schema/problemConfig.json',
|
|
||||||
fileMatch: ['hydro://problem/file/config.yaml'],
|
|
||||||
schema: problemConfigSchema as any,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
uri: new URL('/manage/config/schema.json', window.location.href).toString(),
|
|
||||||
fileMatch: ['hydro://system/setting.yaml'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
@@ -1,10 +1,25 @@
|
|||||||
import { getFeatures, load as loadModule } from '../../lazyload';
|
import { getFeatures, load as loadModule } from '../../lazyload';
|
||||||
|
|
||||||
|
/* eslint-disable no-await-in-loop */
|
||||||
|
|
||||||
let loaded;
|
let loaded;
|
||||||
|
|
||||||
|
const localeLoader: Partial<Record<string, () => Promise<void>>> = {
|
||||||
|
ko: async () => {
|
||||||
|
await import('@codingame/monaco-vscode-language-pack-ko');
|
||||||
|
},
|
||||||
|
zh: async () => {
|
||||||
|
await import('@codingame/monaco-vscode-language-pack-zh-hans');
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
'zh_TW': async () => {
|
||||||
|
await import('@codingame/monaco-vscode-language-pack-zh-hant');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const val: Record<string, any> = {};
|
const val: Record<string, any> = {};
|
||||||
/** @deprecated */
|
/** @deprecated */
|
||||||
export async function legacyLoadExternalModule(target: string) {
|
async function legacyLoadExternalModule(target: string) {
|
||||||
if (val[target]) return val[target];
|
if (val[target]) return val[target];
|
||||||
const ele = document.createElement('script');
|
const ele = document.createElement('script');
|
||||||
ele.src = target;
|
ele.src = target;
|
||||||
@@ -18,22 +33,26 @@ export async function legacyLoadExternalModule(target: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loaders = {
|
const loaders = {
|
||||||
i18n: async () => {
|
workbench: async () => {
|
||||||
const { setLocaleData } = await import('./nls');
|
await Promise.all([
|
||||||
let resource;
|
import('@codingame/monaco-vscode-theme-seti-default-extension'),
|
||||||
const lang = UserContext.viewLang;
|
import('@codingame/monaco-vscode-media-preview-default-extension'),
|
||||||
if (lang === 'zh') {
|
import('@codingame/monaco-vscode-markdown-language-features-default-extension'),
|
||||||
resource = await import('monaco-editor-nls/locale/zh-hans.json');
|
import('@codingame/monaco-vscode-markdown-math-default-extension'),
|
||||||
} else if (lang === 'zh_TW') {
|
import('@codingame/monaco-vscode-configuration-editing-default-extension'),
|
||||||
resource = await import('monaco-editor-nls/locale/zh-hant.json');
|
import('@codingame/monaco-editor-wrapper/features/viewPanels'),
|
||||||
} else if (lang === 'ko') {
|
import('@codingame/monaco-editor-wrapper/features/search'),
|
||||||
resource = await import('monaco-editor-nls/locale/ko.json');
|
]);
|
||||||
}
|
|
||||||
if (resource) setLocaleData(resource);
|
|
||||||
},
|
},
|
||||||
markdown: () => import('./languages/markdown'),
|
markdown: async () => await Promise.all([
|
||||||
typescript: () => import('./languages/typescript').then((m) => m.loadTypes()),
|
import('./languages/markdown'),
|
||||||
yaml: () => import('./languages/yaml'),
|
import('@codingame/monaco-vscode-markdown-basics-default-extension'),
|
||||||
|
import('@codingame/monaco-vscode-markdown-language-features-default-extension'),
|
||||||
|
import('@codingame/monaco-vscode-markdown-math-default-extension'),
|
||||||
|
]),
|
||||||
|
typescript: async () => await import('@codingame/monaco-vscode-typescript-language-features-default-extension'),
|
||||||
|
cpp: async () => await import('@codingame/monaco-vscode-cpp-default-extension'),
|
||||||
|
yaml: async () => await import('@codingame/monaco-vscode-yaml-default-extension'),
|
||||||
external: async (monaco, feat) => {
|
external: async (monaco, feat) => {
|
||||||
for (const item of await getFeatures(`monaco-${feat}`)) {
|
for (const item of await getFeatures(`monaco-${feat}`)) {
|
||||||
let apply = typeof item === 'function'
|
let apply = typeof item === 'function'
|
||||||
@@ -47,19 +66,28 @@ const loaders = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let loadPromise = Promise.resolve();
|
let loadPromise = localeLoader['zh-hans']();
|
||||||
|
let config = false;
|
||||||
|
|
||||||
|
async function initConfigManager(t: typeof import('./monaco.ts')) {
|
||||||
|
t.registerFile(new t.RegisteredMemoryFile(t.default.Uri.parse('/.vscode/settings.json'), localStorage.getItem('monaco.settings') || '{}'));
|
||||||
|
const model = await t.default.editor.createModelReference(t.default.Uri.parse('/.vscode/settings.json'));
|
||||||
|
model.object.textEditorModel?.onDidChangeContent(() => {
|
||||||
|
const value = model.object.textEditorModel?.getValue() || '{}';
|
||||||
|
localStorage.setItem('monaco.settings', value);
|
||||||
|
t.updateUserConfiguration(value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export async function load(features = ['markdown']) {
|
export async function load(features = ['markdown']) {
|
||||||
let s = Date.now();
|
let s = Date.now();
|
||||||
await loadPromise;
|
await loadPromise;
|
||||||
let resolve;
|
let resolve;
|
||||||
loadPromise = new Promise((r) => { resolve = r; });
|
loadPromise = new Promise((r) => { resolve = r; });
|
||||||
|
if (!loaded) console.log('Loading monaco editor');
|
||||||
|
const res = await import('./monaco');
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
await loaders.i18n();
|
await res.init(features.includes('workbench'));
|
||||||
console.log('Loading monaco editor');
|
|
||||||
}
|
|
||||||
const res = await import('./index');
|
|
||||||
if (!loaded) {
|
|
||||||
console.log('Loaded monaco editor in', Date.now() - s, 'ms');
|
console.log('Loaded monaco editor in', Date.now() - s, 'ms');
|
||||||
loaded = [];
|
loaded = [];
|
||||||
}
|
}
|
||||||
@@ -83,9 +111,12 @@ export async function load(features = ['markdown']) {
|
|||||||
console.log('Monaco feat', feat, 'failed to load:', e);
|
console.log('Monaco feat', feat, 'failed to load:', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await res.loadThemePromise;
|
if (!config) {
|
||||||
|
config = true;
|
||||||
|
await initConfigManager(res);
|
||||||
|
}
|
||||||
resolve();
|
resolve();
|
||||||
return { monaco: res.default, registerAction: res.registerAction, customOptions: res.customOptions };
|
return { ...res, monaco: res.default };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default load;
|
export default load;
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import '@codingame/monaco-editor-wrapper/features/extensionHostWorker';
|
||||||
|
import '@codingame/monaco-editor-wrapper/features/notifications';
|
||||||
|
import '@codingame/monaco-vscode-theme-defaults-default-extension';
|
||||||
|
import '@codingame/monaco-vscode-json-default-extension';
|
||||||
|
|
||||||
|
import {
|
||||||
|
createEditor, initialize, registerFile, registerServices,
|
||||||
|
} from '@codingame/monaco-editor-wrapper';
|
||||||
|
import { RegisteredMemoryFile } from '@codingame/monaco-vscode-files-service-override';
|
||||||
|
import * as monaco from 'monaco-editor';
|
||||||
|
import { Uri } from 'vscode';
|
||||||
|
|
||||||
|
export default monaco;
|
||||||
|
export { createEditor, registerFile, RegisteredMemoryFile };
|
||||||
|
export {
|
||||||
|
getUserConfiguration, getConfiguration,
|
||||||
|
onUserConfigurationChange, onConfigurationChanged,
|
||||||
|
updateUserConfiguration,
|
||||||
|
} from '@codingame/monaco-editor-wrapper';
|
||||||
|
|
||||||
|
export const init = async (workbench = false) => {
|
||||||
|
if (workbench) {
|
||||||
|
const [
|
||||||
|
{ default: getWorkbenchServiceOverride },
|
||||||
|
{ default: getMultiDiffEditorServiceOverride },
|
||||||
|
{ default: getQuickAccessServiceOverride },
|
||||||
|
] = await Promise.all([
|
||||||
|
import('@codingame/monaco-vscode-workbench-service-override'),
|
||||||
|
import('@codingame/monaco-vscode-multi-diff-editor-service-override'),
|
||||||
|
import('@codingame/monaco-vscode-quickaccess-service-override'),
|
||||||
|
]);
|
||||||
|
registerServices({
|
||||||
|
...getWorkbenchServiceOverride(),
|
||||||
|
...getMultiDiffEditorServiceOverride(),
|
||||||
|
...getQuickAccessServiceOverride({
|
||||||
|
shouldUseGlobalPicker() {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
isKeybindingConfigurationVisible() {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return initialize({
|
||||||
|
workspaceProvider: {
|
||||||
|
trusted: true,
|
||||||
|
workspace: {
|
||||||
|
workspaceUri: Uri.file('/'),
|
||||||
|
},
|
||||||
|
async open() {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
function format(message, args) {
|
|
||||||
let result;
|
|
||||||
if (!args.length) result = message;
|
|
||||||
else {
|
|
||||||
result = String(message).replace(/\{(\d+)\}/g, (match, rest) => {
|
|
||||||
const index = rest[0];
|
|
||||||
return typeof args[index] !== 'undefined' ? args[index] : match;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getConfiguredDefaultLocale = () => 'zh';
|
|
||||||
|
|
||||||
let CURRENT_LOCALE_DATA = {}; // eslint-disable-line @typescript-eslint/naming-convention
|
|
||||||
|
|
||||||
export function localize(path, message, ...args) {
|
|
||||||
return format(CURRENT_LOCALE_DATA[path.key || path] || message, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function localize2(data, message, ...args) {
|
|
||||||
const original = localize(message, args);
|
|
||||||
return {
|
|
||||||
value: original,
|
|
||||||
original,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setLocaleData(data) {
|
|
||||||
CURRENT_LOCALE_DATA = Object.assign(...Object.values(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function loadMessageBundle() {
|
|
||||||
return localize;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function config() {
|
|
||||||
return loadMessageBundle;
|
|
||||||
}
|
|
||||||
@@ -41,22 +41,21 @@ export default connect((state: any) => ({
|
|||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
const value = this.props.value || '';
|
const value = this.props.value || '';
|
||||||
const { language } = this.props;
|
const { language } = this.props;
|
||||||
const { monaco, registerAction, customOptions } = await load([language]);
|
const { monaco, createEditor } = await load([language]);
|
||||||
const uri = monaco.Uri.parse(`hydro:${UiContext.pdoc.pid || UiContext.pdoc.docId}.${language}`);
|
const uri = monaco.Uri.parse(`/${UiContext.pdoc.pid || UiContext.pdoc.docId}.${language}`);
|
||||||
this.model = monaco.editor.getModel(uri) || monaco.editor.createModel(value, language, uri);
|
this.model = monaco.editor.getModel(uri) || monaco.editor.createModel(value, language, uri);
|
||||||
if (this.containerElement) {
|
if (this.containerElement) {
|
||||||
const config: monaco.editor.IStandaloneEditorConstructionOptions = {
|
const config: monaco.editor.IStandaloneEditorConstructionOptions = {
|
||||||
theme: 'vs-light',
|
theme: 'vs-light',
|
||||||
fontFamily: UserContext.codeFontFamily,
|
fontFamily: UserContext.codeFontFamily,
|
||||||
...customOptions,
|
|
||||||
lineNumbers: 'on',
|
lineNumbers: 'on',
|
||||||
glyphMargin: true,
|
glyphMargin: true,
|
||||||
lightbulb: { enabled: monaco.editor.ShowLightbulbIconMode.On },
|
lightbulb: { enabled: monaco.editor.ShowLightbulbIconMode.On },
|
||||||
model: this.model,
|
model: this.model,
|
||||||
fontLigatures: '',
|
fontLigatures: '',
|
||||||
|
language,
|
||||||
};
|
};
|
||||||
this.editor = monaco.editor.create(this.containerElement, config);
|
this.editor = createEditor(this.containerElement, config);
|
||||||
registerAction(this.editor, this.model);
|
|
||||||
this.disposable.push(
|
this.disposable.push(
|
||||||
this.editor.onDidChangeModelContent((event) => {
|
this.editor.onDidChangeModelContent((event) => {
|
||||||
if (!this.__prevent_trigger_change_event) {
|
if (!this.__prevent_trigger_change_event) {
|
||||||
@@ -96,7 +95,7 @@ export default connect((state: any) => ({
|
|||||||
if (model && editor && prevProps.language !== language) {
|
if (model && editor && prevProps.language !== language) {
|
||||||
const val = model.getValue(LF, false);
|
const val = model.getValue(LF, false);
|
||||||
model.dispose();
|
model.dispose();
|
||||||
const uri = monaco.Uri.parse(`hydro:${UiContext.pdoc.pid || UiContext.pdoc.docId}.${language}`);
|
const uri = monaco.Uri.parse(`file:///${UiContext.pdoc.pid || UiContext.pdoc.docId}.${language}`);
|
||||||
this.model = monaco.editor.getModel(uri) || monaco.editor.createModel(val, language, uri);
|
this.model = monaco.editor.getModel(uri) || monaco.editor.createModel(val, language, uri);
|
||||||
editor.setModel(this.model);
|
editor.setModel(this.model);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,11 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@blueprintjs/core": "^5.10.3",
|
"@blueprintjs/core": "^5.10.3",
|
||||||
|
"@codingame/monaco-editor-wrapper": "^6.6.10",
|
||||||
|
"@codingame/monaco-vscode-language-pack-ko": "5.3.0",
|
||||||
|
"@codingame/monaco-vscode-language-pack-zh-hans": "5.3.0",
|
||||||
|
"@codingame/monaco-vscode-language-pack-zh-hant": "5.3.0",
|
||||||
|
"@codingame/monaco-vscode-typescript-language-features-default-extension": "5.3.0",
|
||||||
"@cordisjs/core": "^3.16.2",
|
"@cordisjs/core": "^3.16.2",
|
||||||
"@fontsource/dm-mono": "^5.0.20",
|
"@fontsource/dm-mono": "^5.0.20",
|
||||||
"@fontsource/fira-code": "^5.0.18",
|
"@fontsource/fira-code": "^5.0.18",
|
||||||
@@ -40,6 +45,7 @@
|
|||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.3",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@types/redux-logger": "^3.0.13",
|
"@types/redux-logger": "^3.0.13",
|
||||||
|
"@types/vscode": "^1.89.0",
|
||||||
"@types/webpack-env": "^1.18.5",
|
"@types/webpack-env": "^1.18.5",
|
||||||
"@vscode/codicons": "^0.0.36",
|
"@vscode/codicons": "^0.0.36",
|
||||||
"ajv": "^8.16.0",
|
"ajv": "^8.16.0",
|
||||||
@@ -73,9 +79,8 @@
|
|||||||
"matchmedia-polyfill": "^0.3.2",
|
"matchmedia-polyfill": "^0.3.2",
|
||||||
"mini-css-extract-plugin": "^2.9.0",
|
"mini-css-extract-plugin": "^2.9.0",
|
||||||
"moment": "^2.30.1",
|
"moment": "^2.30.1",
|
||||||
"monaco-editor": "0.46.0",
|
"monaco-editor": "npm:@codingame/monaco-vscode-editor-api@5.3.0",
|
||||||
"monaco-editor-nls": "^3.1.0",
|
"monaco-languageclient": "^8.4.0",
|
||||||
"monaco-editor-webpack-plugin": "^7.1.0",
|
|
||||||
"monaco-themes": "^0.4.4",
|
"monaco-themes": "^0.4.4",
|
||||||
"monaco-yaml": "^5.1.1",
|
"monaco-yaml": "^5.1.1",
|
||||||
"nanoid": "^5.0.7",
|
"nanoid": "^5.0.7",
|
||||||
@@ -117,8 +122,12 @@
|
|||||||
"timeago-react": "^3.0.6",
|
"timeago-react": "^3.0.6",
|
||||||
"timeago.js": "^4.0.2",
|
"timeago.js": "^4.0.2",
|
||||||
"ts-loader": "^9.5.1",
|
"ts-loader": "^9.5.1",
|
||||||
|
"url": "^0.11.3",
|
||||||
|
"util": "^0.12.5",
|
||||||
"vditor": "^3.10.4",
|
"vditor": "^3.10.4",
|
||||||
"vinyl-buffer": "^1.0.1",
|
"vinyl-buffer": "^1.0.1",
|
||||||
|
"vscode": "npm:@codingame/monaco-vscode-api@^5.3.0",
|
||||||
|
"vscode-languageclient": "^9.0.1",
|
||||||
"web-streams-polyfill": "^4.0.0",
|
"web-streams-polyfill": "^4.0.0",
|
||||||
"webpack": "^5.91.0",
|
"webpack": "^5.91.0",
|
||||||
"webpack-bundle-analyzer": "^4.10.2",
|
"webpack-bundle-analyzer": "^4.10.2",
|
||||||
|
|||||||
Reference in new issue
Block a user