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': '其他',
},
},