From 0e5cfbc8ada3cc66977137aec6e10be97754bfaf Mon Sep 17 00:00:00 2001 From: purocean Date: Tue, 3 Jan 2023 15:43:15 +0800 Subject: [PATCH] feat(macro): add global macro replacement setting --- help/FEATURES.md | 4 ++ help/FEATURES_ZH-CN.md | 4 ++ src/renderer/plugins/markdown-macro.ts | 69 +++++++++++++++++++++++++- src/renderer/services/setting.ts | 2 +- src/renderer/startup.ts | 2 +- src/renderer/types.ts | 5 +- src/share/i18n/languages/en.ts | 8 +++ src/share/i18n/languages/zh-CN.ts | 8 +++ 8 files changed, 96 insertions(+), 6 deletions(-) diff --git a/help/FEATURES.md b/help/FEATURES.md index 59fcf3b6..9e758490 100644 --- a/help/FEATURES.md +++ b/help/FEATURES.md @@ -598,6 +598,10 @@ Using macro replacement may lead to inaccurate correspondence between source cod The `define` field can define some text replacement mappings. Supports definition in another file, supports macro expressions. For details, please refer to the Front Matter at the top of this document. +::: tip +You can define global macros in the settings. But you still need to define `enableMacro: true` in Front Matter. +::: + - App Name: --APP_NAME-- - App Version: --APP_VERSION-- - From Another File: --TEST_DEFINE-- diff --git a/help/FEATURES_ZH-CN.md b/help/FEATURES_ZH-CN.md index f3bd445e..e6f74a6d 100644 --- a/help/FEATURES_ZH-CN.md +++ b/help/FEATURES_ZH-CN.md @@ -598,6 +598,10 @@ Yank Note 允许你在页面中嵌入宏,用以动态地替换文档。 Front Matter 中的 `define` 字段可以定义一些文本替换映射。支持在另一个文件定义,支持宏表达式。具体可参考本文件顶部 Front Matter 部分。 +::: tip +你还可以在设置中配置 *全局宏替换* ,这样所有文档都可以使用。不过,你仍然需要在 Front Matter 中定义 `enableMacro: true`。 +::: + - 应用名: --APP_NAME-- - 应用版本: --APP_VERSION-- - 另一个文件的定义: --TEST_DEFINE-- diff --git a/src/renderer/plugins/markdown-macro.ts b/src/renderer/plugins/markdown-macro.ts index ac4ce8c9..95752b0a 100644 --- a/src/renderer/plugins/markdown-macro.ts +++ b/src/renderer/plugins/markdown-macro.ts @@ -1,7 +1,7 @@ import { escapeRegExp, omit } from 'lodash-es' import frontMatter from 'front-matter' import type { Plugin } from '@fe/context' -import type { Doc } from '@fe/types' +import type { BuildInSettings, Doc } from '@fe/types' import type { MenuItem } from '@fe/services/status-bar' import { render } from '@fe/services/view' import { t } from '@fe/services/i18n' @@ -23,6 +23,7 @@ const magicNewline = '--yn-macro-new-line--' const AsyncFunction = Object.getPrototypeOf(async () => 0).constructor let macroOuterVars = {} +let globalMacroReplacement: Record = {} const globalVars = { $export: exportVar, @@ -95,7 +96,7 @@ function transform ( callback?: (result: Result | Promise, match: string, matchPos: number) => void }, ) { - const define = { ...vars.define, ...options.cache.$define } + const define = { ...globalMacroReplacement, ...vars.define, ...options.cache.$define } vars.define = define const keys = Object.keys(define) if (keys.length) { @@ -421,5 +422,69 @@ export default { [/=\]/, { token: 'keyword', next: '@pop', nextEmbedded: '@pop' }] ] }) + + ctx.setting.changeSchema(schema => { + schema.groups.push({ label: 'T_setting-panel.tabs.macros', value: 'macros' }) + schema.properties.macros = { + defaultValue: [], + type: 'array', + title: 'T_setting-panel.schema.repos.repos', + format: 'table', + group: 'macros', + items: { + type: 'object', + title: 'T_setting-panel.schema.macros.macros', + properties: { + match: { + type: 'string', + title: 'T_setting-panel.schema.macros.match', + defaultValue: '', + maxLength: 50, + options: { + inputAttributes: { placeholder: 'T_setting-panel.schema.macros.match-placeholder' } + }, + }, + replace: { + type: 'string', + title: 'T_setting-panel.schema.macros.replace', + defaultValue: '', + format: 'textarea', + options: { + inputAttributes: { + placeholder: 'T_setting-panel.schema.macros.replace-placeholder', + style: 'height: auto; resize: vertical; min-height: 37px;', + rows: 1, + } + }, + } + } as any + }, + } + }) + + ctx.registerHook('SETTING_BEFORE_WRITE', ({ settings }) => { + if (settings.macros && Array.isArray(settings.macros)) { + settings.macros = settings.macros.filter(x => x.match && x.replace) + } + }) + + function buildGlobalMacroReplacement (settings: BuildInSettings) { + const macros = settings.macros || [] + globalMacroReplacement = {} + macros.forEach(x => { + globalMacroReplacement[x.match] = x.replace + }) + } + + ctx.registerHook('SETTING_FETCHED', ({ settings }) => { + buildGlobalMacroReplacement(settings) + }, true) + + ctx.registerHook('SETTING_CHANGED', ({ changedKeys, settings }) => { + if (changedKeys.includes('macros')) { + buildGlobalMacroReplacement(settings) + ctx.view.render() + } + }) } } as Plugin diff --git a/src/renderer/services/setting.ts b/src/renderer/services/setting.ts index 21473657..64f4a74d 100644 --- a/src/renderer/services/setting.ts +++ b/src/renderer/services/setting.ts @@ -498,7 +498,7 @@ export async function writeSettings (settings: Record) { delete data.theme } - triggerHook('SETTING_BEFORE_WRITE', { settings } as any) + triggerHook('SETTING_BEFORE_WRITE', { settings: data } as any) await api.writeSettings(data) return await fetchSettings() diff --git a/src/renderer/startup.ts b/src/renderer/startup.ts index 2b3becce..d58b8b53 100644 --- a/src/renderer/startup.ts +++ b/src/renderer/startup.ts @@ -58,7 +58,7 @@ export default function startup () { const doc = getLastOpenFile() switchDoc(doc) -function changeLanguage ({ settings }: { settings: BuildInSettings }) { +function changeLanguage ({ settings }: { settings: Partial }) { if (settings.language && settings.language !== getLanguage()) { setLanguage(settings.language) } diff --git a/src/renderer/types.ts b/src/renderer/types.ts index fe63f620..88a64fcc 100644 --- a/src/renderer/types.ts +++ b/src/renderer/types.ts @@ -163,7 +163,7 @@ export type FileSort = { by: 'mtime' | 'birthtime' | 'name' | 'serial', order: ' export type ThemeName = 'system' | 'dark' | 'light' export type LanguageName = 'system' | Language export type ExportType = 'print' | 'pdf' | 'docx' | 'html' | 'rst' | 'adoc' -export type SettingGroup = 'repos' | 'appearance' | 'editor' | 'image' | 'proxy' | 'other' +export type SettingGroup = 'repos' | 'appearance' | 'editor' | 'image' | 'proxy' | 'other' | 'macros' export type RegistryHostname = 'registry.npmjs.org' | 'registry.npmmirror.com' export type PrintOpts = { @@ -233,6 +233,7 @@ export interface Extension { export interface BuildInSettings { 'repos': Repo[], + 'macros': { match: string, replace: string }[], 'theme': ThemeName, 'language': LanguageName, 'auto-save': number, @@ -381,7 +382,7 @@ export type BuildInHookTypes = { SETTING_PANEL_BEFORE_SHOW: {}, SETTING_CHANGED: { changedKeys: (keyof BuildInSettings)[], oldSettings: BuildInSettings, settings: BuildInSettings } SETTING_FETCHED: { settings: BuildInSettings, oldSettings: BuildInSettings }, - SETTING_BEFORE_WRITE: { settings: BuildInSettings }, + SETTING_BEFORE_WRITE: { settings: Partial }, EXTENSION_READY: { extensions: Extension[] }, CODE_RUNNER_CHANGE: { type: 'register' | 'remove' }, PLUGIN_HOOK: { diff --git a/src/share/i18n/languages/en.ts b/src/share/i18n/languages/en.ts index c7636015..1ef630be 100644 --- a/src/share/i18n/languages/en.ts +++ b/src/share/i18n/languages/en.ts @@ -347,6 +347,7 @@ const data = { 'editor': 'Editor', 'image': 'Image', 'proxy': 'Proxy', + 'macros': 'Macro', 'other': 'Other', }, 'schema': { @@ -404,6 +405,13 @@ const data = { 'bypass-list': 'Bypass List', 'pac-url': 'PAC URL', }, + 'macros': { + 'macros': 'Macros', + 'match': 'Match', + 'replace': 'Replace', + 'match-placeholder': '%foo%', + 'replace-placeholder': '%foo% -> BAR', + }, } }, 'quick-open': { diff --git a/src/share/i18n/languages/zh-CN.ts b/src/share/i18n/languages/zh-CN.ts index d47ff0fd..1c0264d0 100644 --- a/src/share/i18n/languages/zh-CN.ts +++ b/src/share/i18n/languages/zh-CN.ts @@ -397,6 +397,13 @@ const data: BaseLanguage = { 'bypass-list': 'Bypass List', 'pac-url': 'PAC URL', }, + 'macros': { + 'macros': '宏', + 'match': '匹配', + 'replace': '替换', + 'match-placeholder': '%foo%', + 'replace-placeholder': '%foo% -> BAR', + }, }, 'tabs': { 'repos': '仓库', @@ -404,6 +411,7 @@ const data: BaseLanguage = { 'editor': '编辑器', 'image': '图片', 'proxy': '代理', + 'macros': '宏替换', 'other': '其他', }, },