Skip to content

Instantly share code, notes, and snippets.

@takker99
Created August 2, 2021 14:47
Show Gist options
  • Save takker99/e5be2bef2f331a5e24b92990d32ce089 to your computer and use it in GitHub Desktop.
Save takker99/e5be2bef2f331a5e24b92990d32ce089 to your computer and use it in GitHub Desktop.
scrapbox-keicho
import { createPopupMenuBar } from "../PopupMenuもどき/script.js";
import { insertText } from "../scrapbox-insert-text-2/script.js";
import { goEnd } from "../scrapbox-motion-emulation/script.js";
export function setup(props) {
const {
botIcon = "[/nishio/nisbot.icon]",
keyBinding = {key: "Enter", ctrlKey: true},
disableKeyBinding = false,
} = props ?? {};
const { render, visible, open, close } = createPopupMenuBar();
close();
scrapbox.PopupMenu.addButton({
title: () => !visible() ? "🤖" : "",
onClick: (text) => {
if (text.trim() === "") return;
update(text);
},
});
if (disableKeyBinding) return;
const {key, ctrlKey, shiftKey, altKey} = keyBinding;
document.getElementById('text-input').addEventListener('keydown', (e) => {
if (!visible()) return;
if (key !== undefined && key !== e.key) return;
if (ctrlKey !== undefined && ctrlKey !== e.ctrlKey) return;
if (shiftKey !== undefined && shiftKey !== e.shiftKey) return;
if (altKey !== undefined && altKey !== e.altKey) return;
e.preventDefault();
e.stopPropagation();
update();
});
async function update(text) {
text = text ?? getAnswer(botIcon);
if (text.trim() === "") {
goEnd();
await insertText("\n");
return;
}
const pending = askKeicho(text);
// 時間がかかるようであれば読み込み中表示をする
const timer = setTimeout(() => {
render([{text: "Asking..."}]);
open();
}, 1000);
const { question, buttons } = await pending;
clearTimeout(timer);
console.log(`[scrapbox-keicho] Ask: \n${text}`);
console.log(`[scrapbox-keicho] Answer: \n${question}`);
if (buttons.length > 0) console.log(`[scrapbox-keicho] Buttons`, buttons);
goEnd();
await insertText(question);
render([
{
text: "Send",
onClick: () => update(),
},
{
text: "🙂",
onClick: () => insertText("🙂"),
},
{
text: "🙁",
onClick: () => insertText("🙁"),
},
...buttons.map((button) => ({
text: button,
onClick: async () => {
goEnd();
await insertText(button);
await update(button);
},
})),
{
text: "Exit",
onClick: () => close(),
},
]);
open();
}
async function askKeicho(text) {
// idを取得する
const id = getTalkId();
const { id: _id, text: question, buttons } = await globalThis.askKeicho(text, { id });
// idが更新されたらURLを作る
const url = id !== _id ? `https://keicho.netlify.app/#talk=${_id}\n` : "";
return {
question: question.trim() === "" ?
"\n" :
`\n${url}${botIcon}${format(question)}\n`,
buttons,
};
}
}
function format(question) {
const splitted = question.split("\n\n");
if (splitted.length > 1) {
const [quote, _question] = splitted;
return [
"",
...quote.trim().split("\n").map((line) => ` > ${line}`),
` ${_question}`
].join("\n");
}
return question;
}
const REGEXP_URL = /https:\/\/keicho\.netlify\.app\/#talk=(\w+)/;
function getTalkId() {
for (const { text } of scrapbox.Page.lines) {
const talkId = text.match(REGEXP_URL)?.[1];
if (talkId) return talkId;
}
}
import { position } from "../scrapbox-cursor-position-6/script.js";
import { getLineNo, getIndentLineCount } from "../scrapbox-access-nodes@0.1.0/script.js";
function getAnswer(botIcon) {
const endNo = getLineNo(position().line);
const iconLineNos = scrapbox.Page.lines.flatMap(({ text }, index) =>
text.startsWith(botIcon) ? [index] : []
);
let startNo = 1; // アイコン行がなければ、タイトルの次の行からテキストを取得する
if (iconLineNos.length > 0) {
// カーソル行がどのアイコン行よりも上にあったら何もしない
if (endNo <= iconLineNos[0]) return "";
startNo = iconLineNos.filter((lineNo) => lineNo < endNo).pop();
}
// ぶら下がっている行は含めない
startNo += getIndentLineCount(startNo);
// アイコン行を除く
startNo++;
const lines = scrapbox.Page.lines.slice(startNo, endNo + 1).map((line) => line.text);
if (lines.every((text) => /\([^)]*\)/.test(text.trim()))) {
// 全ての行が心の声なら、そのまま返す
return lines.join("\n");
} else {
// 普通の回答が混じっていたら、そこだけ取り出す
return lines.filter((text) => !/\([^)]*\)/.test(text.trim())).join("\n");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment