0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Django学習記録⑨Markdownでコード実行できるようにしてみた

0
Posted at

昨日から、SmarMemoでPythonコードをブラウザ上で実行できるようにしたい。実行結果もMarkdownノートに保存したい。ことをしたがったので、時間をかけて作りました。

実装内容

  • まずは最初は複雑のをするよりはPyodideを導入
  • プレビュー画面のPythonコードブロックに「▶Run」ボタンを追加
  • 実行結果をリアルタイム表示
  • updateOutBlock()を作成し、実行したコードブロックの直後に```textブロックを自動追加・更新するようにしました。

完成した動作

print("Hello")

を実行すると

print("Hello")
Hello

苦労した点

  • 最初はMarkdown全体の最後に実行していました。
  • コードブロックが複数になると、どの実行結果なのか分からなくなっていました。
  • substring()やreplace()を使って対応しょうとしましたが、複雑になってしまいました。
function updateOutputBlock(editor,code,output){
                
                //コードブロックごとに実行管理
                const codeText = code.trim();
                const currentContent = editor.getValue();


                //実行したPythonコードをMarkdownの中で探すため作成
                const codeBlock = 
                "```python\n" + 
                codeText + 
                "\n```";

                //実行したPythonコードがMarkdownの何文字目にあるか確認
                const position = currentContent.indexOf(codeBlock);

                const outputBlock = 
                "\n\n```text\n" + 
                output.trim() + 
                "\n```\n";

                //positionが見つかったどうか確認
                if (position === -1){
                    return;
                }
                //見つからなかったら終了
                const insertPosition = position + codeBlock.length;

                //コードブロックより後ろのMarkdownを取り出す
                const afterCode = currentContent.substring(insertPosition);

                //ここから実行結果(textブロック)があるか確認
                const trimmedAfterCode = afterCode.trimStart();

                if(trimmedAfterCode.startsWith("```text")){

                    const endIndex = trimmedAfterCode.indexOf("```",7);
                    if(endIndex !== -1){
                        const rest = trimmedAfterCode.substring(endIndex + 3);

                        const newContent = 
                        currentContent.substring(0, insertPosition) + 
                        outputBlock + 
                        rest;

                        editor.setValue(newContent);
                    }

                }  
                else{
                        editor.setValue(
                            currentContent.substring(0, insertPosition) + 
                            outputBlock + 
                            currentContent.substring(insertPosition)
                        );
                    }
                

            }

最終的に「実行したコードブロックの直後だけを更新する」というシンプルなアルゴリズムに作り直しました。

 //コードブロックごとに実行管理
            function updateOutputBlock(editor,code,output){
                
                //エディタ全体のMarkdownを取得
                const currentContent = editor.getValue();

                //実行したPyhtonコードブロックを作成
                const codeBlock = 
                "```python\n" + 
                code.trim() + 
                "\n```";

                //実行結果(textブロック)を作成
                const outputBlock = 
                "\n\n```text\n" + 
                output.trim() +
                "\n```\n";

                //実行したコードブロックの位置を検索
                const position = currentContent.indexOf(codeBlock);

                //コードが見つからなければ終了
                if (position === -1){
                    return;
                }

                //コードブロックまで内容を取得
                const before = currentContent.slice(
                    0,
                    position + codeBlock.length
                );

                // コードブロック以降の内容を取得
                let after = currentContent.slice(
                    position + codeBlock.length
                    
                );

                //既存の実行結果(textブロック)を削除
                after = after.replace(
                        /^\s*```text[\s\S]*?```\s*/,
                        ""
                    );

                //新しい実行結果を導入    
                const newContent = 
                before + 
                outputBlock + 
                after;
                
                //エディタを更新
                editor.setValue(newContent);

            }

今後の課題

  • エラー表示改善
  • Notebook風UIへの発展
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?