diff --git a/src/i18n.ts b/src/i18n.ts index 00d8047..1e137e1 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -34,6 +34,8 @@ export type TranslationKey = | 'callout-copy-priority' | 'callout-copy-priority-desc' | 'auto-add-block-id' | 'auto-add-block-id-desc' | 'manual-block-id' | 'manual-block-id-desc' + | 'block-id-insert-position' | 'block-id-insert-position-desc' + | 'block-id-end-of-block' | 'block-id-next-line' | 'block-id-next-line-with-gap' | 'modal-block-id' | 'modal-block-id-desc' | 'auto-block-display-text' | 'auto-block-display-text-desc' | 'block-display-word-limit' | 'block-display-word-limit-desc' @@ -49,6 +51,11 @@ export const translations: Record> = { 'auto-add-block-id-desc': 'When enabled, if there is no copyable content, a random block ID (^xxxx) will be automatically added to the end of the current line.' , 'manual-block-id': 'Manually enter Block ID', 'manual-block-id-desc': 'If enabled, you will be prompted to enter a block ID manually.', + 'block-id-insert-position': 'Block ID insert position', + 'block-id-insert-position-desc': 'Choose where to insert the block ID - For special blocks like code blocks and quote blocks, at least one line break will be inserted.', + 'block-id-end-of-block': 'End of current block', + 'block-id-next-line': 'Next line below current block', + 'block-id-next-line-with-gap': 'Two lines below current block (with empty line)', 'modal-block-id': 'Enter block ID', 'modal-block-id-desc': 'Allowed: letters, numbers, hyphens (-), underscores (_). Spaces will be converted to hyphens.', 'error-block-id-empty': 'Block ID cannot be empty', @@ -144,6 +151,11 @@ export const translations: Record> = { 'auto-add-block-id-desc': '启用后,如果没有可复制内容时会自动在当前文本末尾添加一个随机生成的块ID(^xxxx)', 'manual-block-id': '手动输入块ID', 'manual-block-id-desc': '启用后,可以在弹窗中手动输入块ID', + 'block-id-insert-position': '块ID插入位置', + 'block-id-insert-position-desc': '选择生成块ID时的插入位置。对于代码块和引用块等特殊段落,至少会插入一个换行。', + 'block-id-end-of-block': '当前块的末尾', + 'block-id-next-line': '当前块的下方一行', + 'block-id-next-line-with-gap': '当前块的下方两行(中间隔一个空行)', 'modal-block-id': '输入块ID', 'modal-block-id-desc': '仅允许字母、数字、短横线(-)、下划线(_),空格会自动转为短横线。', 'error-block-id-empty': '块ID不能为空', @@ -245,6 +257,11 @@ export const translations: Record> = { 'block-display-char-limit-desc': '非空格分隔語言(如中文 "這是一句話")在塊顯示文本中顯示的最大字符數——當第一行包含非ASCII字符時,會採用此設置。', 'manual-block-id': '手動輸入塊ID', 'manual-block-id-desc': '啟用後,可以在彈窗中手動輸入塊ID', + 'block-id-insert-position': '塊ID插入位置', + 'block-id-insert-position-desc': '選擇生成塊ID時的插入位置。對於代碼塊和引用塊等特殊段落,至少會插入一個換行。', + 'block-id-end-of-block': '當前塊的末尾', + 'block-id-next-line': '當前塊的下方一行', + 'block-id-next-line-with-gap': '當前塊的下方兩行(中間隔一個空行)', 'modal-block-id': '輸入塊ID', 'modal-block-id-desc': '僅允許字母、數字、連字號(-)、底線(_),空格會自動轉為連字號。', 'error-block-id-empty': '塊ID 不能為空', diff --git a/src/main.ts b/src/main.ts index 6c65fb1..3ba1fb6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,6 @@ 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 { ContextData, ContextType, DEFAULT_SETTINGS, EasyCopySettings, LinkFormat, BlockIdInsertPosition } from './type'; import { EasyCopySettingTab } from './settingTab'; import { BlockIdInputModal } from './blockIdModal'; @@ -134,7 +134,7 @@ export default class EasyCopy extends Plugin { } /** - * 检测光标所在行末尾或下一行开头的 block ID + * 检测光标所在行末尾或下 1~2 行开头的 block ID */ private detectBlockRange(editor: Editor, cursorLine: number): { start: number, end: number } { // 如果当前行是列表,那么范围就是当前行(不对,要继续延伸到后面的……只能说开头是定了) @@ -147,14 +147,17 @@ export default class EasyCopy extends Plugin { } const totalLines = editor.lineCount(); + let start = cursorLine; while (start > 0 && this.isContinuousText(editor.getLine(start - 1))) { start--; } + let end = cursorLine; while (end < totalLines - 1 && this.isContinuousText(editor.getLine(end + 1))) { end++; } + return { start, end }; } @@ -261,7 +264,7 @@ export default class EasyCopy extends Plugin { { type: ContextType.HIGHLIGHT, regex: /==([^=]+)==/g , enable: !this.settings.customizeTargets || this.settings.enableHighlight}, { type: ContextType.STRIKETHROUGH, regex: /~~([^~]+)~~/g , enable: !this.settings.customizeTargets || this.settings.enableStrikethrough}, { type: ContextType.INLINECODE, regex: /`([^`]+)`/g , enable: !this.settings.customizeTargets || this.settings.enableInlineCode}, - { type: ContextType.INLINELATEX, regex: /\$([^$]*)\$/g , enable: !this.settings.customizeTargets || this.settings.enableInlineLatex}, + { type: ContextType.INLINELATEX, regex: /\$([^$]+)\$/g , enable: !this.settings.customizeTargets || this.settings.enableInlineLatex}, { type: ContextType.WIKILINK, regex: /\[\[([^\]]+)\]\]/g, enable: !this.settings.customizeTargets || this.settings.enableWikiLink }, ]; @@ -745,11 +748,30 @@ export default class EasyCopy extends Plugin { if (!/\^[a-zA-Z0-9_-]+$/.test(lastLine.trim())) { // 在 block 最后一行末尾插入块ID let insertText = '^' + blockId; + + // 代码块、引用块、数学块等 + const isSpecialBlock = lastLine.startsWith('> ') || lastLine.startsWith('```') || lastLine.startsWith('$$'); + const needsSeparator = lastLine.trim().length > 0 && !lastLine.endsWith(' '); // 末尾需要空格分隔符 - if (lastLine.startsWith('> ') || lastLine.startsWith('``')) { - insertText = '\n' + insertText; - } else if ( lastLine.trim().length > 0 && !lastLine.endsWith(' ')) { - insertText = ' ' + insertText; + // 添加 block id 到末尾——读取设置中的位置 + const insertPosition = this.settings.blockIdInsertPosition; + + if (isSpecialBlock) { + insertText = "\n" + insertText; + } else { + switch (insertPosition) { + case BlockIdInsertPosition.END_OF_BLOCK: + if (needsSeparator) { + insertText = ' ' + insertText; + } + break; + case BlockIdInsertPosition.NEXT_LINE: + insertText = "\n" + insertText; + break; + default: + insertText = "\n" + insertText; + break; + } } editor.replaceRange(insertText, { line: end, ch: lastLine.length }); diff --git a/src/settingTab.ts b/src/settingTab.ts index a4d6251..36ac5e2 100644 --- a/src/settingTab.ts +++ b/src/settingTab.ts @@ -1,6 +1,6 @@ import { App, PluginSettingTab, Setting } from "obsidian"; import EasyCopy from "./main"; -import { LinkFormat } from "./type"; +import { LinkFormat, BlockIdInsertPosition } from "./type"; export class EasyCopySettingTab extends PluginSettingTab { @@ -145,6 +145,21 @@ export class EasyCopySettingTab extends PluginSettingTab { this.display(); })); + if (this.plugin.settings.autoAddBlockId) { + // 新增:块ID插入位置设置 + new Setting(containerEl) + .setName(this.plugin.t('block-id-insert-position')) + .setDesc(this.plugin.t('block-id-insert-position-desc')) + .addDropdown(dropdown => dropdown + .addOption(BlockIdInsertPosition.END_OF_BLOCK, this.plugin.t('block-id-end-of-block')) + .addOption(BlockIdInsertPosition.NEXT_LINE, this.plugin.t('block-id-next-line')) + .setValue(this.plugin.settings.blockIdInsertPosition) + .onChange(async (value) => { + this.plugin.settings.blockIdInsertPosition = value as BlockIdInsertPosition; + await this.plugin.saveSettings(); + })); + } + if (this.plugin.settings.autoAddBlockId) { new Setting(containerEl) .setName(this.plugin.t('manual-block-id')) diff --git a/src/type.ts b/src/type.ts index efff540..2399f6f 100644 --- a/src/type.ts +++ b/src/type.ts @@ -3,6 +3,12 @@ export enum LinkFormat { WIKILINK = 'wiki-link' } +export enum BlockIdInsertPosition { + END_OF_BLOCK = 'end-of-block', // 当前块的末尾 + NEXT_LINE = 'next-line', // 当前块的下方一行 + // NEXT_LINE_WITH_GAP = 'next-line-with-gap' // 当前块的下方两行(中间隔一个空行) +} + export enum ContextType { NULL = 'null', HEADING = 'heading', @@ -51,6 +57,7 @@ export interface EasyCopySettings { calloutCopyPriority: boolean; // Callout 与块ID冲突时,优先复制 Callout autoAddBlockId: boolean; // 是否自动添加 Block ID allowManualBlockId: boolean; // 是否允许手动输入 Block ID + blockIdInsertPosition: BlockIdInsertPosition; // 块ID的插入位置 autoBlockDisplayText: boolean; // 自动为 Block 添加显示文本 blockDisplayWordLimit: number; // Block 显示文本英文单词限制(按空格分隔) blockDisplayCharLimit: number; // Block 显示文本字符限制(非英文语言) @@ -81,6 +88,7 @@ export const DEFAULT_SETTINGS: EasyCopySettings = { calloutCopyPriority: true, autoAddBlockId: false, // 默认关闭 allowManualBlockId: false, // 默认关闭 + blockIdInsertPosition: BlockIdInsertPosition.END_OF_BLOCK, // 默认在块末尾插入 autoBlockDisplayText: true, blockDisplayWordLimit: 3, // 英文单词限制:3个单词 blockDisplayCharLimit: 5, // 字符限制:5个字符