import { patch, useStatusBar, openInTheSameTab, type ScrapboxSocket, connect, disconnect, caret, } from "../scrapbox-userscript-std/mod.ts"; import { delay as sleep } from "../deno_std%2Fasync/mod.ts"; import { getIndentLineCount, getIndentCount, } from "../scrapbox-userscript-std/text.ts"; import { formatTitle, toYYYYMMDD_HHMMSS, toYYYYMMDD } from "./util.ts"; import { unwrapOk } from "npm:option-t@49/plain_result"; type Page = string[]; export const addToInbox = async ( project: string, title: string, lines: string[], options?: { socket: ScrapboxSocket }, ): Promise => { const { render, dispose } = useStatusBar(); const items: string[] = []; const pages: Page[] = []; for (const block of parse(lines)) { if (block.type === "line") { items.push(`[${formatTitle(block.text)}~@${toYYYYMMDD(new Date())}]`); continue; } const title = `${formatTitle(block.lines[0])}~@${toYYYYMMDD(new Date())}`; pages.push([ title, ...block.lines.slice(1), "", `#${toYYYYMMDD_HHMMSS(new Date())}`, ]); items.push(`[${title}]`); } const socket = unwrapOk(await connect(options?.socket)); try { render( { type: "spinner" }, { type: "text", text: `Adding ${items.length} items...` }, ); await patch(project, title, (_lines) => { const lines = _lines.map((line) => line.text); const lastSeparatorIndex = lines.flatMap( (line, i) => line.trim() === "[/icons/hr.icon]" ? [i] : [] ).pop() ?? -1; // 仕切り線が見つからなければ、末尾に追記する if (lastSeparatorIndex < 0) return [...lines, ...items]; return [ ...lines.slice(0, lastSeparatorIndex), ...items, ...lines.slice(lastSeparatorIndex), ]; }, { socket }); render( { type: "spinner" }, { type: "text", text: `Create ${pages.length} pages...` }, ); await Promise.all(pages.map( (page) => patch(project, page[0], (lines) => [ lines[0].text, ...lines.slice(1).map((line) => line.text), ...page.slice(1), ], { socket }) )); render( { type: "check-circle" }, { type: "text", text: "Added to the inbox." }, ); } catch(e: unknown) { render( { type: "exclamation-triangle" }, { type: "text", text: "Failed to add (see console). Write directory instead." }, ); console.error(e); openInTheSameTab(project, title, [...items, ...pages].join("\n")); } finally { const waiting = sleep(1000); if (options?.socket) await disconnect(socket); await waiting; dispose(); } }; type Block = { type: "line"; text: string; } | { type: "block"; lines: string[]; }; function* parse(lines: string[]): Generator { let index = 0; while (index < lines.length) { const count = getIndentLineCount(index, lines); if (count === 0) { yield { type: "line", text: lines[index].trim() }; index++; continue; } const indentNum = getIndentCount(lines[index]); yield { type: "block", lines: lines.slice(index, index + count + 1) .map(line => line.slice(indentNum)), }; index += count + 1; } }