diff --git a/src/renderer/plugins.ts b/src/renderer/plugins.ts index ca1c56b5..c9532dc9 100644 --- a/src/renderer/plugins.ts +++ b/src/renderer/plugins.ts @@ -17,6 +17,7 @@ import statusBarGet from '@fe/plugins/status-bar-get' import editorPaste from '@fe/plugins/editor-paste' import editorAttachment from '@fe/plugins/editor-attachment' import editorMarkdown from '@fe/plugins/editor-markdown' +import editorWords from '@fe/plugins/editor-words' import editorEmoji from '@fe/plugins/editor-emoji' import copyText from '@fe/plugins/copy-text' import switchTodo from '@fe/plugins/switch-todo' @@ -71,6 +72,7 @@ export default [ editorAttachment, editorMarkdown, editorEmoji, + editorWords, copyText, switchTodo, imageViewer, diff --git a/src/renderer/plugins/editor-markdown.ts b/src/renderer/plugins/editor-markdown.ts index 8d8baf53..a1433f5b 100644 --- a/src/renderer/plugins/editor-markdown.ts +++ b/src/renderer/plugins/editor-markdown.ts @@ -1,59 +1,19 @@ /* eslint-disable no-template-curly-in-string */ import dayjs from 'dayjs' import type * as Monaco from 'monaco-editor' -import { deleteLine, getEditor, getLineContent, getMonaco, getOneIndent, getValue, insert, replaceLine, whenEditorReady } from '@fe/services/editor' +import { deleteLine, getEditor, getLineContent, getMonaco, getOneIndent, insert, replaceLine, whenEditorReady } from '@fe/services/editor' import type { Plugin } from '@fe/context' import { t } from '@fe/services/i18n' import { getSetting } from '@fe/services/setting' import { isKeydown } from '@fe/core/command' -function getWords (content: string) { - const words = new Set() - - if (content.length > 50000) { - return words - } - - const identifier = /[a-zA-Z_]+\w/g - - while (true) { - if (words.size > 1000) { - break - } - - const res = identifier.exec(content) - if (!res) { - break - } - - if (res[0].length > 2 && res[0].length < 15) { - words.add(res[0]) - } - } - - return words -} - -function createDependencyProposals (range: Monaco.IRange, model: Monaco.editor.ITextModel, position: Monaco.Position): Monaco.languages.CompletionItem[] { +function createDependencyProposals (range: Monaco.IRange): Monaco.languages.CompletionItem[] { const monaco = getMonaco() - const currentWord = model.getWordUntilPosition(position).word const replaceRange = { ...range, endColumn: range.startColumn + 1 } const result: Monaco.languages.CompletionItem[] = [] - getWords(getValue()).forEach((word, i) => { - if (currentWord !== word) { - result.push({ - label: { label: word }, - kind: monaco.languages.CompletionItemKind.Text, - insertText: word, - range: replaceRange, - sortText: (10000 + i).toString() - }) - } - }) - ;[ { name: '/ ![]() Image', insertText: '![${2:Img}]($1)' }, { name: '/ []() Link', insertText: '[${2:Link}]($1)' }, diff --git a/src/renderer/plugins/editor-words.ts b/src/renderer/plugins/editor-words.ts new file mode 100644 index 00000000..a1d28b71 --- /dev/null +++ b/src/renderer/plugins/editor-words.ts @@ -0,0 +1,75 @@ +import type * as Monaco from 'monaco-editor' +import type { Ctx, Plugin } from '@fe/context' + +function getWords (content: string) { + const words = new Set() + + if (content.length > 50000) { + return words + } + + const identifier = /[a-zA-Z_]+\w/g + + while (true) { + if (words.size > 1000) { + break + } + + const res = identifier.exec(content) + if (!res) { + break + } + + if (res[0].length > 2 && res[0].length < 15) { + words.add(res[0]) + } + } + + return words +} + +class WordsCompletionProvider implements Monaco.languages.CompletionItemProvider { + private readonly monaco: typeof Monaco + private readonly ctx: Ctx + + constructor (monaco: typeof Monaco, ctx: Ctx) { + this.monaco = monaco + this.ctx = ctx + } + + public async provideCompletionItems (model: Monaco.editor.IModel, position: Monaco.Position): Promise { + const currentWord = model.getWordUntilPosition(position) + const result: Monaco.languages.CompletionItem[] = [] + + getWords(model.getValue()).forEach((word, i) => { + if (currentWord.word !== word) { + result.push({ + label: { label: word }, + kind: this.monaco.languages.CompletionItemKind.Text, + insertText: word, + range: new this.monaco.Range( + position.lineNumber, + currentWord.startColumn, + position.lineNumber, + currentWord.endColumn, + ), + sortText: i.toString().padStart(7) + }) + } + }) + + return { suggestions: result } + } +} + +export default { + name: 'editor-words', + register: (ctx) => { + ctx.editor.whenEditorReady().then(({ monaco }) => { + monaco.languages.registerCompletionItemProvider( + 'markdown', + new WordsCompletionProvider(monaco, ctx) + ) + }) + } +} as Plugin