|
<%* |
|
|
|
// 【配置选项】 |
|
const CONFIG = { |
|
calloutType: "info", // Callout 类型 |
|
collapsed: false, // 是否折叠 |
|
useFirstLineAsTitle: false, // 是否使用第一行作为标题 |
|
cursorPosition: "type" // 可选值: "end", "type", "title" |
|
}; |
|
|
|
// 获取编辑器实例 |
|
const editor = app.workspace.activeEditor.editor; |
|
|
|
// 【拓展范围】 |
|
// 判断是否为标题行 |
|
const isHeading = (line) => /^#{1,6}\s+/.test(line); |
|
// 判断是否为空行或标题行 |
|
const shouldStop = (line) => !line.trim() || isHeading(line); |
|
|
|
// 获取当前选中的内容和范围 |
|
let selection = editor.getSelection(); |
|
let from, to; |
|
|
|
if (!selection) { |
|
// 如果没有选中文本,从光标所在行开始扩展 |
|
const cursor = editor.getCursor(); |
|
// 如果光标在标题行上,直接返回 |
|
if (isHeading(editor.getLine(cursor.line))) return; |
|
// 设置初始范围为光标所在行的开始到结束 |
|
from = { line: cursor.line, ch: 0 }; |
|
to = { line: cursor.line, ch: editor.getLine(cursor.line).length }; |
|
} else { |
|
// 如果有选中文本,获取选择范围 |
|
from = editor.getCursor('from'); |
|
to = editor.getCursor('to'); |
|
} |
|
|
|
// 向上扩展选择范围直到遇到空行或标题行 |
|
let line = from.line; |
|
while (line > 0) { |
|
const prevLine = editor.getLine(line - 1); |
|
if (shouldStop(prevLine)) break; |
|
line--; |
|
} |
|
from.line = line; |
|
from.ch = 0; |
|
|
|
// 向下扩展选择范围直到遇到空行或标题行 |
|
line = to.line; |
|
while (line < editor.lineCount() - 1) { |
|
const nextLine = editor.getLine(line + 1); |
|
if (shouldStop(nextLine)) break; |
|
line++; |
|
} |
|
to.line = line; |
|
to.ch = editor.getLine(line).length; |
|
|
|
// 更新选择范围 |
|
editor.setSelection(from, to); |
|
|
|
// 获取扩展后的选中内容 |
|
const selectedText = editor.getRange(from, to); |
|
|
|
// 如果没有有效内容,直接返回 |
|
if (!selectedText.trim()) return; |
|
|
|
// 将内容按行分割 |
|
const lines = selectedText.split('\n'); |
|
let firstLine = lines[0]; |
|
|
|
// 定义正则表达式,匹配Markdown标题(#、##、### 等)和无序列表(-、*、+) |
|
const markdownPattern = /^(#{1,6}\s+|- |\* |\+ )/; |
|
|
|
// 如果第一行匹配正则表达式,则去除相应的前缀 |
|
if (markdownPattern.test(firstLine)) { |
|
firstLine = firstLine.replace(markdownPattern, ''); |
|
} |
|
|
|
// 构建 Callout 标记 |
|
const calloutMark = `> [!${CONFIG.calloutType}]${CONFIG.collapsed ? '- ' : ' '}`; |
|
|
|
// 根据配置决定是否添加标题 |
|
const titleLine = CONFIG.useFirstLineAsTitle ? ` ${firstLine}` : ''; |
|
|
|
// 确定要处理的内容行 |
|
const contentLines = CONFIG.useFirstLineAsTitle ? lines.slice(1) : lines; |
|
|
|
// 检查前后是否有空行 |
|
const prevLine = from.line > 0 ? editor.getLine(from.line - 1) : ''; |
|
const nextLine = to.line < editor.lineCount() - 1 ? editor.getLine(to.line + 1) : ''; |
|
const hasLeadingNewline = !prevLine.trim(); |
|
const hasTrailingNewline = !nextLine.trim(); |
|
|
|
// 将内容行添加引用前缀 (移除末尾可能的换行符) |
|
const formattedContent = contentLines.map(line => '> ' + line).join('\n'); |
|
|
|
// 组合最终内容 |
|
const finalContent = `${hasLeadingNewline ? '' : '\n'}${calloutMark}${titleLine}\n${formattedContent}${hasTrailingNewline ? '' : '\n'}`; |
|
|
|
// 替换选中的内容 |
|
editor.replaceRange(finalContent, from, to); |
|
|
|
// 计算新的光标位置 |
|
switch (CONFIG.cursorPosition) { |
|
case "type": { |
|
// 选中 Callout 类型 |
|
const typeStartLine = from.line + (hasLeadingNewline ? 0 : 1); |
|
const typeStartCh = editor.getLine(typeStartLine).indexOf(CONFIG.calloutType); |
|
editor.setSelection( |
|
{ line: typeStartLine, ch: typeStartCh }, |
|
{ line: typeStartLine, ch: typeStartCh + CONFIG.calloutType.length } |
|
); |
|
break; |
|
} |
|
case "title": { |
|
// 将光标放在标题行的末尾 |
|
const titleLine = from.line + (hasLeadingNewline ? 0 : 1); |
|
const lineText = editor.getLine(titleLine); |
|
editor.setCursor({ |
|
line: titleLine, |
|
ch: lineText.length |
|
}); |
|
break; |
|
} |
|
case "end": |
|
default: { |
|
// 找到最后一个引用行并定位到末尾 |
|
const newLines = finalContent.split('\n'); |
|
const lastContentLine = newLines.findLastIndex(line => line.startsWith('> ')); |
|
if (lastContentLine !== -1) { |
|
const targetLine = from.line + lastContentLine; |
|
const targetText = editor.getLine(targetLine); |
|
editor.setCursor({ |
|
line: targetLine, |
|
ch: targetText.length |
|
}); |
|
} |
|
break; |
|
} |
|
} |
|
|
|
/* |
|
// 第二版 |
|
// 获取编辑器实例 |
|
const editor = app.workspace.activeEditor.editor; |
|
|
|
// 获取当前选中的内容和范围 |
|
let selection = editor.getSelection(); |
|
let from, to; |
|
|
|
if (!selection) { |
|
// 如果没有选中文本,从光标所在行开始扩展 |
|
const cursor = editor.getCursor(); |
|
// 设置初始范围为光标所在行的开始到结束 |
|
from = { line: cursor.line, ch: 0 }; |
|
to = { line: cursor.line, ch: editor.getLine(cursor.line).length }; |
|
} else { |
|
// 如果有选中文本,获取选择范围 |
|
from = editor.getCursor('from'); |
|
to = editor.getCursor('to'); |
|
} |
|
|
|
// 向上扩展选择范围直到遇到空行 |
|
let line = from.line; |
|
while (line > 0) { |
|
const prevLine = editor.getLine(line - 1); |
|
if (!prevLine.trim()) break; |
|
line--; |
|
} |
|
from.line = line; |
|
from.ch = 0; |
|
|
|
// 向下扩展选择范围直到遇到空行 |
|
line = to.line; |
|
while (line < editor.lineCount() - 1) { |
|
const nextLine = editor.getLine(line + 1); |
|
if (!nextLine.trim()) break; |
|
line++; |
|
} |
|
to.line = line; |
|
to.ch = editor.getLine(line).length; |
|
|
|
// 更新选择范围 |
|
editor.setSelection(from, to); |
|
// 获取扩展后的选中内容 |
|
const selectedText = editor.getRange(from, to); |
|
|
|
// 如果没有有效内容,直接返回 |
|
if (!selectedText.trim()) return; |
|
|
|
// 将内容按行分割 |
|
const lines = selectedText.split('\n'); |
|
// 获取第一行 |
|
let firstLine = lines[0]; |
|
|
|
// 定义正则表达式,匹配Markdown标题(#、##、### 等)和无序列表(-、*、+) |
|
const markdownPattern = /^(#{1,6}\s+|- |\* |\+ )/; |
|
|
|
// 如果第一行匹配正则表达式,则去除相应的前缀 |
|
if (markdownPattern.test(firstLine)) { |
|
firstLine = firstLine.replace(markdownPattern, ''); |
|
} |
|
|
|
// 将除第一行以外的每一行前添加 "> " 进行引用 |
|
const formattedContent = lines.slice(1).map(line => '> ' + line).join('\n') + '\n'; |
|
|
|
// 在formattedContent之前加上 "> [!info]- \n",并保留第一行 |
|
const finalContent = '\n> [!info]- ' + firstLine + '\n' + formattedContent; |
|
|
|
// 替换选中的内容 |
|
editor.replaceRange(finalContent, from, to); |
|
*/ |
|
|
|
|
|
/* |
|
|
|
// 原始版本 |
|
|
|
// 来自:[「QuickAdd」使用callout一键折叠所选 - 经验分享 - Obsidian 中文论坛](https://forum-zh.obsidian.md/t/topic/42073) |
|
|
|
// 获取选中的内容 |
|
let selectedText = app.workspace.activeEditor.getSelection(); |
|
|
|
// 将内容按行分割 |
|
const lines = selectedText.split('\n'); |
|
// 获取第一行 |
|
let firstLine = lines[0]; |
|
|
|
// 定义正则表达式,匹配Markdown标题(#、##、### 等)和无序列表(-、*、+) |
|
const markdownPattern = /^(#{1,6}\s+|- |\* |\+ )/; |
|
|
|
// 如果第一行匹配正则表达式,则去除相应的前缀 |
|
if (markdownPattern.test(firstLine)) { |
|
firstLine = firstLine.replace(markdownPattern, ''); // 去掉匹配的部分 |
|
} |
|
|
|
// 将除第一行以外的每一行前添加 "> " 进行引用 |
|
const formattedContent = lines.slice(1).map(line => '> ' + line).join('\n') + '\n'; |
|
|
|
// 在formattedContent之前加上 "> [!info]- \n",并保留第一行 |
|
const finalContent = '\n> [!info]- ' + firstLine + '\n' + formattedContent; |
|
|
|
// 替换选中的内容 |
|
app.workspace.activeEditor.editor.replaceSelection(finalContent); |
|
|
|
*/ |
|
-%> |