Pyodide上でdocutilsを動かしてみる

docutilsはreStructuredTextをPythonで扱うためのモジュール。

Pyodide上でdocutilsを動かせば、ブラウザ上だけでreStructuredTextを扱えるかなと思って試していました。

コード

pyodide-docutils.html:

<!doctype html>
<html>
  <head>
    <script src="https://cdn.jsdelivr.net/pyodide/v0.24.1/full/pyodide.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
    <title>docutils on Pyodide</title>
  </head>
  <body>
    <div class="container-fluid">
      <div class="row">
        <div class="col-md-6 vh-100 p-1">
          <form class="h-100">
            <textarea placeholder="You can write texts by reStructuredText." id="editarea" class="form-control h-100 font-monospace"></textarea>
          </form>
        </div>
        <div class="col-md-6 border border-2 h-auto" id="preview"></div>
      </div>
    </div>
    <script type="text/javascript">
      let pyodide;
      let previousText = "";
      let lock = false
      const editArea = document.getElementById("editarea");
      const preview = document.getElementById("preview");
      async function main() {
        // setup
        pyodide = await loadPyodide();
        await pyodide.loadPackage("micropip");
        const micropip = pyodide.pyimport("micropip");
        await micropip.install("docutils");
        // start interval
        setInterval(updatePreview, 500)
      }
      async function updatePreview() {
        const currentText = editarea.value;
        if (currentText == previousText || lock) { return }
        lock = true;
        await render(currentText);
        previousText = currentText;
        lock = false;
      }
      async function render(rst) {
        pyodide.globals.set("rst", rst)
        const output = pyodide.runPython(`
          from docutils.core import publish_parts
          try:
              result = publish_parts(rst, writer_name='html')['html_body']
          except Exception as e:
              print(e)
        `)
        preview.innerHTML = pyodide.globals.get("result");
      }
      main();
    </script>
  </body>
</html>

見た目はBootstrap5を使って簡単に整えつつ、テキストエリアに入力したreStructuredTextをdocutilsでHTMLに変換し、右側に表示をします。

特別なことは特になくて、普通に動きました。何かに使えると面白そうですね。

参考