-
-
Save takker99/e5be2bef2f331a5e24b92990d32ce089 to your computer and use it in GitHub Desktop.
scrapbox-keicho
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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