generated at
Projectを横断してリンクを置換するUserScript
本文を直接編集することなくリンク置換 (scrapbox)するscript
リンクを置換するPopup Menuとはちがい、指定した全てのprojectに含まれる同一リンクを全て置換する
↑Gyazo GIFがなぜかガクガクしてしまったので、別途GIFを作った



使い方
script.js
import { replace, getLink } from "./mod.js"; scrapbox.PopupMenu.addButton({ title: (text) => getLink(text) ? "update link" : "", onClick: (text) => replace( text, ["takker", "takker-memex", "takker-private"], ), });

takker-workflow@0.0.1を動かす上でもあると便利なのでほしい
projectを横断して言及しているproject (GTD)次に取るべき行動のタイトルを置換しやすくなる
以下の修正が必要

実装したいこと
現状だと、置換後のリンクと同名のタイトルがあるとエラーになる
✅️DuplicationTitleErrorに対応しないと実装できない
置換対象のprojectを選択できるようにする?
UIが複雑になりそう
現在のprojectも対象にしたい
各自で replace() の引数に入れてください

2024-11-13
16:36:58 scrapbox-userscript-stdの破壊的変更に対応
2024-07-05
12:58:53 リンク検知処理を複数のリンクをまとめて置換するUserScriptと共通化した
微妙に正規表現が違うせいで、popup menu上は検知されているのに押しても置換windowが表示されないことがしょっちゅうあってまあまあストレスだった
重い腰を上げて、ようやくなおした

実装はリンクを置換するPopup Menuとほとんど同じ
dependencies
mod.ts
import { disconnect, connect, patch, replaceLinks, useStatusBar, } from "../scrapbox-userscript-std/mod.ts"; import type { ErrorLike } from "../scrapbox-jp%2Ftypes/rest.ts"; import { getLinks } from "../複数のリンクをまとめて置換するUserScript/mod.ts"; import { isErr, unwrapErr, unwrapOk } from "npm:option-t@49/plain_result"; export const replace = async (text: string, projects: string[]) => { const link = getLinks(text)[0]; if (!link) return; const newLink = window.prompt( `Replace "${link}" to this in ${ projects.map((project) => `"/${project}"`).join(", ") }`, link, ) ?.replace?.(/[\[\]\n]/g, " ") ?? ""; if (newLink === "") return; const { render, dispose } = useStatusBar(); const socket = unwrapOk(await connect()); try { render( { type: "spinner" }, { type: "text", text: `Replacing links in ${projects.length} projects...`, }, ); let count = 0; const replacedNums = await Promise.all(projects.map(async (project) => { const [result] = await Promise.all([ // 本当はhasBackLinksOrIcons === trueのときのみ置換したい replaceLinks(project, link, newLink), patch(project, link, (lines, { persistent }) => { if (!persistent) return; return [ newLink, ...lines.map((line) => line.text).slice(1), ]; }, { socket }), ]); if (isErr(result)) { render( { type: "exclamation-triangle" }, { type: "text", text: `${unwrapErr(result).name} ${unwrapErr(result).message}`, }, ); throw toError(unwrapErr(result)); } count++; render( { type: "spinner" }, { type: "text", text: `Replacing links in ${projects.length - count} projects...`, }, ); return unwrapOk(result); })); const replaced = replacedNums.reduce((acc, cur) => acc + cur, 0); render( { type: "check-circle" }, { type: "text", text: `Successfully replaced ${replaced} links.` }, ); } finally { await disconnect(socket); setTimeout(dispose, 1000); } } const toError = (e: ErrorLike) => { const error = new Error(); error.name = e.name; error.message = e.message; return error; }

#2024-11-13 16:36:26
#2024-07-05 13:00:02
#2024-07-05 12:58:33
#2022-03-03 19:18:51
#2022-02-14 14:23:29