【脚本】快速编辑链接文本

29155110-a380-4edf-8749-f7e470bbea86

如图,快速选中光标前方的链接文本范围,方便修改链接的显示文本。

/*
 * @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 }
        );
    }

    }  
}


可以和 【实用技巧】如何改善笔记的链接编辑体验 - 经验分享 - Obsidian 中文论坛 配合使用。