好东西!感谢~
多亏你提供思路,借着这个契机把之前一直想弄的功能给实现了,哈哈!
老早就想替换掉官方的那个「切换 Callout」快捷键了,但是没有办法像官方那样「自动扩散选择范围」,这次让AI搞了个改进版
说明:
- 增加了可配置项,可以自行设置「Callout类型、是否折叠、是否用第一行作为标题」
- 自动将转换的范围扩散到光标(或选中文本)上下的 非空行/非标题 范围,不需要很精确选择,随便点一下就可以把整段文本都转换成 Callout
改进代码:
<%*
// 配置选项
const CONFIG = {
calloutType: "info", // Callout 类型
collapsed: true, // 是否折叠
useFirstLineAsTitle: false // 是否使用第一行作为标题
};
// 获取编辑器实例
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 formattedContent = contentLines.map(line => '> ' + line).join('\n') + '\n';
// 组合最终内容
const finalContent = `\n${calloutMark}${titleLine}\n${formattedContent}`;
// 替换选中的内容
editor.replaceRange(finalContent, from, to);
// 计算新的光标位置
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
});
}
-%>
我习惯用 Tp 所以这里写的是 Templater 的脚本,不过好像没用啥 tp
接口,应该可以通用