build: 1.5.3

This commit is contained in:
Moy 2026-04-22 14:32:47 +08:00
parent d327b5013a
commit f93ad24367
6 changed files with 87 additions and 8 deletions

View file

@ -15,6 +15,7 @@ export type TranslationKey =
| 'add-extra-commands' | 'add-extra-commands-desc'
| 'use-heading-as-display' | 'use-heading-as-display-desc' | 'heading-link-separator' | 'heading-link-separator-desc' | 'block-id'
| 'simplified-heading-to-note-link' | 'simplified-heading-to-note-link-desc'
| 'strict-heading-match' | 'strict-heading-match-desc'
| 'use-frontmatter-as-display' | 'use-frontmatter-as-display-desc' | 'frontmatter-key' | 'frontmatter-key-desc'
| 'link-format'| 'link-format-desc' | 'link-format-obsidian' | 'markdown-link' | 'wiki-link' | 'contextual-copy'
| 'copy-current-file-link' | 'file-link-copied'
@ -97,6 +98,8 @@ export const translations: Record<Language, Record<TranslationKey, string>> = {
'use-heading-as-display-desc': 'Use the heading text as display text in copied heading links',
'simplified-heading-to-note-link': 'Simplify link when filename matches heading',
'simplified-heading-to-note-link-desc': 'When the filename matches the heading text (ignoring spaces), create a note link instead of a heading link',
'strict-heading-match': 'Strict heading match',
'strict-heading-match-desc': 'When enabled, filename must exactly match the heading (case-insensitive). When disabled, the link is also simplified if the filename contains the heading as a substring (e.g. "260422_note" matches heading "note").',
'heading-link-separator': 'Heading Link: Separator between filename and heading',
'heading-link-separator-desc': 'Customize the separator symbol between filename and heading (only shown when "Use heading as display text" is disabled)',
'link-format': 'Link format',
@ -193,6 +196,8 @@ export const translations: Record<Language, Record<TranslationKey, string>> = {
'use-heading-as-display-desc': '在复制的标题链接中,使用标题文本作为显示文本',
'simplified-heading-to-note-link': '文件名匹配标题时简化链接',
'simplified-heading-to-note-link-desc': '当文件名与标题文本匹配时(相同或包含),直接创建笔记链接而不是标题链接',
'strict-heading-match': '严格匹配',
'strict-heading-match-desc': '启用后,文件名必须与标题完全相同(忽略大小写)才会简化。关闭时,文件名包含标题也会简化(如文件名 "260422_note" 匹配标题 "note")。',
'heading-link-separator': '标题链接:文件名与标题间的连接符',
'heading-link-separator-desc': '自定义文件名与标题之间的连接符号(仅在禁用"使用标题作为显示文本"时显示)',
'link-format': '链接格式',
@ -299,6 +304,8 @@ export const translations: Record<Language, Record<TranslationKey, string>> = {
'use-heading-as-display-desc': '在複製的標題連結中,使用標題文本作為顯示文本',
'simplified-heading-to-note-link': '檔案名匹配標題時簡化連結',
'simplified-heading-to-note-link-desc': '當檔案名與標題文本匹配時(相同或包含),直接建立筆記連結而不是標題連結',
'strict-heading-match': '嚴格匹配',
'strict-heading-match-desc': '啟用後,檔案名必須與標題完全相同(忽略大小寫)才會簡化。關閉時,檔案名包含標題也會簡化(如檔案名 "260422_note" 匹配標題 "note")。',
'heading-link-separator': '標題連結:檔案名與標題間的連接符',
'heading-link-separator-desc': '自定義檔案名與標題之間的連接符號(僅在禁用「使用標題作為顯示文本」時顯示)',
'link-format': '連結格式',

View file

@ -276,17 +276,17 @@ describe('buildHeadingLink', () => {
});
});
// -- compareIgnoreCase: strict equality (no substring matching) -----------
// -- compareIgnoreCase: default (includes) vs strict matching -----------
describe('filename-heading matching (strict equality)', () => {
it('does not simplify when filename contains heading as substring', () => {
describe('filename-heading matching (default: includes)', () => {
it('simplifies when filename contains heading as substring', () => {
const result = buildHeadingLink({
...defaults,
heading: 'Java',
filename: 'JavaScript',
});
expect(result.link).toBe('[[JavaScript#Java|Java]]');
expect(result.isNoteLink).toBe(false);
expect(result.link).toBe('[[JavaScript|Java]]');
expect(result.isNoteLink).toBe(true);
});
it('does not simplify when heading contains filename as substring', () => {
@ -299,15 +299,69 @@ describe('buildHeadingLink', () => {
expect(result.isNoteLink).toBe(false);
});
it('does not simplify on space-removed substring match', () => {
it('simplifies on space-removed substring match', () => {
const result = buildHeadingLink({
...defaults,
heading: 'Some Thing',
filename: 'SomeThingElse',
});
expect(result.link).toBe('[[SomeThingElse|Some Thing]]');
expect(result.isNoteLink).toBe(true);
});
it('simplifies when filename contains heading (e.g. date-prefixed notes)', () => {
const result = buildHeadingLink({
...defaults,
heading: 'note',
filename: '260422_note',
});
expect(result.link).toBe('[[260422_note|note]]');
expect(result.isNoteLink).toBe(true);
});
});
describe('filename-heading matching (strict mode)', () => {
const strict = { ...defaults, strictHeadingMatch: true };
it('does not simplify when filename contains heading as substring', () => {
const result = buildHeadingLink({
...strict,
heading: 'Java',
filename: 'JavaScript',
});
expect(result.link).toBe('[[JavaScript#Java|Java]]');
expect(result.isNoteLink).toBe(false);
});
it('does not simplify on space-removed substring match', () => {
const result = buildHeadingLink({
...strict,
heading: 'Some Thing',
filename: 'SomeThingElse',
});
expect(result.link).toBe('[[SomeThingElse#Some Thing|Some Thing]]');
expect(result.isNoteLink).toBe(false);
});
it('still simplifies on exact case-insensitive match', () => {
const result = buildHeadingLink({
...strict,
heading: 'mynote',
filename: 'MyNote',
});
expect(result.link).toBe('[[MyNote|mynote]]');
expect(result.isNoteLink).toBe(true);
});
it('still simplifies on space-removed exact match', () => {
const result = buildHeadingLink({
...strict,
heading: 'Some Thing',
filename: 'SomeThing',
});
expect(result.link).toBe('[[SomeThing|Some Thing]]');
expect(result.isNoteLink).toBe(true);
});
});
// -- Combinatorial --------------------------------------------------------

View file

@ -34,6 +34,7 @@ export interface BuildHeadingLinkOptions {
linkFormat: LinkFormat;
useHeadingAsDisplayText: boolean;
headingLinkSeparator: string;
strictHeadingMatch?: boolean;
}
export interface BuildHeadingLinkResult {
@ -42,7 +43,7 @@ export interface BuildHeadingLinkResult {
}
export function buildHeadingLink(options: BuildHeadingLinkOptions): BuildHeadingLinkResult {
const { filename, linkFormat, useHeadingAsDisplayText, headingLinkSeparator } = options;
const { filename, linkFormat, useHeadingAsDisplayText, headingLinkSeparator, strictHeadingMatch } = options;
const filenameOrTitle = options.frontmatterTitle || filename;
// 提取标题文本和级别
@ -65,7 +66,9 @@ export function buildHeadingLink(options: BuildHeadingLinkOptions): BuildHeading
let isNoteLink = false;
const compareIgnoreCase = (a: string, b: string): boolean =>
a.toLowerCase() === b.toLowerCase();
strictHeadingMatch
? a.toLowerCase() === b.toLowerCase()
: a.toLowerCase() === b.toLowerCase() || a.toLowerCase().includes(b.toLowerCase());
// 特殊情况:如果文件名包含标题,则不添加指向标题的 # 部分
// 我自己的情况——会把 SomeThing 给拆成 Some Thing 来做标题,所以也考虑空格替换的部分

View file

@ -563,6 +563,7 @@ export default class EasyCopy extends Plugin {
linkFormat: this.getEffectiveLinkFormat(),
useHeadingAsDisplayText: this.settings.useHeadingAsDisplayText,
headingLinkSeparator: this.settings.headingLinkSeparator,
strictHeadingMatch: this.settings.strictHeadingMatch,
});
navigator.clipboard.writeText(link);

View file

@ -159,6 +159,18 @@ export class EasyCopySettingTab extends PluginSettingTab {
this.display();
})));
if (this.plugin.settings.simplifiedHeadingToNoteLink) {
formatGroup.addSetting(setting => setting
.setName(this.plugin.t('strict-heading-match'))
.setDesc(this.plugin.t('strict-heading-match-desc'))
.addToggle(toggle => toggle
.setValue(this.plugin.settings.strictHeadingMatch)
.onChange(async (value) => {
this.plugin.settings.strictHeadingMatch = value;
await this.plugin.saveSettings();
})));
}
// 新增:是否使用 frontmatter 属性作为显示文本
formatGroup.addSetting(setting => setting

View file

@ -42,6 +42,7 @@ export interface EasyCopySettings {
useHeadingAsDisplayText: boolean;
headingLinkSeparator: string; // 文件名和标题间的连接符
simplifiedHeadingToNoteLink: boolean; // 是否简化标题到笔记链接
strictHeadingMatch: boolean; // 标题与文件名简化匹配时是否使用严格匹配
linkFormat: LinkFormat;
customizeTargets: boolean;
enableInlineCode: boolean;
@ -73,6 +74,7 @@ export const DEFAULT_SETTINGS: EasyCopySettings = {
useHeadingAsDisplayText: true,
headingLinkSeparator: '#',
simplifiedHeadingToNoteLink: true,
strictHeadingMatch: false,
linkFormat: LinkFormat.OBSIDIAN,
customizeTargets: false,
enableInlineCode: true,