feat: 🎸 support more commands and options

- 3 new commands to copy current file/block links
- option to add display text for block link

 Closes: #7 #8
This commit is contained in:
Moy 2025-05-21 00:00:17 +08:00
parent 1f44a9545b
commit 40f9e40b4b
4 changed files with 165 additions and 59 deletions

View file

@ -11,6 +11,7 @@ export type TranslationKey =
| 'inline-code-copied' | 'block-id-copied' | 'note-link-copied' | 'heading-copied' | 'strikethrough-copied'
| 'inline-latex-copied' | 'bold-copied' | 'highlight-copied' | 'italic-copied' | 'link-text-copied' | 'link-url-copied'
| 'format' | 'add-to-menu' | 'add-to-menu-desc' | 'show-notice' | 'show-notice-desc'
| 'add-extra-commands' | 'add-extra-commands-desc'
| 'use-heading-as-display' | 'use-heading-as-display-desc' | 'block-id'
| 'use-frontmatter-as-display' | 'use-frontmatter-as-display-desc' | 'frontmatter-key' | 'frontmatter-key-desc'
| 'link-format'| 'link-format-desc' | 'markdown-link' | 'wiki-link' | 'contextual-copy'
@ -26,6 +27,8 @@ export type TranslationKey =
| 'auto-add-block-id' | 'auto-add-block-id-desc'
| 'manual-block-id' | 'manual-block-id-desc'
| 'modal-block-id' | 'modal-block-id-desc'
| 'auto-block-display-text' | 'auto-block-display-text-desc'
| 'generate-current-block-link-auto' | 'generate-current-block-link-manual'
| 'error-block-id-empty' | 'error-block-id-invalid';
// 本地化翻译字典
@ -66,6 +69,8 @@ export const translations: Record<Language, Record<TranslationKey, string>> = {
'target': 'Target',
'add-to-menu': 'Add to menu',
'add-to-menu-desc': 'Add the command to the context menu',
'add-extra-commands': 'Add extra commands',
'add-extra-commands-desc': 'Enable to add "Copy current note link" and "Generate & copy current block link" commands to the command palette',
'show-notice': 'Show notice',
'show-notice-desc': 'Show notification when content is copied',
'use-heading-as-display': 'Use heading as display text',
@ -90,10 +95,14 @@ export const translations: Record<Language, Record<TranslationKey, string>> = {
'enable-inline-latex-desc': 'Enable copying inline LaTeX like $latex example$',
'enable-link': 'Enable link title/url',
'enable-link-desc': 'Enable copying link like [linktitle](linkurl) - the plugin will copy the title or the URL of the link based on the current cursor position.',
'auto-block-display-text': 'Auto display text for block links',
'auto-block-display-text-desc': 'Automatically generate display text for block ID links (if disabled, block links will not show display text)',
// 命令名称
'contextual-copy': 'Contextual copy',
'copy-current-file-link': 'Copy current file link',
'generate-current-block-link-auto': 'Generate & copy current block link (auto)',
'generate-current-block-link-manual': 'Generate & copy current block link (manual)',
'file-link-copied': 'File link copied!',
},
[Language.ZH]: {
@ -127,6 +136,8 @@ export const translations: Record<Language, Record<TranslationKey, string>> = {
'target': '复制对象',
'add-to-menu': '添加到菜单',
'add-to-menu-desc': '将命令添加到右键菜单',
'add-extra-commands': '添加拓展命令',
'add-extra-commands-desc': '启用后,将在命令面板中添加“复制当前笔记的链接”和“生成并复制当前块的链接”命令',
'show-notice': '显示通知',
'show-notice-desc': '复制内容时显示通知提示',
'use-heading-as-display': '使用标题作为显示文本',
@ -155,16 +166,24 @@ export const translations: Record<Language, Record<TranslationKey, string>> = {
// 命令名称
'contextual-copy': '智能复制',
'copy-current-file-link': '复制当前文件链接',
'generate-current-block-link-auto': '生成并复制当前块链接(自动)',
'generate-current-block-link-manual': '生成并复制当前块链接(手动)',
'file-link-copied': '当前文件链接已复制!',
'use-frontmatter-as-display': '使用 Frontmatter 属性作为显示文本',
'use-frontmatter-as-display-desc': '启用后,使用指定 Frontmatter 属性的值作为链接显示文本',
'frontmatter-key': 'Frontmatter 属性名',
'frontmatter-key-desc': '用于显示文本的 Frontmatter 属性名默认title',
'auto-block-display-text': '块链接自动显示文本',
'auto-block-display-text-desc': '自动为块ID链接生成显示文本关闭后块链接不显示文本',
},
[Language.ZH_TW]: {
// 复制 Block ID
'auto-add-block-id': '自動新增塊ID',
'auto-add-block-id-desc': '啟用後若沒有可複製內容時會自動在當前文本末尾新增一個隨機的塊ID^xxxx',
'add-extra-commands': '添加擴展命令',
'add-extra-commands-desc': '啟用後,會在命令面板中新增「複製當前筆記鏈接」和「生成並複製當前塊鏈接」命令',
'auto-block-display-text': '塊連結自動顯示文本',
'auto-block-display-text-desc': '自動為塊ID連結生成顯示文本關閉後塊連結不顯示文本',
'manual-block-id': '手動輸入塊ID',
'manual-block-id-desc': '啟用後可以在彈窗中手動輸入塊ID',
'modal-block-id': '輸入塊ID',
@ -221,6 +240,8 @@ export const translations: Record<Language, Record<TranslationKey, string>> = {
// 命令名称
'contextual-copy': '智能複製',
'copy-current-file-link': '複製當前文件連結',
'generate-current-block-link-auto': '生成並複製當前塊連結(自動)',
'generate-current-block-link-manual': '生成並複製當前塊連結(手動)',
'file-link-copied': '當前文件連結已複製!',
'use-frontmatter-as-display': '使用屬性作為顯示文本',
'use-frontmatter-as-display-desc': '啟用後,使用指定屬性的值作為連結顯示文本',

View file

@ -1,4 +1,4 @@
import { Editor, MarkdownView, Notice, Plugin, Menu, Platform } from 'obsidian';
import { Editor, MarkdownView, Notice, Plugin, Menu, Platform, MarkdownFileInfo } from 'obsidian';
import { Language, TranslationKey, I18n } from './i18n';
import { ContextData, ContextType, DEFAULT_SETTINGS, EasyCopySettings, LinkFormat } from './type';
import { EasyCopySettingTab } from './settingTab';
@ -34,14 +34,50 @@ export default class EasyCopy extends Plugin {
}
});
// 新增:复制当前文件链接命令
this.addCommand({
id: 'copy-current-file-link',
name: this.t('copy-current-file-link'),
callback: () => {
this.copyCurrentFileLink();
}
});
if (this.settings.addExtraCommands){
// 新增:复制当前文件链接命令
this.addCommand({
id: 'copy-current-file-link',
name: this.t('copy-current-file-link'),
callback: () => {
this.copyCurrentFileLink();
}
});
// 新增:复制当前文件链接命令
this.addCommand({
id: 'generate-current-block-link-auto',
name: this.t('generate-current-block-link-auto'),
editorCallback: (editor: Editor, fileInfo: MarkdownFileInfo) => {
const file = fileInfo.file;
if (!file){
new Notice(this.t('no-file'));
return;
}
const filename = file.basename;
// 自动生成名称
this.insertBlockIdAndCopyLink(editor, filename, false);
}
});
// 新增:复制当前文件链接命令
this.addCommand({
id: 'generate-current-block-link-manual',
name: this.t('generate-current-block-link-manual'),
editorCallback: (editor: Editor, fileInfo: MarkdownFileInfo) => {
const file = fileInfo.file;
if (!file){
new Notice(this.t('no-file'));
return;
}
const filename = file.basename;
// 手动输入名称
this.insertBlockIdAndCopyLink(editor, filename, true);
}
});
}
// This adds a settings tab so the user can configure various aspects of the plugin
this.addSettingTab(new EasyCopySettingTab(this.app, this));
@ -304,54 +340,11 @@ export default class EasyCopy extends Plugin {
if (contextType.type == ContextType.NULL) {
// 如果启用自动添加 Block ID
if (this.settings.autoAddBlockId) {
let blockId = '';
const isManual = this.settings.allowManualBlockId;
await this.insertBlockIdAndCopyLink(editor, filename, isManual);
if (isManual) {
// 用 Modal 弹窗获取 Block ID
const modalBlockId = await new Promise<string | null>((resolve) => {
new BlockIdInputModal(this.app,
this.t('modal-block-id'), this.t('modal-block-id-desc'),
this.t.bind(this),
(result: any) => {
resolve(result ?? null);
}
).open();
});
if (!modalBlockId) return;
blockId = modalBlockId;
} else {
// 随机生成
const randomId = Math.random().toString(36).substr(2, 6);
blockId = `${randomId}`;
}
// —— 新逻辑:定位 block段落末尾 ——
const cursor = editor.getCursor();
const { start, end } = this.detectBlockRange(editor, cursor.line);
const firstLine = editor.getLine(start);
const lastLine = editor.getLine(end);
// 检查 block 最后一行末是否已有块ID
if (!/\^[a-zA-Z0-9_-]+$/.test(lastLine.trim())) {
// 在 block 最后一行末尾插入块ID
let insertText = '^'+blockId;
if (lastLine.startsWith('> ') || lastLine.startsWith('``')) {
insertText = '\n' + insertText;
} else if (!lastLine.endsWith(' ')) {
insertText = ' ' + insertText;
}
editor.replaceRange(insertText, { line: end, ch: lastLine.length });
// 如果不是手动输入的,使用简短的显示文本
const useBrief = !isManual;
// 复制块ID链接
this.copyBlockLink(blockId, filename, useBrief, firstLine);
return;
}
}
new Notice(this.t('no-content'));
@ -425,9 +418,12 @@ export default class EasyCopy extends Plugin {
/*
*
*/
private copyBlockLink(content: string, filename: string, useBrief: boolean, firstLine: string=''): void {
private copyBlockLink(content: string, filename: string, useBrief: boolean, firstLine=''): void {
const blockId = content;
let text = firstLine;
const autoDisplayText = this.settings.autoBlockDisplayText;
// 先去掉结尾的 ^ 及其后面的内容(如果有的话)
text = text.replace(/\^.*\s*$/, '');
@ -465,15 +461,22 @@ export default class EasyCopy extends Plugin {
} else {
displayText = tempText;
}
} else {
displayText = briefText;
}
}
}
// displayText = "^"+displayText;
let blockIdLink = this.settings.linkFormat === LinkFormat.WIKILINK
? `[[${filename}#^${blockId}|${displayText}]]`
: `[^${displayText}](${filename}#^${blockId})`;
const blockIdLink = this.settings.linkFormat === LinkFormat.WIKILINK
? `[[${filename}#^${blockId}|${displayText}]]`
: `[^${displayText}](${filename}#^${blockId})`;
if (!autoDisplayText) {
blockIdLink = this.settings.linkFormat === LinkFormat.WIKILINK
? `[[${filename}#^${blockId}]]`
: `[](${filename}#^${blockId})`;
}
navigator.clipboard.writeText(blockIdLink);
if (this.settings.showNotice) {
@ -564,6 +567,60 @@ export default class EasyCopy extends Plugin {
}
}
/**
* Block ID
* @param editor
* @param filename
*/
private async insertBlockIdAndCopyLink(editor: Editor, filename: string, isManual=false): Promise<void> {
let blockId = '';
if (isManual) {
// 用 Modal 弹窗获取 Block ID
const modalBlockId = await new Promise<string | null>((resolve) => {
new BlockIdInputModal(this.app,
this.t('modal-block-id'), this.t('modal-block-id-desc'),
this.t.bind(this),
(result: any) => {
resolve(result ?? null);
}
).open();
});
if (!modalBlockId) return;
blockId = modalBlockId;
} else {
// 随机生成
const randomId = Math.random().toString(36).substr(2, 6);
blockId = `${randomId}`;
}
// —— 新逻辑:定位 block段落末尾 ——
const cursor = editor.getCursor();
const { start, end } = this.detectBlockRange(editor, cursor.line);
const firstLine = editor.getLine(start);
const lastLine = editor.getLine(end);
// 检查 block 最后一行末是否已有块ID
if (!/\^[a-zA-Z0-9_-]+$/.test(lastLine.trim())) {
// 在 block 最后一行末尾插入块ID
let insertText = '^' + blockId;
if (lastLine.startsWith('> ') || lastLine.startsWith('``')) {
insertText = '\n' + insertText;
} else if (!lastLine.endsWith(' ')) {
insertText = ' ' + insertText;
}
editor.replaceRange(insertText, { line: end, ch: lastLine.length });
// 如果不是手动输入的,使用简短的显示文本
const useBrief = !isManual;
// 生成之后复制块ID链接
this.copyBlockLink(blockId, filename, useBrief, firstLine);
}
}
/**
* 使Obsidian的语言设置
*/

View file

@ -26,6 +26,16 @@ export class EasyCopySettingTab extends PluginSettingTab {
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName(this.plugin.t('add-extra-commands'))
.setDesc(this.plugin.t('add-extra-commands-desc'))
.addToggle(toggle => toggle
.setValue(this.plugin.settings.addExtraCommands)
.onChange(async (value) => {
this.plugin.settings.addExtraCommands = value;
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName(this.plugin.t('show-notice'))
.setDesc(this.plugin.t('show-notice-desc'))
@ -68,6 +78,20 @@ export class EasyCopySettingTab extends PluginSettingTab {
);
}
// 新增:自动为 Block 链接添加显示文本
new Setting(containerEl)
.setName(this.plugin.t('auto-block-display-text'))
.setDesc(this.plugin.t('auto-block-display-text-desc'))
.addToggle(toggle => toggle
.setValue(this.plugin.settings.autoBlockDisplayText)
.onChange(async (value) => {
this.plugin.settings.autoBlockDisplayText = value;
await this.plugin.saveSettings();
this.display();
})
);
new Setting(containerEl)
.setName(this.plugin.t('use-heading-as-display'))
.setDesc(this.plugin.t('use-heading-as-display-desc'))

View file

@ -28,6 +28,7 @@ export interface EasyCopySettings {
useFrontmatterAsDisplay: boolean; // 是否使用 frontmatter 属性作为显示文本
frontmatterKey: string; // frontmatter 属性名
addToMenu: boolean;
addExtraCommands: boolean;
showNotice: boolean;
useHeadingAsDisplayText: boolean;
linkFormat: LinkFormat;
@ -41,12 +42,14 @@ export interface EasyCopySettings {
enableLink: boolean;
autoAddBlockId: boolean; // 是否自动添加 Block ID
allowManualBlockId: boolean; // 是否允许手动输入 Block ID
autoBlockDisplayText: boolean; // 自动为 Block 添加显示文本
}
export const DEFAULT_SETTINGS: EasyCopySettings = {
useFrontmatterAsDisplay: false,
frontmatterKey: 'title',
addToMenu: true,
addExtraCommands: true,
showNotice: true,
useHeadingAsDisplayText: true,
linkFormat: LinkFormat.WIKILINK,
@ -60,4 +63,5 @@ export const DEFAULT_SETTINGS: EasyCopySettings = {
enableLink: true,
autoAddBlockId: false, // 默认关闭
allowManualBlockId: false, // 默认关闭
autoBlockDisplayText: true,
}