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

一句话总结

使用QuickAdd的capture一键转换所选内容,到折叠好的callout中

使用方法

配置:QuickAdd设置,新建capture,如图设置,粘贴代码至Capture format栏即可

使用:选中文本,调出QuickAdd面板或直接使用快捷键触发配置好的capture命令,即可自动转换所选内容为折叠好的callout,第一行为callout标题

详细步骤/高级用法/配置快捷键见:QuickAdd JS & Templater JS 简介及相互修改

脚本源码

```js quickadd
// 获取选中的内容
const selectedContent = this.quickAddApi.utility.getSelectedText();

// 将内容按行分割
const lines = selectedContent.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;

// 返回最终处理后的内容
return finalContent;
```
2 个赞

好东西!感谢~

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

老早就想替换掉官方的那个「切换 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 个赞

在编辑区双击,会选中光标所在句子;
在编辑区三击,会选中光标所在行;
两个空行之间的是一个区,那么能不能直接捕获光标所在的区呢?

这样就不用从头选到尾了。能省不少操作