mirror of
https://github.com/moyf/easy-copy.git
synced 2026-07-22 05:43:47 +00:00
A soft-wrapped multi-line item is ONE block in Obsidian (the block id sits at the end of its last line and the cache span covers every line), but the auto display text was built from a single line: the range's first line when inserting a new id, the id-bearing last line when copying an existing one. Multi-line blocks therefore got truncated aliases. - new EasyCopy.getBlockText(): walks up to the block's first line (bullet or paragraph start, also from a continuation line under the cursor), extends through the soft-wrapped continuation lines, strips per-line trailing block ids, and joins with newlines - both copy paths pass the full block text; extractBlockDisplayText joins the lines with single spaces (blank lines dropped) before applying the existing word/char limits - the trailing-id strip is now ^[a-zA-Z0-9_-]+$ per line instead of the greedy /\^.*$/, so a mid-line caret (e.g. 2^10) survives - firstLine renamed blockText through the pipeline; 5 new tests
116 lines
2.6 KiB
TypeScript
116 lines
2.6 KiB
TypeScript
import { extractBlockDisplayText, sanitizeHeadingForLink, stripWikiBrackets } from './linkBuilder';
|
|
|
|
export interface CopyMetadata {
|
|
clipboardText: string;
|
|
sourceFilePath: string;
|
|
subpath: string;
|
|
alias: string;
|
|
isEmbed: boolean;
|
|
timestamp: number;
|
|
}
|
|
|
|
export interface BuildBlockCopyMetadataInput {
|
|
clipboardText: string;
|
|
sourceFilePath: string;
|
|
blockId: string;
|
|
useBrief: boolean;
|
|
/** 块的完整文本(可多行,行尾块 ID 会被清理) */
|
|
blockText: string;
|
|
autoBlockDisplayText: boolean;
|
|
autoEmbedBlockLink: boolean;
|
|
blockDisplayWordLimit: number;
|
|
blockDisplayCharLimit: number;
|
|
}
|
|
|
|
export function buildBlockCopyMetadata(input: BuildBlockCopyMetadataInput): CopyMetadata {
|
|
const {
|
|
clipboardText,
|
|
sourceFilePath,
|
|
blockId,
|
|
useBrief,
|
|
blockText,
|
|
autoBlockDisplayText,
|
|
autoEmbedBlockLink,
|
|
blockDisplayWordLimit,
|
|
blockDisplayCharLimit,
|
|
} = input;
|
|
|
|
let alias = blockId;
|
|
if (useBrief && blockText) {
|
|
alias = extractBlockDisplayText(blockText, blockId, blockDisplayWordLimit, blockDisplayCharLimit);
|
|
}
|
|
if (!autoBlockDisplayText) {
|
|
alias = '';
|
|
}
|
|
|
|
return {
|
|
clipboardText,
|
|
sourceFilePath,
|
|
subpath: `#^${blockId}`,
|
|
alias,
|
|
isEmbed: autoEmbedBlockLink,
|
|
timestamp: Date.now(),
|
|
};
|
|
}
|
|
|
|
export interface BuildHeadingCopyMetadataInput {
|
|
clipboardText: string;
|
|
sourceFilePath: string;
|
|
heading: string;
|
|
filename: string;
|
|
frontmatterTitle?: string;
|
|
useHeadingAsDisplayText: boolean;
|
|
headingLinkSeparator: string;
|
|
isNoteLink: boolean;
|
|
}
|
|
|
|
export function buildHeadingCopyMetadata(input: BuildHeadingCopyMetadataInput): CopyMetadata {
|
|
const {
|
|
clipboardText,
|
|
sourceFilePath,
|
|
heading: rawHeading,
|
|
filename,
|
|
frontmatterTitle,
|
|
useHeadingAsDisplayText,
|
|
headingLinkSeparator,
|
|
isNoteLink,
|
|
} = input;
|
|
|
|
const heading = stripWikiBrackets(rawHeading);
|
|
|
|
let alias = heading;
|
|
if (!useHeadingAsDisplayText) {
|
|
const separator = headingLinkSeparator || '#';
|
|
const filenameOrTitle = frontmatterTitle || filename;
|
|
alias = `${filenameOrTitle}${separator}${heading}`;
|
|
}
|
|
if (isNoteLink && filename === heading) {
|
|
alias = '';
|
|
}
|
|
|
|
return {
|
|
clipboardText,
|
|
sourceFilePath,
|
|
subpath: isNoteLink ? '' : `#${sanitizeHeadingForLink(heading)}`,
|
|
alias,
|
|
isEmbed: false,
|
|
timestamp: Date.now(),
|
|
};
|
|
}
|
|
|
|
export interface BuildFileCopyMetadataInput {
|
|
clipboardText: string;
|
|
sourceFilePath: string;
|
|
displayText?: string;
|
|
}
|
|
|
|
export function buildFileCopyMetadata(input: BuildFileCopyMetadataInput): CopyMetadata {
|
|
return {
|
|
clipboardText: input.clipboardText,
|
|
sourceFilePath: input.sourceFilePath,
|
|
subpath: '',
|
|
alias: input.displayText || '',
|
|
isEmbed: false,
|
|
timestamp: Date.now(),
|
|
};
|
|
}
|