如图,快速选中光标前方的链接文本范围,方便修改链接的显示文本。
/*
* @Author: Moy
* @Date: 2025-05-08 13:02:51
* @Last Modified by: Moy
* @Last Modified time: 2025-05-08 13:02:51
* @URL:
*/
/** 拓展选择到 [] 的括号范围 */
// 1. 默认情况下,选中整行
// 2. 如果在 [] 内,则选中 [] 内的文本
// 3. () 亦然
const activeEditor = app.workspace.activeEditor;
const selectUrlLink = false;
if (activeEditor && activeEditor.editor) {
const editor = activeEditor.editor;
const cursor = editor.getCursor();
const currentLine = cursor.line;
const content = editor.getValue();
const lines = content.split('\n');
// 判断当前 cursor 是否在 [] 内(范围是当前行)
const currentLineContent = lines[currentLine];
// 获取当前行所有 wiki 链接的区间
function findNearestWikiLink(line, cursorCh) {
const regex = /\[\[([^\[\]\|]+)(\|([^\]]+))?\]\]/g;
let match, links = [];
while ((match = regex.exec(line)) !== null) {
const start = match.index;
const end = regex.lastIndex;
const pipeIndex = match[0].indexOf('|');
let pipeCh = pipeIndex !== -1 ? start + pipeIndex : -1;
links.push({
text: match[0],
start,
end,
pipeCh,
textStart: pipeCh !== -1 ? pipeCh + 1 : -1,
textEnd: end - 2 // ']]' 前
});
}
if (links.length === 0) return null;
// 找距离 cursor 最近的 wiki link
let minDist = Infinity, target = null;
for (const link of links) {
let dist = 0;
if (cursorCh < link.start) dist = link.start - cursorCh;
else if (cursorCh > link.end) dist = cursorCh - link.end;
else dist = 0;
if (dist < minDist) {
minDist = dist;
target = link;
}
}
return target;
}
// 获取当前行所有 markdown 链接的区间
function findNearestMarkdownLink(line, cursorCh) {
const regex = /\[([^\]]+)\]\(([^)]+)\)/g;
let match, links = [];
while ((match = regex.exec(line)) !== null) {
links.push({
text: match[0],
textStart: match.index + 1, // '[' 后
textEnd: match.index + match[1].length + 1, // ']' 前
urlStart: match.index + match[0].indexOf('(') + 1,
urlEnd: match.index + match[0].lastIndexOf(')'),
start: match.index,
end: regex.lastIndex
});
}
if (links.length === 0) return null;
// 找距离 cursor 最近的链接
let minDist = Infinity, target = null;
for (const link of links) {
let dist = 0;
// 💡 这里是用来找最近的链接的,如果需要调整,改这里
// 让结尾的判断更宽松
const urlEndOffset = 2;
if (cursorCh < link.start) dist = link.start - cursorCh;
// else if (cursorCh > link.end) dist = cursorCh - link.end;
else if (cursorCh > link.urlEnd) dist = cursorCh - link.urlEnd - urlEndOffset;
else dist = 0;
if (dist < minDist) {
minDist = dist;
target = link;
}
}
return target;
}
const selectedText = editor.getSelection();
// 先判断 wiki link
const wikiLink = findNearestWikiLink(currentLineContent, cursor.ch);
if (wikiLink) {
// 如果光标正好在 ]] 后方
if (cursor.ch === wikiLink.end || cursor.ch === wikiLink.end + 1) {
new Notice(`跳转到 ]] 前 ch:${wikiLink.end - 2}`);
editor.setCursor(
{ line: currentLine, ch: wikiLink.end - 3 }
);
editor.setCursor(
{ line: currentLine, ch: wikiLink.end - 2 }
);
}
// [[link|text]] 且光标在 | 后
else if (wikiLink.pipeCh !== -1 && cursor.ch > wikiLink.pipeCh && cursor.ch <= wikiLink.end - 2) {
// 如果已经选中别名,则拓展到整行
if (selectedText === currentLineContent.substring(wikiLink.textStart, wikiLink.textEnd)) {
new Notice(`拓展到整行 line:${currentLine}`);
editor.setSelection(
{ line: currentLine, ch: 0 },
{ line: currentLine, ch: currentLineContent.length }
);
} else {
new Notice("选中 | 后的文本(别名)");
editor.setSelection(
{ line: currentLine, ch: wikiLink.textStart },
{ line: currentLine, ch: wikiLink.textEnd }
);
}
}
// 其它情况,默认选中整个 wiki link
else {
new Notice("选中整个 wiki link 内的文本");
editor.setSelection(
{ line: currentLine, ch: wikiLink.start + 2 },
{ line: currentLine, ch: wikiLink.end - 2 }
);
}
} else {
// markdown link 逻辑
const link = findNearestMarkdownLink(currentLineContent, cursor.ch);
if (link) {
if ( selectUrlLink && cursor.ch >= link.urlStart && cursor.ch <= link.urlEnd) {
// 光标在 () 内
new Notice("选中括号文本");
editor.setSelection(
{ line: currentLine, ch: link.urlStart },
{ line: currentLine, ch: link.urlEnd }
);
} else if (cursor.ch >= link.textStart && cursor.ch <= link.textEnd) {
// 光标在 [] 内
const linkText = currentLineContent.substring(link.textStart, link.textEnd);
if (selectedText === linkText) {
new Notice(`拓展到整行 line:${currentLine}`);
editor.setSelection(
{ line: currentLine, ch: 0 },
{ line: currentLine, ch: currentLineContent.length }
);
} else {
new Notice("选中链接文本");
editor.setSelection(
{ line: currentLine, ch: link.textStart },
{ line: currentLine, ch: link.textEnd }
);
}
} else {
// 光标在链接附近但不在 [] 或 () 内
new Notice(`跳转到链接文本的位置 ch:${link.textEnd}`);
editor.setCursor(
{ line: currentLine, ch: link.textEnd - 1 }
);
editor.setCursor(
{ line: currentLine, ch: link.textEnd }
);
}
} else {
new Notice("选中整行");
editor.setSelection(
{ line: currentLine, ch: 0 },
{ line: currentLine, ch: currentLineContent.length }
);
}
}
}