如何查询在 callout 代码块里的任务?

比如有如下结构

[!faq] 测试

  • 任务1
  • 任务2

我想通过dataview(js) 的方式去定向查询在faq 的callout 块下的任务,如何去写呢;范围是整个库

发现比想象的复杂, 我遇到的难题是, 元数据似乎没有标记 callout 块的类型 (note, faq, tip …)
最后只能老实读笔记原文去提取 callout 首行

基本思路参照 DataviewJS 的提取与汇总 - 经验分享

```dataviewjs
const asyncFilter = async (arr, predicate) => {
    const results = await Promise.all(arr.map(predicate));
    return arr.filter((_v, index) => results[index]);
}

// 获取所有文件中的任务
const allTasks = dv.pages('"仓库里的/指定的/子目录"').file.tasks.values;

// 过滤出在指定 callout 块中的任务
const faqTasks = await asyncFilter(allTasks, (async task => {
    // 检查任务的父级是否是 callout 块
    // task column start = 0 的 一定不在 callout 块里
    if (task.position.start.col === 0) {
        return false;
    }

    const path = app.vault.getAbstractFileByPath(task.path);
    const callouts = app.metadataCache.getFileCache(path).sections.filter(p=> p.type == 'callout');
    // 笔记里没 callout 的, 一定不是目标 task
    if (callouts.length === 0) {
        return false;
    }

    const rawlines = (await dv.io.load(task.path)).split('\n');
    // 检查 callout类型 检查任务的行号是否在 callout 块里
    let taskInFaq = false;
    callouts.forEach(callout => { 
	    const calloutHeader = rawlines[callout.position.start.line]; 
	    if (calloutHeader.includes("!faq") &&
            (task.line >= callout.position.start.line) && 
            (task.line <= callout.position.end.line)) {
            task.visual = task.text + ` (in ${calloutHeader.slice(2,)})`;
            taskInFaq = true;
        }
	});
    return taskInFaq;
}));

// 输出任务 console.log('faqTasks', faqTasks); dv.list(faqTasks.map(t => t.visual));
dv.taskList(faqTasks);

dv.span('done, 可能逻辑细节有问题需核查')
```

另一个坑点是我刚知道 array.filter(elem => ...) 里没法用异步函数…


测试任务类似下面这样 (未考虑 callout 嵌套等复杂情况):


> [!note] 不该命中测试
>
 > - [ ] 不该命中任务1 inside callout
 > - [x] 不该命中任务2 完成 inside callout

- [ ] 不该命中任务5 普通 outside callout


> [!faq] 测试
>
 > - [x] 目标任务1 inside callout
 > - [ ] 目标任务2 完成 inside callout


- [ ] 不该命中任务3 普通 outside callout

最后效果大致如下:

image

1 个赞

感谢大佬 :grinning: ,我不用复杂场景,这个代码就很好了