预期的效果
三个步骤:
- 复制链接
link
- 复制文本
text
- 回到 Obsidian 中敲击
vvv
触发得到[🔗via: text](link)
背景
相关信息
- Windows 11;已开启
Win + V
系统级剪贴板管理;- Obsidian 1.8.9
我个人在写周刊等内容的时候会使用 LaTeX Suite 插件触发一个 $\longleftarrow$ [🔗via: text](link)
格式来表示信息的出处。格式如下方举例的最后两行:
- FramePack
- 这篇文章由 GaggiX 编写,详细探讨了一种创新的视频生成方法,通过封装输入帧的上下文来实现高效的下一帧预测。此技术允许在普通消费者硬件上运行,并被认为是业界首个可靠的解决方案。用户可以通过简单的配置快速生成高质量的视频,特别是在生成舞蹈动作的场景中效果显著。
- $\Longleftrightarrow$ GitHub - lllyasviel/FramePack: Lets make video diffusion practical!
- $\longrightarrow$ HN-Comments | 下一帧预测模型中的输入帧上下文打包用于视频生成 - Telegraph
- $\longleftarrow$
via: Hacker News 摘要
- $\longleftarrow$
via: 橘橘橘子汁 &
最初代码如下:
{trigger: "vvv", replacement: "[🔗via: $1]($2)$3", options: "tA"},
每一次我都需要手动将 link
和 text
手动复制一遍,然后每一次都需要手动将二者粘贴一遍。
前面的复制操作不可避免,但是我想后面的粘贴操作可以尽量避免。
成功尝试
代码改进如下:
{trigger: "vvv", replacement: () => {
const { clipboard } = require('electron');
let text = clipboard.readText(); // 得到剪贴板的第一个内容
// let link = ???;
// let out_link = `\[🔗via: ${text}\]\(${link}\)$1`;
let out_link = `\[🔗via: ${text}\]\($1\)$2`;
return out_link;
}, options: "tA"},
对于上面这段代码,步骤如下:
- 复制帖子链接
link
,复制链接文本text
; - 回到 Obsidian 中,敲击
vvv
; - 触发得到
[🔗via: text]()
,此时光标在()
内部; Win + V
打开历史剪贴板,选中第二条内容(即链接),粘贴;- 敲击
TAB
,光标跳转到第二个占位符,即退出链接。
相比之下上一段代码,步骤上就仅仅是少了一个 粘贴 text
的步骤。
回到注释,这段代码中我可以得到剪贴板的第一个内容 text
,但是我不知道怎么得到剪贴板的第二个内容 link
。
这也核心问题就是:如何通过 Javascript 中如何得到历史剪贴板的第二个内容?
失败尝试
我不是很了解 javascript,问了 DeepSeek 之后迷惑更大了。
AI 提供了一个方案(引用格式)
基于你的需求,以下是极简实现方案:通过记录最后两次剪贴操作,直接获取第二次内容。代码完全集中于「保存两次剪贴内容」的原子性功能实现:
const { clipboard } = require('electron');
// 核心逻辑:保存最近两次剪贴内容(当前内容为clipboardHistory[0],上一步为[1])
let clipboardHistory = [];
setInterval(() => {
const text = clipboard.readText().trim();
// 仅当内容变化时更新数组 (核心去重判断)
if (text && clipboardHistory[0] !== text) {
clipboardHistory.unshift(text); // 插入数组头部
clipboardHistory = clipboardHistory.slice(0, 2); // 只保留前两项
}
}, 300); // 每0.3秒检查一次剪贴板
// 触发器直接使用数组索引获取历史
{
trigger: "vvv",
replacement: "[🔗via: " + (clipboardHistory[1] || "文本未复制") + "](" + clipboardHistory[0] + ")",
options: "tA"
}
但是不行:
- 抛开上面代码不谈,LaTeX Suite 插件支持的
.js
snippets 文件本质上是一个大列表,每一个元素都是{trigger...}
的形式,上述代码中的clipboardHistory
和setInterval
部分并不属于{trigger...}
范围内。 - 就算是把全局的变量全部放入
{trigger...}
范围内,结果也运行不对。
{trigger: "vvv", replacement: () => {
const { clipboard } = require('electron');
let clipboardHistory = [];
setInterval(() => {
const text = clipboard.readText().trim();
// 仅当内容变化时更新数组 (核心去重判断)
if (text && clipboardHistory[0] !== text) {
clipboardHistory.unshift(text); // 插入数组头部
clipboardHistory = clipboardHistory.slice(0, 2); // 只保留前两项
}
}, 300); // 每0.3秒检查一次剪贴板
let out_link = `[🔗via: ${clipboardHistory[1]}](${clipboardHistory[0]})`;
return out_link;
}, options: "tA"},
改写成如上,得到的就是 [🔗via: undefined](undefined)
。
同时 AI 也提到:
常规的剪贴板管理中,通常只能访问最新的内容。无论是浏览器环境还是Electron这样的桌面应用,通常的API如clipboard.readText()只能获得最新的剪贴板内容。因为大多数系统的剪贴板历史并不是默认公开的,尤其是对于更早的条目。
所以,或许没有办法实现我预期的效果吗?
换个思路,别的软件可以怎么实现呢?