Skip to content

Commit

Permalink
refactor(editor): improve custom editor handling and add support for …
Browse files Browse the repository at this point in the history
…non-normal file types
  • Loading branch information
purocean committed Jan 7, 2025
1 parent 6ae48e2 commit 03573d8
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 34 deletions.
29 changes: 7 additions & 22 deletions src/renderer/components/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,19 @@

<script lang="ts" setup>
import { computed, nextTick, onBeforeUnmount, onMounted, shallowRef, watch } from 'vue'
import { getAllCustomEditors, isDefault, getValue, setValue, switchEditor } from '@fe/services/editor'
import { getAvailableCustomEditors, isDefault, getValue, setValue, switchEditor } from '@fe/services/editor'
import { registerAction, removeAction } from '@fe/core/action'
import { registerHook, removeHook, triggerHook } from '@fe/core/hook'
import { getLogger, storage } from '@fe/utils'
import { FileTabs } from '@fe/services/workbench'
import { useQuickFilter } from '@fe/support/ui/quick-filter'
import { isMarkdownFile } from '@fe/services/document'
import { t } from '@fe/services/i18n'
import store from '@fe/support/store'
import type { Components, CustomEditor, Doc } from '@fe/types'
import DefaultEditor from './DefaultEditor.vue'
const EDITOR_LAST_USAGE_TIME_KEY = 'editor.last-usage-time'
const defaultEditor: CustomEditor = {
name: 'default-markdown-editor',
displayName: t('editor.default-editor'),
component: null,
when ({ doc }) {
return !!(doc && isMarkdownFile(doc))
}
}
const logger = getLogger('main-editor')
const editorLastUsageTime = storage.get<Record<string, number>>(EDITOR_LAST_USAGE_TIME_KEY, {})
Expand All @@ -41,19 +31,14 @@ function recordEditorUsageTime (name: string) {
storage.set(EDITOR_LAST_USAGE_TIME_KEY, editorLastUsageTime)
}
async function changeEditor ({ doc }: { doc?: Doc | null, name?: string }) {
availableEditors.value = (await Promise.allSettled(
getAllCustomEditors().concat([defaultEditor]).map(async val => {
if (await val.when({ doc })) {
(val as any)._lastUsageAt = editorLastUsageTime[val.name] || 0
return val
}
type XCustomEditor = CustomEditor & { _lastUsageAt: number }
return null
async function changeEditor ({ doc }: { doc?: Doc | null, name?: string }) {
availableEditors.value = (await getAvailableCustomEditors({ doc }))
.map((editor) => {
(editor as XCustomEditor)._lastUsageAt = editorLastUsageTime[editor.name] || 0
return editor as XCustomEditor
})
))
.filter(x => x.status === 'fulfilled' && x.value)
.map(x => (x as any).value)
.sort((a, b) => b._lastUsageAt - a._lastUsageAt)
if (availableEditors.value.length < 1) {
Expand Down
21 changes: 14 additions & 7 deletions src/renderer/plugins/markdown-link/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ import { DOM_ATTR_NAME, DOM_CLASS_NAME } from '@fe/support/args'
import { basename, join } from '@fe/utils/path'
import { getAttachmentURL, openExternal, openPath } from '@fe/services/base'
import { getRepo } from '@fe/services/repo'
import { getAllCustomEditors } from '@fe/services/editor'
import { getAvailableCustomEditors } from '@fe/services/editor'
import { fetchTree } from '@fe/support/api'
import type { Doc } from '@share/types'
import { isMarkdownFile } from '@share/misc'
import { getRenderEnv } from '@fe/services/view'
import { convertResourceState, parseLink } from './lib'
import workerIndexerUrl from './worker-indexer?worker&url'
import type { ParseLinkResult } from '@fe/types'
import type { Doc, ParseLinkResult } from '@fe/types'

function getAnchorElement (target: HTMLElement) {
let cur: HTMLElement | null = target
Expand Down Expand Up @@ -99,21 +98,29 @@ function handleLink (link: HTMLAnchorElement): boolean {
return true
} else if (
(!parsedLink.path && parsedLink.position) || // anchor
isMarkdownFile(parsedLink.path) || // markdown file
getAllCustomEditors() // custom editor support
.some(x => x.when?.({ doc: { path: parsedLink.path, type: 'file', name: basename(parsedLink.path), repo: currentFile.repo } }))
isMarkdownFile(parsedLink.path) // markdown file
) {
_switchDoc(parsedLink)
return true
} else {
openFile()
const doc: Doc = { path: parsedLink.path, type: 'file', name: basename(parsedLink.path), repo: currentFile.repo }

getAvailableCustomEditors({ doc }).then(editors => {
if (editors.length > 0) {
_switchDoc(parsedLink)
} else {
openFile()
}
})

return true
}
} else {
useToast().show('warning', 'Invalid link.')
return true
}
} else {
// is Wiki Link
if (store.state.currentRepo?.name === currentFile.repo && store.state.tree) {
_switchDoc(parseLink(currentFile, href, true, store.state.tree))
} else {
Expand Down
37 changes: 34 additions & 3 deletions src/renderer/services/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { getColorScheme } from './theme'
import { getSetting } from './setting'
import { t } from './i18n'
import { language as markdownLanguage } from 'monaco-editor/esm/vs/basic-languages/markdown/markdown.js'
import { CustomEditor } from '@fe/types'
import type { CustomEditor, CustomEditorCtx } from '@fe/types'

export type SimpleCompletionItem = {
label: string,
Expand All @@ -35,7 +35,8 @@ let currentEditor: CustomEditor | null | undefined
let monaco: typeof Monaco
let editor: Monaco.editor.IStandaloneCodeEditor

const DEFAULT_MAC_FONT_FAMILY = 'MacEmoji, Menlo, Monaco, \'Courier New\', monospace'
export const DEFAULT_MAC_FONT_FAMILY = 'MacEmoji, Menlo, Monaco, \'Courier New\', monospace'
export const DEFAULT_MARKDOWN_EDITOR_NAME = 'default-markdown-editor'

const refreshMarkdownMonarchLanguageDebounce = debounce(() => {
whenEditorReady().then(({ monaco }) => {
Expand Down Expand Up @@ -457,10 +458,15 @@ export function switchEditor (name: string) {
* @param editor Editor
*/
export function registerCustomEditor (editor: CustomEditor) {
if (!editor.component) {
if (!editor.component && editor.name !== DEFAULT_MARKDOWN_EDITOR_NAME) {
throw new Error('Editor component is required')
}

// check if the editor is already registered
if (ioc.get('EDITOR_CUSTOM_EDITOR').some(item => item.name === editor.name)) {
throw new Error(`Editor ${editor.name} is already registered`)
}

ioc.register('EDITOR_CUSTOM_EDITOR', editor)
triggerHook('EDITOR_CUSTOM_EDITOR_CHANGE', { type: 'register' })
}
Expand All @@ -483,6 +489,31 @@ export function getAllCustomEditors () {
return ioc.get('EDITOR_CUSTOM_EDITOR')
}

/**
* Get all available custom editors.
*/
export async function getAvailableCustomEditors (ctx: CustomEditorCtx): Promise<CustomEditor[]> {
const promises = getAllCustomEditors().map(async editor => {
try {
// check if the editor is supported for the other file types
if (ctx.doc && ctx.doc.type !== 'file' && !editor.supportNonNormalFile) {
return null
}

if (await editor.when(ctx)) {
return editor
} else {
return null
}
} catch (error) {
console.error(error)
return null
}
})

return (await Promise.all(promises)).filter(Boolean) as CustomEditor[]
}

/**
* Trigger save.
*/
Expand Down
13 changes: 11 additions & 2 deletions src/renderer/startup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import * as storage from '@fe/utils/storage'
import { basename } from '@fe/utils/path'
import type { BuildInSettings, Doc, FrontMatterAttrs, Repo } from '@fe/types'
import { reloadMainWindow } from '@fe/services/base'
import { createDoc, isMarked, markDoc, switchDoc, toUri, unmarkDoc } from '@fe/services/document'
import { whenEditorReady } from '@fe/services/editor'
import { createDoc, isMarkdownFile, isMarked, markDoc, switchDoc, toUri, unmarkDoc } from '@fe/services/document'
import { DEFAULT_MARKDOWN_EDITOR_NAME, whenEditorReady } from '@fe/services/editor'
import { getLanguage, setLanguage, t } from '@fe/services/i18n'
import { fetchSettings } from '@fe/services/setting'
import { getPurchased } from '@fe/others/premium'
Expand Down Expand Up @@ -224,6 +224,15 @@ registerHook('DOC_PRE_ENSURE_CURRENT_FILE_SAVED', async () => {
}
})

editor.registerCustomEditor({
name: DEFAULT_MARKDOWN_EDITOR_NAME,
displayName: t('editor.default-editor'),
component: null,
when ({ doc }) {
return !!(doc && isMarkdownFile(doc))
}
})

store.watch(() => store.state.currentRepo, (val) => {
toggleOutline(false)
document.documentElement.setAttribute('repo-name', val?.name || '')
Expand Down
1 change: 1 addition & 0 deletions src/renderer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ export type CustomEditor = {
name: string,
displayName: string,
hiddenPreview?: boolean,
supportNonNormalFile?: boolean,
when: (ctx: CustomEditorCtx) => boolean | Promise<boolean>,
component: any,
getIsDirty?: () => boolean | Promise<boolean>,
Expand Down

0 comments on commit 03573d8

Please sign in to comment.