「QuickAdd」使用callout一键折叠所选

好东西!感谢~

多亏你提供思路,借着这个契机把之前一直想弄的功能给实现了,哈哈!

老早就想替换掉官方的那个「切换 Callout」快捷键了,但是没有办法像官方那样「自动扩散选择范围」,这次让AI搞了个改进版

c17e2e81-6d7f-4375-8914-830890b06f34

说明:

  1. 增加了可配置项,可以自行设置「Callout类型、是否折叠、是否用第一行作为标题」
  2. 自动将转换的范围扩散到光标(或选中文本)上下的 非空行/非标题 范围,不需要很精确选择,随便点一下就可以把整段文本都转换成 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 接口,应该可以通用

1 个赞