🗑️

ChatGPTでコピーしたテキストを(少しだけ)いい感じに整形し直してくれるScrapboxのUserScript

2024/02/03に公開

Scrapboxというサービスを利用して、生活や学習含めて雑多なことを記録するようにしています。メモ書きのように使えて、雑にリンク張り巡らせておくことで頭の中で連想するように関連記事を漁っていけるのがいいなと思っています。

スクボを使った最近の学習方法として、
・わからない単語があったら取り敢えずスクボに記事を作って
・GPTに雑に解説してもらって
・解説を雑に記事に貼り付ける(おわり)
という感じで使っています。

ただ、ChatGPTに出力してもらったテキストは、そのままScrapboxに貼り付けると次のような表示になってしまいます。

これはGPTはマークダウンで書かれている一方で、Scrapboxの記法は異なるからですね。そこで、UserScriptを使っていい感じに整形し直してくれるようにしてみました。

整形の条件

  1. コードブロックとして表現される
    """{言語名}
    """
    をスクボのコードブロック(code: {言語名})の書き方に整形す
  2. コードブロック以外に関しては引用表記にする
  3. 文章全体の先頭にLineとGPTのアイコンを表示する

実装

 scrapbox.PopupMenu.addButton({
  title: 'GPTpaste',
  onClick: text => {
    let resultText = '';
    let codeBlocks = [];

    const codeBlockPattern = /```([a-zA-Z0-9]+)\n([\s\S]*?)\n```/g;
    text = text.replace(codeBlockPattern, (match, lang, code) => {
      const indentedCode = code.split('\n').map(line => ` ${line}`).join('\n');
      const transformedCode = `code: .${lang}\n${indentedCode}`;
      codeBlocks.push(transformedCode);
      return `CODEBLOCK${codeBlocks.length - 1}`;
    });

    text.split('\n').forEach((line, index, array) => {
      if (line.startsWith('CODEBLOCK')) {
        const blockIndex = parseInt(line.replace('CODEBLOCK', ''), 10);
        // コードブロックの前後に空行を挿入する処理
        if (resultText !== '' && !resultText.endsWith('\n\n')) {
          resultText += '\n';
        }
        resultText += codeBlocks[blockIndex] + '\n\n';
      } else {
        // 空行でも引用記号を追加する
        resultText += line.trim() === '' ? '>\n' : `> ${line}\n`;
      }
    });

    // 処理後のテキストの末尾が不要な空行で終わらないようにする
    const trimmedResult = resultText.replace(/(>\n)+$/, '>\n');

    const borderLine = '[/icons/hr.icon]\n';
    const gptIcon = '[/icons/ChatGPT.icon]\n';

    return borderLine + gptIcon + trimmedResult;
  }
});

ちなみに、UserScriptはWebサービス上で利用できるJavaScriptのコードで、Scrapboxでは自身のページにscript.jsのコードブロックを設けることで、そのコードをScrapbox内で利用できるようになります。

所感

基本的なコードの書き方はGPTに書いてもらって、それを読んで若干の微調整加えました。というのも、iOS, Swift以外まともに触れたことがなかったからなんですが、GPTのおかげでわりとやりたいことサクッと実現できました。

実際に実装してみると、メニュー表示されるボタンがあって、titleはボタンタイトル、onClickはボタンタップのイベント処理が記述されるといった感じで、UIKitと使い方似ていて直感的にわかりやすかった。アロー関数というのは聞いたことなかったのですが、Swiftでいうところのクロージャだなあと。

とまぁ、UserScriptを書いてみたものの、貼り付ける際に事前に整形されているのが一番親切なはずで、その辺りそのうちうまいこと実現できたらいいなと思っています。

Discussion