From 583de2a9804aba81282e360e87805adad73f0a49 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Mon, 19 Jan 2026 20:58:18 +0100 Subject: Add support for compiling pandoc.wasm. 'make pandoc.wasm' will compile a wasm version of pandoc. This commit also adds a wasm directory with pandoc.js, a JavaScript wrapper for pandoc.wasm, and an example application that exposes almost all pandoc features to a web interface, together with a set of examples. --- Makefile | 13 + cabal.project | 89 +- flake.lock | 79 +- flake.nix | 11 +- pandoc-cli/lua/PandocCLI/Lua.hs | 15 +- pandoc-cli/pandoc-cli.cabal | 32 +- pandoc-cli/src/pandoc-wasm.hs | 74 + pandoc-cli/src/pandoc.hs | 4 +- pandoc-lua-engine/pandoc-lua-engine.cabal | 8 +- .../src/Text/Pandoc/Lua/Module/CLI.hs | 10 +- wasm/LICENSE | 21 + wasm/Makefile | 34 + wasm/examples/bibtex-to-csljson/options.json | 4 + wasm/examples/bibtex-to-csljson/stdin | 12 + wasm/examples/csv-table-to-org/options.json | 4 + wasm/examples/csv-table-to-org/stdin | 10 + wasm/examples/custom-template/custom.tpl | 6 + wasm/examples/custom-template/options.json | 6 + wasm/examples/custom-template/stdin | 10 + .../docx-with-equations-to-latex/equations.docx | Bin 0 -> 10921 bytes .../docx-with-equations-to-latex/options.json | 6 + wasm/examples/hello-world/options.json | 4 + wasm/examples/hello-world/stdin | 1 + .../examples/highlighted-code-to-html/options.json | 13 + wasm/examples/highlighted-code-to-html/stdin | 39 + wasm/examples/ipynb-to-rtf/options.json | 5 + wasm/examples/ipynb-to-rtf/stdin | 68 + .../latex-to-docbook-with-mathml/options.json | 6 + wasm/examples/latex-to-docbook-with-mathml/stdin | 27 + .../options.json | 6 + .../latex-with-macros-to-restructured-text/stdin | 9 + wasm/examples/man-page-to-context/options.json | 4 + wasm/examples/man-page-to-context/stdin | 40 + .../le-tapuscrit-note.csl | 496 ++++ .../options.json | 7 + .../refs.bib | 9 + .../stdin | 7 + .../options.json | 6 + .../markdown-to-docbook-with-citations/stdin | 22 + .../markdown-to-revealjs-slides/options.json | 9 + wasm/examples/markdown-to-revealjs-slides/stdin | 560 +++++ wasm/examples/markdown-to-rst/options.json | 10 + wasm/examples/markdown-to-rst/stdin | 250 ++ .../mediawiki-to-docx-with-equations/options.json | 6 + .../mediawiki-to-docx-with-equations/stdin | 8 + .../options.json | 9 + .../ris-to-formatted-markdown-bibliography/stdin | 20 + wasm/examples/rst-table-from-yaml-data/custom.rst | 7 + .../examples/rst-table-from-yaml-data/options.json | 8 + wasm/examples/rst-table-from-yaml-data/species.rst | 2 + wasm/examples/rst-table-from-yaml-data/stdin | 721 ++++++ wasm/index.html | 2486 ++++++++++++++++++++ wasm/pandoc.js | 141 ++ 53 files changed, 5434 insertions(+), 20 deletions(-) create mode 100644 pandoc-cli/src/pandoc-wasm.hs create mode 100644 wasm/LICENSE create mode 100644 wasm/Makefile create mode 100644 wasm/examples/bibtex-to-csljson/options.json create mode 100644 wasm/examples/bibtex-to-csljson/stdin create mode 100644 wasm/examples/csv-table-to-org/options.json create mode 100644 wasm/examples/csv-table-to-org/stdin create mode 100644 wasm/examples/custom-template/custom.tpl create mode 100644 wasm/examples/custom-template/options.json create mode 100644 wasm/examples/custom-template/stdin create mode 100644 wasm/examples/docx-with-equations-to-latex/equations.docx create mode 100644 wasm/examples/docx-with-equations-to-latex/options.json create mode 100644 wasm/examples/hello-world/options.json create mode 100644 wasm/examples/hello-world/stdin create mode 100644 wasm/examples/highlighted-code-to-html/options.json create mode 100644 wasm/examples/highlighted-code-to-html/stdin create mode 100644 wasm/examples/ipynb-to-rtf/options.json create mode 100644 wasm/examples/ipynb-to-rtf/stdin create mode 100644 wasm/examples/latex-to-docbook-with-mathml/options.json create mode 100644 wasm/examples/latex-to-docbook-with-mathml/stdin create mode 100644 wasm/examples/latex-with-macros-to-restructured-text/options.json create mode 100644 wasm/examples/latex-with-macros-to-restructured-text/stdin create mode 100644 wasm/examples/man-page-to-context/options.json create mode 100644 wasm/examples/man-page-to-context/stdin create mode 100644 wasm/examples/markdown-citations-to-plain-with-csl-style/le-tapuscrit-note.csl create mode 100644 wasm/examples/markdown-citations-to-plain-with-csl-style/options.json create mode 100644 wasm/examples/markdown-citations-to-plain-with-csl-style/refs.bib create mode 100644 wasm/examples/markdown-citations-to-plain-with-csl-style/stdin create mode 100644 wasm/examples/markdown-to-docbook-with-citations/options.json create mode 100644 wasm/examples/markdown-to-docbook-with-citations/stdin create mode 100644 wasm/examples/markdown-to-revealjs-slides/options.json create mode 100644 wasm/examples/markdown-to-revealjs-slides/stdin create mode 100644 wasm/examples/markdown-to-rst/options.json create mode 100644 wasm/examples/markdown-to-rst/stdin create mode 100644 wasm/examples/mediawiki-to-docx-with-equations/options.json create mode 100644 wasm/examples/mediawiki-to-docx-with-equations/stdin create mode 100644 wasm/examples/ris-to-formatted-markdown-bibliography/options.json create mode 100644 wasm/examples/ris-to-formatted-markdown-bibliography/stdin create mode 100644 wasm/examples/rst-table-from-yaml-data/custom.rst create mode 100644 wasm/examples/rst-table-from-yaml-data/options.json create mode 100644 wasm/examples/rst-table-from-yaml-data/species.rst create mode 100644 wasm/examples/rst-table-from-yaml-data/stdin create mode 100644 wasm/index.html create mode 100644 wasm/pandoc.js diff --git a/Makefile b/Makefile index b42183567..d64412ac0 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,7 @@ WEBSITE=../../web/pandoc.org REVISION?=1 BENCHARGS?=--csv bench_$(TIMESTAMP).csv $(BASELINECMD) --timeout=6 +RTS -T --nonmoving-gc -RTS $(if $(PATTERN),--pattern "$(PATTERN)",) pandoc=$(shell cabal list-bin $(CABALOPTS) pandoc-cli) +OPTIMIZE_WASM?=1 all: build test binpath ## build executable and run tests .PHONY: all @@ -326,3 +327,15 @@ release-checklist-$(VERSION).org: RELEASE-CHECKLIST-TEMPLATE.org hie.yaml: ## regenerate hie.yaml gen-hie > $@ .PHONY: hie.yaml + +pandoc.wasm: + -rm $@ + wasm32-wasi-cabal build pandoc-cli +ifeq ($(OPTIMIZE_WASM),1) + echo "Optimizing (this may take a long time, to avoid, set OPTIMIZE_WASM=0)..." + wasm-opt --low-memory-unused --converge --gufa --flatten --rereloop -Oz $$(wasm32-wasi-cabal list-bin pandoc-cli | tail -1) -o $@ +else + echo "Copying unoptimized pandoc.wasm..." + cp "$$(wasm32-wasi-cabal list-bin pandoc-cli | tail -1)" "$@" +endif +.PHONY: pandoc.wasm diff --git a/cabal.project b/cabal.project index 5629d8c17..c31f628c0 100644 --- a/cabal.project +++ b/cabal.project @@ -2,11 +2,12 @@ packages: . pandoc-lua-engine pandoc-server pandoc-cli -tests: True -flags: +embed_data_files constraints: skylighting-format-blaze-html >= 0.1.1.3, skylighting-format-context >= 0.1.0.2 +package pandoc + flags: +embed_data_files +http + source-repository-package type: git location: https://github.com/jgm/asciidoc-hs.git @@ -31,3 +32,87 @@ source-repository-package type: git location: https://github.com/jgm/djoths.git tag: a6fc625fd58aa39df05dd1d82ee005e681815095 + +if arch(wasm32) + tests: False + + package atomic-counter + flags: +no-cmm + + package aeson + flags: -ordered-keymap + + package crypton + ghc-options: -optc-DARGON2_NO_THREADS + + package digest + flags: -pkg-config + + package lua + flags: +cross-compile + ghc-options: -optc-D_WASI_EMULATED_SIGNAL -optc-lwasi-emulated-signal -optc-mllvm -optc-wasm-enable-sjlj -optc-mllvm -optc-wasm-use-legacy-eh -optc-D_WASI_EMULATED_PROCESS_CLOCKS -optc-lwasi-emulated-process-clocks -optc-DLUA_NOTEMP -optl-lsetjmp + ld-options: -lsetjmp + + package pandoc + flags: +embed_data_files -http + + package pandoc-cli + flags: -lua -server + + package pandoc-lua-engine + flags: -repl + + package pandoc-cli + flags: -repl + + allow-newer: + all:base, + all:binary, + all:bytestring, + all:containers, + all:ghc-bignum, + all:template-haskell, + all:text, + all:time + + source-repository-package + type: git + location: https://github.com/haskell-wasm/conduit.git + tag: ff33329247f2ef321dcab836e98c1bcfaff2bd13 + subdir: conduit-extra + + source-repository-package + type: git + location: https://github.com/haskell-wasm/foundation.git + tag: 8e6dd48527fb429c1922083a5030ef88e3d58dd3 + subdir: basement + + source-repository-package + type: git + location: https://github.com/haskell-wasm/hs-memory.git + tag: a198a76c584dc2cfdcde6b431968de92a5fed65e + + source-repository-package + type: git + location: https://github.com/haskell-wasm/streaming-commons.git + tag: 7e9c38b2fd55ce50d3f74fe708ca47db8c9bb315 + + source-repository-package + type: git + location: https://github.com/haskell-wasm/xml.git + tag: bc793dc9bc29c92245d3482a54d326abd3ae1403 + subdir: xml-conduit + + -- https://github.com/haskellari/splitmix/pull/73 + source-repository-package + type: git + location: https://github.com/amesgen/splitmix + tag: 5f5b766d97dc735ac228215d240a3bb90bc2ff75 + + -- only needed if we have +lua + source-repository-package + type: git + location: https://github.com/jgm/hslua.git + subdir: lua + tag: 013a0751a29f810a1a954eee4f237441007772ef + diff --git a/flake.lock b/flake.lock index 864c91efd..8b1d3d2f3 100644 --- a/flake.lock +++ b/flake.lock @@ -18,13 +18,68 @@ "type": "github" } }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "ghc-wasm-meta": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs" + }, + "locked": { + "host": "gitlab.haskell.org", + "lastModified": 1767359139, + "narHash": "sha256-Ttinox5tFOmaK3WRExsQfBFw6XT+8QwwrXQGdL96mN4=", + "owner": "haskell-wasm", + "repo": "ghc-wasm-meta", + "rev": "184c5936d3e51fdb21f9e9d8a0a0c88481767323", + "type": "gitlab" + }, + "original": { + "host": "gitlab.haskell.org", + "owner": "haskell-wasm", + "repo": "ghc-wasm-meta", + "type": "gitlab" + } + }, "nixpkgs": { "locked": { - "lastModified": 1767606049, - "narHash": "sha256-OE2fSzvBXKRe4K5/USQkdopiDU+5PdgJ8tIl5M6nY0s=", + "lastModified": 1767047869, + "narHash": "sha256-tzYsEzXEVa7op1LTnrLSiPGrcCY6948iD0EcNLWcmzo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "89dbf01df72eb5ebe3b24a86334b12c27d68016a", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1768089576, + "narHash": "sha256-x8tU88T91e1AEemjmaaLKkZsQMfsFyP9W0ri9o8ff7U=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2259340fabfc9c61fd9961ef7e2520f77bfc08e9", + "rev": "aef8bcdfb3ec01e5650b67da9ce9bf25806cc47d", "type": "github" }, "original": { @@ -36,7 +91,8 @@ "root": { "inputs": { "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs" + "ghc-wasm-meta": "ghc-wasm-meta", + "nixpkgs": "nixpkgs_2" } }, "systems": { @@ -53,6 +109,21 @@ "repo": "default", "type": "github" } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index f653bceab..23d057f0f 100644 --- a/flake.nix +++ b/flake.nix @@ -4,9 +4,11 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs"; flake-utils.url = "github:numtide/flake-utils"; + + ghc-wasm-meta.url = "gitlab:haskell-wasm/ghc-wasm-meta?host=gitlab.haskell.org"; }; - outputs = { self, nixpkgs, flake-utils }: + outputs = { self, nixpkgs, flake-utils, ghc-wasm-meta }: flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; @@ -33,6 +35,10 @@ # DON'T FORGET TO PUT YOUR PACKAGE NAME HERE, REMOVING `throw` packageName = "pandoc"; + + wasmToolchain = ghc-wasm-meta.packages.${system}.default; + # Alternatively, if you want a specific "bundle" exposed by ghc-wasm-meta: + # wasmToolchain = ghc-wasm-meta.packages.${system}.all_9_14; in { packages.${packageName} = haskellPackages.callCabal2nix packageName self rec { @@ -44,6 +50,8 @@ devShells.default = pkgs.mkShell { buildInputs = with pkgs; [ + wasmToolchain + haskellPackages.haskell-language-server # you must build it with your ghc to work haskellPackages.hlint haskellPackages.cabal-install @@ -66,6 +74,7 @@ ]; inputsFrom = map (__getAttr "env") (__attrValues self.packages.${system}); }; + devShell = self.devShells.${system}.default; }); } diff --git a/pandoc-cli/lua/PandocCLI/Lua.hs b/pandoc-cli/lua/PandocCLI/Lua.hs index df00963dd..d13e2b0a3 100644 --- a/pandoc-cli/lua/PandocCLI/Lua.hs +++ b/pandoc-cli/lua/PandocCLI/Lua.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE OverloadedStrings #-} {- | Module : PandocCLI.Lua @@ -9,8 +10,8 @@ Functions to run the pandoc Lua scripting engine. -} module PandocCLI.Lua (runLuaInterpreter, getEngine) where +#ifdef REPL import Control.Monad ((<=<)) -import HsLua.CLI (EnvBehavior (..), Settings (..), runStandalone) import System.Environment (lookupEnv) import System.IO.Temp (withSystemTempFile) import System.IO (hClose) @@ -18,6 +19,12 @@ import Text.Pandoc.Class (runIOorExplode) import Text.Pandoc.Error (handleError) import Text.Pandoc.Lua (runLua, runLuaNoEnv, getEngine) import Text.Pandoc.Version (pandocVersionText) +import HsLua.CLI (EnvBehavior (..), Settings (..), runStandalone) +#else +import Text.Pandoc.Lua (getEngine) +import System.IO (stderr, hPutStrLn) +import System.Exit (exitWith, ExitCode(..)) +#endif -- | Runs pandoc as a Lua interpreter that is (mostly) compatible with -- the default @lua@ program shipping with Lua. @@ -28,6 +35,7 @@ import Text.Pandoc.Version (pandocVersionText) runLuaInterpreter :: String -- ^ Program name -> [String] -- ^ Command line arguments -> IO () +#ifdef REPL runLuaInterpreter progName args = do -- We need some kind of temp mbhistfile <- lookupEnv "PANDOC_REPL_HISTORY" @@ -54,3 +62,8 @@ runLuaInterpreter progName args = do IgnoreEnvVars -> runLuaNoEnv ConsultEnvVars -> runLua in handleError <=< runIOorExplode . runLua' +#else +runLuaInterpreter _ _ = do + hPutStrLn stderr "Pandoc not compiled with Lua interpreter support." + exitWith $ ExitFailure 4 +#endif diff --git a/pandoc-cli/pandoc-cli.cabal b/pandoc-cli/pandoc-cli.cabal index c39c5b2eb..8fce95672 100644 --- a/pandoc-cli/pandoc-cli.cabal +++ b/pandoc-cli/pandoc-cli.cabal @@ -14,11 +14,13 @@ category: Text synopsis: Conversion between documentation formats description: Pandoc-cli provides a command-line executable that uses the pandoc library to convert between markup formats. --- data-files: extra-source-files: man/pandoc.1 man/pandoc-lua.1 man/pandoc-server.1 + wasm/pandoc.js + wasm/index.html + wasm/LICENSE source-repository head type: git location: https://github.com/jgm/pandoc.git @@ -32,6 +34,10 @@ flag server Description: Include support for running pandoc as an HTTP server. Default: True +flag repl + Description: Include support for running a pandoc Lua repl. + Default: True + flag nightly Description: Add '-nightly-COMPILEDATE' to the output of '--version'. Default: False @@ -61,19 +67,26 @@ common common-options common common-executable import: common-options - ghc-options: -rtsopts -with-rtsopts=-A8m -threaded + ghc-options: -rtsopts -with-rtsopts=-H64m executable pandoc import: common-executable hs-source-dirs: src - main-is: pandoc.hs buildable: True -- Note: we always link to an exact version of pandoc, with the -- same version as this package: - build-depends: pandoc == 3.8.3, - text + build-depends: pandoc == 3.8.3 other-modules: PandocCLI.Lua , PandocCLI.Server + + if arch(wasm32) + main-is: pandoc-wasm.hs + build-depends: aeson, containers, bytestring + ghc-options: -optl-Wl,--export=__wasm_call_ctors,--export=hs_init_with_rtsopts,--export=malloc,--export=wasm_main,--export=get_extensions_for_format + else + main-is: pandoc.hs + build-depneds: text + if flag(nightly) cpp-options: -DNIGHTLY build-depends: template-haskell, @@ -88,9 +101,12 @@ executable pandoc hs-source-dirs: no-server if flag(lua) - build-depends: hslua-cli >= 1.4.1 && < 1.5, - pandoc-lua-engine >= 0.5 && < 0.6, - temporary >= 1.1 && < 1.4 + build-depends: pandoc-lua-engine >= 0.5 && < 0.6 hs-source-dirs: lua else hs-source-dirs: no-lua + + if flag(repl) + build-depends: hslua-cli >= 1.4.1 && < 1.5, + temporary >= 1.1 && < 1.4 + cpp-options: -DREPL diff --git a/pandoc-cli/src/pandoc-wasm.hs b/pandoc-cli/src/pandoc-wasm.hs new file mode 100644 index 000000000..a8d7cc80a --- /dev/null +++ b/pandoc-cli/src/pandoc-wasm.hs @@ -0,0 +1,74 @@ +{-# LANGUAGE ScopedTypeVariables #-} + +{- | + Module : Main + Copyright : Copyright (C) 2006-2024 John MacFarlane + License : GNU GPL, version 2 or above + + Maintainer : John MacFarlane + Stability : alpha + Portability : portable + +Parses command-line options and calls the appropriate readers and +writers (wasm version). +-} +module Main where +import qualified Data.Map as M +import Text.Read (readMaybe) +import qualified Control.Exception as E +import Data.Maybe (fromMaybe) +import Text.Pandoc.App ( convertWithOpts, Opt(..), defaultOpts ) +import Text.Pandoc (Verbosity(ERROR)) +import Text.Pandoc.Extensions (extensionsToList, extensionEnabled, getAllExtensions, + getDefaultExtensions) +import PandocCLI.Lua +import Control.Exception +import Foreign +import Foreign.C +import qualified Data.Aeson as Aeson +import qualified Text.Pandoc.UTF8 as UTF8 +import qualified Data.ByteString.Lazy as BL + +foreign export ccall "wasm_main" wasm_main :: Ptr CChar -> Int -> IO () + +wasm_main :: Ptr CChar -> Int -> IO () +wasm_main raw_args_ptr raw_args_len = + E.catch act (\(err :: SomeException) -> + writeFile "/stderr" ("ERROR: " <> displayException err)) + where + act = do + args <- peekCStringLen (raw_args_ptr, raw_args_len) + free raw_args_ptr + engine <- getEngine + let aesonRes = Aeson.eitherDecode (UTF8.fromStringLazy args) + case aesonRes of + Left e -> error e + Right (f :: Opt -> Opt) -> do + let opts = f defaultOpts + let opts' = opts{ optInputFiles = + Just $ fromMaybe ["/stdin"] (optInputFiles opts) + , optOutputFile = + Just $ fromMaybe "/stdout" (optOutputFile opts) + , optLogFile = + Just $ fromMaybe "/warnings" (optLogFile opts) + , optVerbosity = ERROR -- only show errors to stderr + } + convertWithOpts engine opts' + +foreign export ccall "get_extensions_for_format" getExtensionsForFormat :: Ptr CChar -> Int -> IO () + +getExtensionsForFormat :: Ptr CChar -> Int -> IO () +getExtensionsForFormat raw_fmt_ptr raw_fmt_len = do + formatName <- readMaybe <$> peekCStringLen (raw_fmt_ptr, raw_fmt_len) + free raw_fmt_ptr + case formatName of + Just fmt -> do + let allExts = getAllExtensions fmt + let defExts = getDefaultExtensions fmt + let addExt x = M.insert (drop 4 (show x)) (extensionEnabled x defExts) + BL.writeFile "/stdout" $ Aeson.encode $ foldr addExt mempty (extensionsToList allExts) + Nothing -> writeFile "/stdout" "{}" + +-- This must be included or we get an error: +main :: IO () +main = pure () diff --git a/pandoc-cli/src/pandoc.hs b/pandoc-cli/src/pandoc.hs index d110c6f62..b6f41d1d6 100644 --- a/pandoc-cli/src/pandoc.hs +++ b/pandoc-cli/src/pandoc.hs @@ -1,5 +1,7 @@ {-# LANGUAGE CPP #-} +{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-} + {- | Module : Main Copyright : Copyright (C) 2006-2024 John MacFarlane @@ -23,7 +25,7 @@ import PandocCLI.Lua import PandocCLI.Server import Text.Pandoc.Scripting (ScriptingEngine(..)) import qualified Data.Text as T - +import System.Exit #ifdef NIGHTLY import qualified Language.Haskell.TH as TH import Data.Time diff --git a/pandoc-lua-engine/pandoc-lua-engine.cabal b/pandoc-lua-engine/pandoc-lua-engine.cabal index cb35943f6..bc8543fe0 100644 --- a/pandoc-lua-engine/pandoc-lua-engine.cabal +++ b/pandoc-lua-engine/pandoc-lua-engine.cabal @@ -44,6 +44,10 @@ source-repository head location: https://github.com/jgm/pandoc.git subdir: pandoc-lua-engine +flag repl + Description: Include pandoc Lua repl. + Default: True + common common-options default-language: Haskell2010 build-depends: base >= 4.12 && < 5 @@ -125,7 +129,6 @@ library , hslua-module-text >= 1.2 && < 1.3 , hslua-module-version >= 1.2 && < 1.3 , hslua-module-zip >= 1.1.5 && < 1.3 - , hslua-repl >= 0.1.1 && < 0.2 , lpeg >= 1.1 && < 1.2 , mtl >= 2.2 && < 2.4 , pandoc >= 3.8 && < 3.9 @@ -134,6 +137,9 @@ library , parsec >= 3.1 && < 3.2 , text >= 1.1.1 && < 2.2 + if flag(repl) + build-depends: hslua-repl >= 0.1.1 && < 0.2 + cpp-options: -DREPL test-suite test-pandoc-lua-engine import: common-options diff --git a/pandoc-lua-engine/src/Text/Pandoc/Lua/Module/CLI.hs b/pandoc-lua-engine/src/Text/Pandoc/Lua/Module/CLI.hs index 3d8ff2727..8bbfd67fe 100644 --- a/pandoc-lua-engine/src/Text/Pandoc/Lua/Module/CLI.hs +++ b/pandoc-lua-engine/src/Text/Pandoc/Lua/Module/CLI.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {- | @@ -15,11 +16,13 @@ module Text.Pandoc.Lua.Module.CLI import Control.Applicative ((<|>)) import Data.Version (makeVersion) import HsLua -import HsLua.REPL (defaultConfig, replWithEnv, setup) import Text.Pandoc.App (defaultOpts, options, parseOptionsFromArgs) import Text.Pandoc.Error (PandocError) import Text.Pandoc.Lua.PandocLua () import qualified Data.Text as T +#ifdef REPL +import HsLua.REPL (defaultConfig, replWithEnv, setup) +#endif -- | Push the pandoc.types module on the Lua stack. documentedModule :: Module PandocError @@ -46,8 +49,9 @@ documentedModule = defmodule "pandoc.cli" , "scripts, taking the list of arguments from the global `arg`." ] `since` makeVersion [3, 0] - +#ifdef REPL , repl `since` makeVersion [3, 1, 2] +#endif ] where peekArgs idx = @@ -61,6 +65,7 @@ documentedModule = defmodule "pandoc.cli" Left e -> failLua $ "Cannot process info option: " ++ show e Right opts -> pure opts +#ifdef REPL -- | Starts a REPL. repl :: DocumentedFunction PandocError repl = defun "repl" @@ -117,3 +122,4 @@ repl = defun "repl" copyval copyval pop 1 -- global table +#endif diff --git a/wasm/LICENSE b/wasm/LICENSE new file mode 100644 index 000000000..a3d114ca9 --- /dev/null +++ b/wasm/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Tweag I/O Limited. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/wasm/Makefile b/wasm/Makefile new file mode 100644 index 000000000..f84ef0e42 --- /dev/null +++ b/wasm/Makefile @@ -0,0 +1,34 @@ +SHA1=$(shell openssl sha1 -r pandoc.wasm | sed 's/ .*$$//') +EXAMPLES=$(patsubst %,%.tar,$(shell find examples -mindepth 1 -type d)) + +site/examples: + mkdir -p $@ + +site: site/examples $(patsubst %,site/%,$(EXAMPLES)) + +examples: $(EXAMPLES) + echo $(EXAMPLES) +.PHONY: examples + +site/pandoc.js: pandoc.js + perl -p -e "s/pandoc.wasm\?sha1=XX/pandoc.wasm?sha1=$(SHA1)/" $< > $@ + +site/%.html: %.html + perl -p -e "s/pandoc.js\?sha1=XX/pandoc.js?sha1=$(SHA1)/" $< > $@ + +site/examples/%.tar: examples/%.tar + cp $< $@ + +site/%: % + cp $< $@ + +upload: site site/pandoc.js site/index.html site/pandoc.wasm + rsync -av site/ website:pandoc.org/wasm-demo +.PHONY: upload + +examples/%.tar: examples/% + tar -cf "$@" -C "$<" . + +serve: + python3 -m http.server +.PHONY: serve diff --git a/wasm/examples/bibtex-to-csljson/options.json b/wasm/examples/bibtex-to-csljson/options.json new file mode 100644 index 000000000..d84da5605 --- /dev/null +++ b/wasm/examples/bibtex-to-csljson/options.json @@ -0,0 +1,4 @@ +{ + "from": "bibtex", + "to": "csljson" +} \ No newline at end of file diff --git a/wasm/examples/bibtex-to-csljson/stdin b/wasm/examples/bibtex-to-csljson/stdin new file mode 100644 index 000000000..e36e5b491 --- /dev/null +++ b/wasm/examples/bibtex-to-csljson/stdin @@ -0,0 +1,12 @@ +@BOOK{Wurm2011-ho, + title = "{Substanz und Qualität : Ein Beitrag zur Interpretation der + plotinischen Traktate VI,1, 2 und 3}", + author = "Wurm, Klaus", + publisher = "De Gruyter", + series = "Quellen und Studien zur Philosophie", + edition = "Reprint 2011", + year = 2011, + address = "Berlin", + keywords = "!!! Plotinus translation", + language = "de" +} \ No newline at end of file diff --git a/wasm/examples/csv-table-to-org/options.json b/wasm/examples/csv-table-to-org/options.json new file mode 100644 index 000000000..9fbc4705b --- /dev/null +++ b/wasm/examples/csv-table-to-org/options.json @@ -0,0 +1,4 @@ +{ + "from": "csv", + "to": "org" +} \ No newline at end of file diff --git a/wasm/examples/csv-table-to-org/stdin b/wasm/examples/csv-table-to-org/stdin new file mode 100644 index 000000000..5915766dc --- /dev/null +++ b/wasm/examples/csv-table-to-org/stdin @@ -0,0 +1,10 @@ +"Year", "Score", "Title" +1968, 86, "Greetings" +1970, 17, "Bloody Mama" +1970, 73, "Hi, Mom!" +1971, 40, "Born to Win" +1973, 98, "Mean Streets" +1973, 88, "Bang the Drum Slowly" +1974, 97, "The Godfather, Part II" +1976, 41, "The Last Tycoon" +1976, 99, "Taxi Driver" \ No newline at end of file diff --git a/wasm/examples/custom-template/custom.tpl b/wasm/examples/custom-template/custom.tpl new file mode 100644 index 000000000..d6eeda8a3 --- /dev/null +++ b/wasm/examples/custom-template/custom.tpl @@ -0,0 +1,6 @@ +

$title$

+

by $author$

+

Keywords: $for(keywords)$$it$$sep$; $endfor$

+
+$body$ +
diff --git a/wasm/examples/custom-template/options.json b/wasm/examples/custom-template/options.json new file mode 100644 index 000000000..aba47f923 --- /dev/null +++ b/wasm/examples/custom-template/options.json @@ -0,0 +1,6 @@ +{ + "from": "markdown", + "to": "html", + "template": "custom.tpl", + "standalone": true +} \ No newline at end of file diff --git a/wasm/examples/custom-template/stdin b/wasm/examples/custom-template/stdin new file mode 100644 index 000000000..ba028327d --- /dev/null +++ b/wasm/examples/custom-template/stdin @@ -0,0 +1,10 @@ +--- +keywords: +- bee +- ant +- ladybug +author: E. N. Tymologist +title: Some bugs +... + +This is a book about bugs. diff --git a/wasm/examples/docx-with-equations-to-latex/equations.docx b/wasm/examples/docx-with-equations-to-latex/equations.docx new file mode 100644 index 000000000..26dd2daaa Binary files /dev/null and b/wasm/examples/docx-with-equations-to-latex/equations.docx differ diff --git a/wasm/examples/docx-with-equations-to-latex/options.json b/wasm/examples/docx-with-equations-to-latex/options.json new file mode 100644 index 000000000..1803234e6 --- /dev/null +++ b/wasm/examples/docx-with-equations-to-latex/options.json @@ -0,0 +1,6 @@ +{ + "from": "docx", + "to": "latex", + "standalone": true, + "input-files": ["equations.docx"] +} diff --git a/wasm/examples/hello-world/options.json b/wasm/examples/hello-world/options.json new file mode 100644 index 000000000..4c0ac827e --- /dev/null +++ b/wasm/examples/hello-world/options.json @@ -0,0 +1,4 @@ +{ + "from": "markdown", + "to": "html5" +} \ No newline at end of file diff --git a/wasm/examples/hello-world/stdin b/wasm/examples/hello-world/stdin new file mode 100644 index 000000000..4bedee873 --- /dev/null +++ b/wasm/examples/hello-world/stdin @@ -0,0 +1 @@ +*Hello* world! \ No newline at end of file diff --git a/wasm/examples/highlighted-code-to-html/options.json b/wasm/examples/highlighted-code-to-html/options.json new file mode 100644 index 000000000..8fa460443 --- /dev/null +++ b/wasm/examples/highlighted-code-to-html/options.json @@ -0,0 +1,13 @@ +{ + "to": "html", + "from": "markdown", + "standalone": true, + "embed-resources": false, + "table-of-contents": false, + "number-sections": false, + "citeproc": false, + "html-math-method": "plain", + "wrap": "preserve", + "highlight-style": "kate", + "template": null +} \ No newline at end of file diff --git a/wasm/examples/highlighted-code-to-html/stdin b/wasm/examples/highlighted-code-to-html/stdin new file mode 100644 index 000000000..d5b2a7625 --- /dev/null +++ b/wasm/examples/highlighted-code-to-html/stdin @@ -0,0 +1,39 @@ +--- +title: Code with syntax highlighting +lang: en-US +... + +Here's some code with syntax highlighting: + +``` haskell +-- | Inefficient quicksort in haskell. +qsort :: (Enum a) => [a] -> [a] +qsort [] = [] +qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++ + qsort (filter (>= x) xs) +``` + +Try changing the highlighting style to see what effect this has. + +Here's some python, with numbered lines: + +``` python {.numberLines} +class FSM(object): + +"""This is a Finite State Machine (FSM). +""" + +def __init__(self, initial_state, memory=None): + + """This creates the FSM. You set the initial state here. The "memory" + attribute is any object that you want to pass along to the action + functions. It is not used by the FSM. For parsing you would typically + pass a list to be used as a stack. """ + + # Map (input_symbol, current_state) --> (action, next_state). + self.state_transitions = {} + # Map (current_state) --> (action, next_state). + self.state_transitions_any = {} + self.default_transition = None + ... +``` diff --git a/wasm/examples/ipynb-to-rtf/options.json b/wasm/examples/ipynb-to-rtf/options.json new file mode 100644 index 000000000..88602529b --- /dev/null +++ b/wasm/examples/ipynb-to-rtf/options.json @@ -0,0 +1,5 @@ +{ + "from": "ipynb", + "to": "rtf", + "standalone": true +} \ No newline at end of file diff --git a/wasm/examples/ipynb-to-rtf/stdin b/wasm/examples/ipynb-to-rtf/stdin new file mode 100644 index 000000000..5fad9322e --- /dev/null +++ b/wasm/examples/ipynb-to-rtf/stdin @@ -0,0 +1,68 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Lorem ipsum\n", + "\n", + "**Lorem ipsum** dolor sit amet, consectetur adipiscing elit. Nunc luctus\n", + "bibendum felis dictum sodales." + ], + "id": "42a14256-91c8-446e-92a7-ab6bf11055d3" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"hello\")" + ], + "id": "98ee7437-e11a-4c16-b642-9e7911f32cd2" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Pyout" + ], + "id": "2df739f6-1afd-400b-845c-ad1efebc209f" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.display import HTML\n", + "HTML(\"\"\"\n", + "\n", + "HTML\n", + "\"\"\")" + ], + "id": "622b77f5-76e7-46cb-a694-56007ed6adbe" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Image\n", + "\n", + "This image ![the moon](attachment:lalune.jpg) will be included as a cell\n", + "attachment." + ], + "attachments": { + "lalune.jpg": { + "image/jpeg": "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\n3FNQTvPJ7UYAelf/2Q==\n" + } + }, + "id": "0db42901-5dc0-4fd3-b2db-b83b3c584437" + } + ], + "nbformat": 4, + "nbformat_minor": 5, + "metadata": {} +} \ No newline at end of file diff --git a/wasm/examples/latex-to-docbook-with-mathml/options.json b/wasm/examples/latex-to-docbook-with-mathml/options.json new file mode 100644 index 000000000..8459c7bf5 --- /dev/null +++ b/wasm/examples/latex-to-docbook-with-mathml/options.json @@ -0,0 +1,6 @@ +{ + "from": "latex", + "to": "docbook5", + "html-math-method": "mathml", + "standalone": true +} \ No newline at end of file diff --git a/wasm/examples/latex-to-docbook-with-mathml/stdin b/wasm/examples/latex-to-docbook-with-mathml/stdin new file mode 100644 index 000000000..a5e3ecf5f --- /dev/null +++ b/wasm/examples/latex-to-docbook-with-mathml/stdin @@ -0,0 +1,27 @@ +\newtheorem{theorem}{Theorem} +\newtheorem{corollary}[theorem]{Corollary} +\newtheorem{lemma}[theorem]{Lemma} +\theoremstyle{definition} +\newtheorem{definition}[theorem]{Definition} +\theoremstyle{remark} +\newtheorem{remark}{Remark} + +\begin{definition}[right-angled triangles] \label{def:tri} +A \emph{right-angled triangle} is a triangle whose sides of length~\(a\), \(b\) and~\(c\), in some permutation of order, satisfies \(a^2+b^2=c^2\). +\end{definition} + +\begin{lemma} +The triangle with sides of length~\(3\), \(4\) and~\(5\) is right-angled. +\end{lemma} + +\begin{proof} +This lemma follows from \cref{def:tri} since \(3^2+4^2=9+16=25=5^2\). +\end{proof} + +\begin{theorem}[Pythagorean triplets] \label{thm:py} +Triangles with sides of length \(a=p^2-q^2\), \(b=2pq\) and \(c=p^2+q^2\) are right-angled triangles. +\end{theorem} + +\begin{remark} +These are all pretty interesting facts. +\end{remark} diff --git a/wasm/examples/latex-with-macros-to-restructured-text/options.json b/wasm/examples/latex-with-macros-to-restructured-text/options.json new file mode 100644 index 000000000..514250ff3 --- /dev/null +++ b/wasm/examples/latex-with-macros-to-restructured-text/options.json @@ -0,0 +1,6 @@ +{ + "from": "latex", + "to": "rst", + "standalone": true, + "citeproc": false +} \ No newline at end of file diff --git a/wasm/examples/latex-with-macros-to-restructured-text/stdin b/wasm/examples/latex-with-macros-to-restructured-text/stdin new file mode 100644 index 000000000..d7bc93abb --- /dev/null +++ b/wasm/examples/latex-with-macros-to-restructured-text/stdin @@ -0,0 +1,9 @@ +% from https://en.wikibooks.org/wiki/LaTeX/Macros +\newcommand{\wbalTwo}[2][Wikimedia]{ +This is the Wikibook about LaTeX +supported by {#1} and {#2}!} + +\begin{itemize} +\item \wbalTwo{John Doe} +\item \wbalTwo[lots of users]{John Doe} +\end{itemize} \ No newline at end of file diff --git a/wasm/examples/man-page-to-context/options.json b/wasm/examples/man-page-to-context/options.json new file mode 100644 index 000000000..896669a13 --- /dev/null +++ b/wasm/examples/man-page-to-context/options.json @@ -0,0 +1,4 @@ +{ + "from": "man", + "to": "context" +} \ No newline at end of file diff --git a/wasm/examples/man-page-to-context/stdin b/wasm/examples/man-page-to-context/stdin new file mode 100644 index 000000000..4f1780776 --- /dev/null +++ b/wasm/examples/man-page-to-context/stdin @@ -0,0 +1,40 @@ +.TP +\f[C]-L\f[R] \f[I]SCRIPT\f[R], \f[C]--lua-filter=\f[R]\f[I]SCRIPT\f[R] +Transform the document in a similar fashion as JSON filters (see +\f[C]--filter\f[R]), but use pandoc\[cq]s built-in Lua filtering system. +The given Lua script is expected to return a list of Lua filters which +will be applied in order. +Each Lua filter must contain element-transforming functions indexed by +the name of the AST element on which the filter function should be +applied. +.RS +.PP +The \f[C]pandoc\f[R] Lua module provides helper functions for element +creation. +It is always loaded into the script\[cq]s Lua environment. +.PP +See the Lua filters documentation for further details. +.PP +In order of preference, pandoc will look for Lua filters in +.IP "1." 3 +a specified full or relative path, +.IP "2." 3 +\f[C]$DATADIR/filters\f[R] where \f[C]$DATADIR\f[R] is the user data +directory (see \f[C]--data-dir\f[R], above). +.PP +Filters, Lua filters, and citeproc processing are applied in the order +specified on the command line. +.RE +.TP +\f[C]-M\f[R] \f[I]KEY\f[R][\f[C]=\f[R]\f[I]VAL\f[R]], \f[C]--metadata=\f[R]\f[I]KEY\f[R][\f[C]:\f[R]\f[I]VAL\f[R]] +Set the metadata field \f[I]KEY\f[R] to the value \f[I]VAL\f[R]. +A value specified on the command line overrides a value specified in the +document using YAML metadata blocks. +Values will be parsed as YAML boolean or string values. +If no value is specified, the value will be treated as Boolean true. +Like \f[C]--variable\f[R], \f[C]--metadata\f[R] causes template +variables to be set. +But unlike \f[C]--variable\f[R], \f[C]--metadata\f[R] affects the +metadata of the underlying document (which is accessible from filters +and may be printed in some output formats) and metadata values will be +escaped when inserted into the template. \ No newline at end of file diff --git a/wasm/examples/markdown-citations-to-plain-with-csl-style/le-tapuscrit-note.csl b/wasm/examples/markdown-citations-to-plain-with-csl-style/le-tapuscrit-note.csl new file mode 100644 index 000000000..03b69dfc4 --- /dev/null +++ b/wasm/examples/markdown-citations-to-plain-with-csl-style/le-tapuscrit-note.csl @@ -0,0 +1,496 @@ + + \ No newline at end of file diff --git a/wasm/examples/markdown-citations-to-plain-with-csl-style/options.json b/wasm/examples/markdown-citations-to-plain-with-csl-style/options.json new file mode 100644 index 000000000..78ec5985a --- /dev/null +++ b/wasm/examples/markdown-citations-to-plain-with-csl-style/options.json @@ -0,0 +1,7 @@ +{ + "from": "markdown", + "to": "plain", + "citeproc": true, + "csl": "le-tapuscrit-note.csl", + "bibliography": "refs.bib" +} diff --git a/wasm/examples/markdown-citations-to-plain-with-csl-style/refs.bib b/wasm/examples/markdown-citations-to-plain-with-csl-style/refs.bib new file mode 100644 index 000000000..ec7a9e761 --- /dev/null +++ b/wasm/examples/markdown-citations-to-plain-with-csl-style/refs.bib @@ -0,0 +1,9 @@ +@book{legras_michel_2010, + author = {Le~Gras, Gwénaëlle}, + publisher = {Scope}, + title = {Michel Simon~: l’art de la disgrâce}, + series = {Jeux d’acteurs}, + date = {2010}, + address = {Paris}, + isbn = {978-2-912573-52-0}, + langid = {fre}} \ No newline at end of file diff --git a/wasm/examples/markdown-citations-to-plain-with-csl-style/stdin b/wasm/examples/markdown-citations-to-plain-with-csl-style/stdin new file mode 100644 index 000000000..1b1c0f5d0 --- /dev/null +++ b/wasm/examples/markdown-citations-to-plain-with-csl-style/stdin @@ -0,0 +1,7 @@ +--- +csl: 'le-tapuscrit-note.csl' +lang: fr-FR +bibliography: refs.bib +--- + +Foo [@legras_michel_2010]. \ No newline at end of file diff --git a/wasm/examples/markdown-to-docbook-with-citations/options.json b/wasm/examples/markdown-to-docbook-with-citations/options.json new file mode 100644 index 000000000..0d3cddc97 --- /dev/null +++ b/wasm/examples/markdown-to-docbook-with-citations/options.json @@ -0,0 +1,6 @@ +{ + "from": "markdown", + "to": "docbook5", + "standalone": true, + "citeproc": true +} \ No newline at end of file diff --git a/wasm/examples/markdown-to-docbook-with-citations/stdin b/wasm/examples/markdown-to-docbook-with-citations/stdin new file mode 100644 index 000000000..9a965f117 --- /dev/null +++ b/wasm/examples/markdown-to-docbook-with-citations/stdin @@ -0,0 +1,22 @@ +--- +references: +- author: + - family: Salam + given: Abdus + container-title: "Elementary particle theory: Relativistic groups and + analyticity. Proceedings of the eighth Nobel symposium" + editor: + - family: Svartholm + given: Nils + event-date: 1968-05-19/1968-05-25 + event-place: Aspenäsgarden, Lerum + id: salam + issued: 1968 + page: 367-377 + publisher: Almquist & Wiksell + publisher-place: Stockholm + title: Weak and electromagnetic interactions + type: paper-conference +--- + +@salam [p. 370] says some interesting things. \ No newline at end of file diff --git a/wasm/examples/markdown-to-revealjs-slides/options.json b/wasm/examples/markdown-to-revealjs-slides/options.json new file mode 100644 index 000000000..ab945447a --- /dev/null +++ b/wasm/examples/markdown-to-revealjs-slides/options.json @@ -0,0 +1,9 @@ +{ + "to": "revealjs", + "from": "markdown", + "standalone": true, + "citeproc": false, + "html-math-method": "mathjax", + "highlight-style": "pygments", + "template": null +} \ No newline at end of file diff --git a/wasm/examples/markdown-to-revealjs-slides/stdin b/wasm/examples/markdown-to-revealjs-slides/stdin new file mode 100644 index 000000000..2330117cc --- /dev/null +++ b/wasm/examples/markdown-to-revealjs-slides/stdin @@ -0,0 +1,560 @@ +--- +title: Pandoc for TeXnicians +author: John MacFarlane +date: TUG 2020, 2020-07-26 +theme: solarized +header-includes: | + +... + +# Overview + +## + +- What is pandoc? +- Using pandoc to convert to and from LaTeX +- Why write in Markdown? +- Overcoming Markdown's limitations + +# What is pandoc? + +## + + + +## Let's take it for a spin + +``` +% cat simple.tex +\section{On $e=mc^2$}\label{einstein} +``` + +``` +% pandoc -f latex -t native simple.tex +% pandoc -f latex -t html simple.tex +% pandoc -t html --mathml simple.tex +% pandoc -t html --mathjax simple.tex +% pandoc -t -html --mathjax -s simple.tex +% pandoc -t ms simple.tex +% pandoc -t gfm simple.tex +% pandoc -t context simple.tex +% pandoc -t jats simple.tex +``` + + +## Some math + +Let's try with a sample TeX document by Professor A.J. Roberts +at the University of Adelaide (CC licensed). + + + +## Some math + +``` +% pandoc maths.tex -o maths.docx +``` + +. . . + +Two problems: + +- the use of a low-level TeX primitive `\mathcode`. +- the use of `\parbox` (line 288) + +Fix by removing the `\mathcode` stuff and +redefining the `\parmath` macro as a no-op: + +```latex +\newcommand{\parmath}[2][]{#2} +``` + +## Take two + +``` +% pandoc maths.tex --number-sections -o maths.docx +% open maths.docx +``` + +- AMS theorem environments come out right, including references. +- Math is translated into native Word equation objects, which + can be edited and which match the font, rather than images. +- Still missing: equation numbers. + +## Going the other way + +``` +% pandoc maths.docx -o newmaths.tex -s +% xelatex newmaths +% xelatex newmaths +``` + +## Converting to HTML + +``` +% pandoc maths.tex -s -o maths.html --mathml \ + --number-sections --toc +% open maths.html +``` + +## Comparison with latex2rtf + +``` +% latex2rtf maths.tex +% open -a "Microsoft Word" maths.rtf +``` + +- References not resolved in Section 1 +- Accents in Section 2 not above the letters, math generally + ugly +- Arrays in Section 8 totally broken; same with subequations in + Section 9 +- But at least we do get equation numbers in Section 9 + +## Comparison with tex4ht + +``` +% make4ht maths +% open maths.html +``` + +- Theorem environments not handled in Section 1 (except for one?). +- Missing accents in Section 2. +- Ugly equations that incorporate both text and images in + different fonts. + +## Comparison with Word from PDF + +``` +% pdflatex maths +% pdflatex maths +% open -a "Microsoft Word" maths.pdf +``` + +- Section 2, accents messed up. +- Some formulas are rendered with images, others with + regular characters, in non-matching font. +- The 'where' in Section 6 is badly mispleacd. +- The integral is missing in Section 7 +- The diagonal ellipses are missing in the arrays + + +## Pandoc can interpret TeX macros + +``` +% cat macros.tex +\newcommand{\nec}{\Box} +\newcommand{\if}[2]{#1 \rightarrow #2} +\newenvironment{warning}% + {\begin{quote}\textbf{WARNING!}}% + {\end{quote}} + +$\if{\nec \phi}{\phi}$ +\begin{warning} +Don't try this at home. +\end{warning} +``` + +``` +% pandoc macros.tex -t html +``` + +## Pandoc can resolve bibtex citations + +With the help of the `pandoc-citeproc` filter +(included in the released binaries). + +``` +% pandoc --filter pandoc-citeproc bib.tex \ + -t plain --csl ieee.csl +``` + +## Limitations + +Pandoc is far from being able +to convert arbitrary tex files with high accuracy. + +Let's try with a real-world example I got at random from arxiv. + +``` +% cd arxiv.2007.07694v1 +% pandoc arxiv.tex -o arxiv.docx +``` + +# An alternative + +## An alternative + +So you can't just write in LaTeX and expect to convert at the +last minute to docx (for a publisher) or epub (for your +students) or HTML (for your website). + +An alternative: write your document +in pandoc's extended version of Markdown, which pandoc +can convert with complete accuracy to any of its +output formats. + + +## What is Markdown? + +Markdown is a set of conventions for indicating document +formatting in plain text, mostly inherited from the pre-internet +days of bulletin boards and email. + +It was designed in 2004 by John Gruber with help from Aaron +Schwartz, and it is currently much used by programmers, +and on forums like stackoverflow and reddit, and by +data scientists via Jupyter notebooks and RMarkdown. + + + +## Appealing things about Markdown + +The source text is readable as it is. +When writing and revising, you don't have +to parse through command-words which aren't part +of the content. + +. . . + +If you're writing in a language other than English, you +don't have to have English words sprinkled in the text. + +. . . + +There's no boilerplate at the beginning. The document +just starts with the text. + +## Real separation of content from formatting. + +\vspace{1em} + +> The paucity of means is the greatest virtue of markdown and +> pandoc markdown. +> +> It is strangely difficult to get people to see the point, but the +> defects of LaTeX for concentration, writing and thought, are at least +> as great as those of Word, for the simple reason that it gives the +> writer too much power; there is always another package to call in the +> preamble, as there is always another drop down menu in Word. +> ... +> +> In markdown - not to put too fine a point on it - the writer is only +> ever faced with one question, and it is the right one: what the next +> sentence should be. +> +> --- Michael Thompson, pandoc-discuss mailing list + + +## Appealing things about Markdown + +Using Markdown makes it possible to collaborate with +others who don't know LaTeX. + +## Appealing things about Markdown + +Markdown can be converted with complete, reliable accuracy +into many different formats. + +It's often not enough just to produce a PDF. + +- JATS for publication or archiving +- EPUB for convenient reading on mobile devices +- Docx or ICML for a publisher +- HTML for a website (or accessibility) +- Jupyter notebook for research +- Beamer or reveal.js slides for presentation + +TeX is a great assembly language for publication-quality +documents. + +## Limitations of Markdown + +John Gruber's original markdown syntax lacks support for: + +- [ ] tables +- [ ] figures +- [ ] footnotes +- [ ] definition lists +- [ ] ordered lists other than decimal-numbered +- [ ] super/subscript +- [ ] math +- [ ] document metadata +- [ ] attributes or metadata on individual elements like sections +- [ ] labels and cross-references +- [ ] numbering for running examples or equations + +## Limitations of Markdown + +We couldn't live without these things in academic writing. + +And we definitely couldn't live without + +- [ ] bibtex/biblatex +- [ ] macros + +How can we overcome these limitations? + +# Overcoming Markdown's limitations + +## Pandoc's extended Markdown syntax + +- [x] tables (limited) +- [x] figures (limited) +- [x] math +- [x] footnotes +- [x] definition lists +- [x] more flexible ordered lists +- [x] running example lists +- [x] super/subscript +- [x] strikeout +- [x] metadata +- [x] attributes +- [x] generic containers + +## + +Pandoc also understands LaTeX macro definitions, which +you can use for math (no matter what the output format). + +## + +Labels and cross-references are still a work in progress, +but you can get good support for them using an external +filter, `pandoc-crossref`, by pandoc contributor +Nikolay Yakimov. + +## + +You can use the `--citeproc` filter to resolve citations +in this syntax: + +``` +Blah blah [@putnam:empirical, p. 33; see also +@dummett:empirical]. +``` + +Change the style by specifying a CSL stylesheet. +(You can even change between author-date, numerical, +and footnote sytles with no modifications to the source.) + +You can use your existing bibtex or biblatex bibliography +file, or a CSL JSON bibliography such as can be produced +by Zotero. + +## + +LaTeX macros allow you to define new constructions +that exactly fit what you're writing about. Can +we recover this flexibility? + +## Raw TeX in Markdown + +One approach is to just include bits of raw TeX in +your markdown file. Pandoc allows that. + +- There is a special syntax for indicating chunks of raw TeX, + but pandoc will also recognize obvious bits of raw TeX + and pass them through as such. + +- The raw TeX chunks will be passed on unchanged if the output format + is `latex`, `beamer`, or `context`, and otherwise simply omitted. + +## + +``` +% cat raw.md +% pandoc raw.md -o raw.pdf +% open raw.pdf +``` +But: +``` +% pandoc raw.md -s -o raw.html +% open raw.html +``` + + +## + +Drawbacks: + +- With this approach you lose the ability to + target multiple formats. +- Your source is now an ugly mix of Markdown and + TeX, compromising readability. + + +## A better approach + +1. Adopt the convention that + a certain thing representable in pandoc's markdown + should be interpreted as, say, a dropped capital letter. + +2. Write a filter that does the interpretation. + +## Example: drop caps + +In LaTeX we can use the `lettrine` package to +get dropped capitals at the beginning of chapters: + +```latex +\lettrine{T}{his} is a pulley +``` + +We will use a generic bracketed span with a class +to represent this in Markdown: + +``` +[This]{.dropcap} is a pulley. + +``` + +## Example: drop caps + +Now we need a filter that replaces +`Span` elements with class `dropcap` in the Pandoc AST +with something appropriate for the output format. + +![](pandoc-architecture.pdf){height=3in} + +## Two kinds of filters + +- **JSON filters** operate on a serialized JSON +representation of the pandoc AST. They +can be written in any language that can consume +and produce JSON. + +- **Lua filters** use a Lua interpreter +and environment built into pandoc. +No external software need be installed, and +the filters are more efficient, +because we don't need to serialize and deserialize +as JSON. + +Documentation: https://pandoc.org/lua-filters.html + +## Example: drop caps + +In a Lua filter we define functions that match +different kinds of AST elements. Here we want to +match a Span. Create a file `dropcap.lua`: + +```lua +function Span(el) + -- do something with the Span (el) + -- return the transformed element or a new element +end +``` + +## Example: drop caps + +We only want to do something if the Span has the +class `dropcap` and its contents begin with a Str +element. + +```lua +function Span(el) + if el.classes:includes('dropcap') then + return make_dropcap(el.content) + end +end +``` + +## Example: drop caps + +Now we just have to define `make_dropcap`. It takes +a list of Inline elements (`el.content`) and returns +a list of Inline elements. + +\small + +```lua +local function make_dropcap(els) + if els[1] and els[1].t == 'Str' then -- arrays start at 1! + local first_letter, rest = els[1].text:match('(%a)(.*)') + if FORMAT == 'latex' then + els[1] = pandoc.RawInline('latex', + '\\lettrine{' .. first_letter .. + '}{' .. rest .. '}') + elseif FORMAT:match('html') then + els[1] = pandoc.Span({ + pandoc.Span(pandoc.Str(first_letter), + {class='dropcap-first'}), + pandoc.Span(pandoc.Str(rest), + {class='dropcap-rest'})}) + end + return els + end +end +``` + +## Example: drop caps + +``` +% pandoc -L dropcap.lua -t latex -o dropcap.pdf +% pandoc -L dropcap.lua -t html -s --css dropcap.css \ + dropcap.md -o dropcap.html +``` + +## Example: tikz diagrams + +To get a tikz diagram, we could have a filter turn +specially marked code blocks into images. + +In fact, there is already a very nice general +diagram filter at https://github.com/pandoc/lua-filters. + +``` +% cat diagram.md +% pandoc diagram.md -L diagram-generator.lua -s \ + --extract-media=media -o diagram.html +% pandoc diagram.md -L diagram-generator.lua \ + -o diagram.docx +``` + +## Example: theorems + +How to reproduce LaTeX `theorem` environments? + +Markdown version: +``` +::: {.theorem #pythagoras} +#### Pythagoras's Theorem +In a right triangle, the lengths of the two shorter sides +$a$, $b$ and the longer side $c$ stand in the relation +$$ +a^2 + b^2 = c^2. +$$ +::: +``` + +## Example: theorems + +``` +% cat theorem.lua +% cat theorem.md +% pandoc -L theorem.lua theorem.md -t latex +% pandoc theorem.md -L theorem.lua -t plain +% pandoc theorem.md -L theorem.lua -t rst +% pandoc theorem.md -L theorem.lua -t html +``` + +## The end + +- For pandoc questions, come to pandoc-discuss on google groups: + +- For bug reports, the tracker at https://github.com/jgm/pandoc +- If you'd like to improve pandoc's handling of LaTeX, + we can always use new contributors! + +Questions? + diff --git a/wasm/examples/markdown-to-rst/options.json b/wasm/examples/markdown-to-rst/options.json new file mode 100644 index 000000000..750f8df4e --- /dev/null +++ b/wasm/examples/markdown-to-rst/options.json @@ -0,0 +1,10 @@ +{ + "to": "rst", + "from": "markdown", + "standalone": true, + "embed-resources": false, + "citeproc": false, + "html-math-method": "plain", + "wrap": "auto", + "template": null +} \ No newline at end of file diff --git a/wasm/examples/markdown-to-rst/stdin b/wasm/examples/markdown-to-rst/stdin new file mode 100644 index 000000000..7c7cd7c8a --- /dev/null +++ b/wasm/examples/markdown-to-rst/stdin @@ -0,0 +1,250 @@ +--- +author: +- Albert Krewinkel +- John MacFarlane +date: 'January 10, 2020' +title: Pandoc Lua Filters +--- + +# Introduction + +Pandoc has long supported filters, which allow the pandoc +abstract syntax tree (AST) to be manipulated between the parsing +and the writing phase. [Traditional pandoc +filters](https://pandoc.org/filters.html) accept a JSON +representation of the pandoc AST and produce an altered JSON +representation of the AST. They may be written in any +programming language, and invoked from pandoc using the +`--filter` option. + +Although traditional filters are very flexible, they have a +couple of disadvantages. First, there is some overhead in +writing JSON to stdout and reading it from stdin (twice, once on +each side of the filter). Second, whether a filter will work +will depend on details of the user's environment. A filter may +require an interpreter for a certain programming language to be +available, as well as a library for manipulating the pandoc AST +in JSON form. One cannot simply provide a filter that can be +used by anyone who has a certain version of the pandoc +executable. + +Starting with version 2.0, pandoc makes it possible to write +filters in Lua without any external dependencies at all. A Lua +interpreter (version 5.3) and a Lua library for creating pandoc +filters is built into the pandoc executable. Pandoc data types +are marshaled to Lua directly, avoiding the overhead of writing +JSON to stdout and reading it from stdin. + +Here is an example of a Lua filter that converts strong emphasis +to small caps: + +``` lua +return { + { + Strong = function (elem) + return pandoc.SmallCaps(elem.c) + end, + } +} +``` + +or equivalently, + +``` lua +function Strong(elem) + return pandoc.SmallCaps(elem.c) +end +``` + +This says: walk the AST, and when you find a Strong element, +replace it with a SmallCaps element with the same content. + +To run it, save it in a file, say `smallcaps.lua`, and invoke +pandoc with `--lua-filter=smallcaps.lua`. + +Here's a quick performance comparison, converting the pandoc +manual (MANUAL.txt) to HTML, with versions of the same JSON +filter written in compiled Haskell (`smallcaps`) and interpreted +Python (`smallcaps.py`): + + Command Time + --------------------------------------- ------- + `pandoc` 1.01s + `pandoc --filter ./smallcaps` 1.36s + `pandoc --filter ./smallcaps.py` 1.40s + `pandoc --lua-filter ./smallcaps.lua` 1.03s + +As you can see, the Lua filter avoids the substantial overhead +associated with marshaling to and from JSON over a pipe. + +# Lua filter structure + +Lua filters are tables with element names as keys and values +consisting of functions acting on those elements. + +Filters are expected to be put into separate files and are +passed via the `--lua-filter` command-line argument. For +example, if a filter is defined in a file `current-date.lua`, +then it would be applied like this: + + pandoc --lua-filter=current-date.lua -f markdown MANUAL.txt + +The `--lua-filter` option may be supplied multiple times. Pandoc +applies all filters (including JSON filters specified via +`--filter` and Lua filters specified via `--lua-filter`) in the +order they appear on the command line. + +Pandoc expects each Lua file to return a list of filters. The +filters in that list are called sequentially, each on the result +of the previous filter. If there is no value returned by the +filter script, then pandoc will try to generate a single filter +by collecting all top-level functions whose names correspond to +those of pandoc elements (e.g., `Str`, `Para`, `Meta`, or +`Pandoc`). (That is why the two examples above are equivalent.) + +For each filter, the document is traversed and each element +subjected to the filter. Elements for which the filter contains +an entry (i.e. a function of the same name) are passed to Lua +element filtering function. In other words, filter entries will +be called for each corresponding element in the document, +getting the respective element as input. + +The return value of a filter function must be one of the +following: + +- nil: this means that the object should remain unchanged. +- a pandoc object: this must be of the same type as the input + and will replace the original object. +- a list of pandoc objects: these will replace the original + object; the list is merged with the neighbors of the + original objects (spliced into the list the original object + belongs to); returning an empty list deletes the object. + +The function's output must result in an element of the same type +as the input. This means a filter function acting on an inline +element must return either nil, an inline, or a list of inlines, +and a function filtering a block element must return one of nil, +a block, or a list of block elements. Pandoc will throw an error +if this condition is violated. + +If there is no function matching the element's node type, then +the filtering system will look for a more general fallback +function. Two fallback functions are supported, `Inline` and +`Block`. Each matches elements of the respective type. + +Elements without matching functions are left untouched. + +See [module documentation](#module-pandoc) for a list of pandoc +elements. + +## Filters on element sequences + +For some filtering tasks, it is necessary to know the order +in which elements occur in the document. It is not enough then to +inspect a single element at a time. + +There are two special function names, which can be used to define +filters on lists of blocks or lists of inlines. + +[`Inlines (inlines)`]{#inlines-filter} +: If present in a filter, this function will be called on all + lists of inline elements, like the content of a [Para] + (paragraph) block, or the description of an [Image]. The + `inlines` argument passed to the function will be a [List] of + [Inline] elements for each call. + +[`Blocks (blocks)`]{#blocks-filter} +: If present in a filter, this function will be called on all + lists of block elements, like the content of a [MetaBlocks] + meta element block, on each item of a list, and the main + content of the [Pandoc] document. The `blocks` argument + passed to the function will be a [List] of [Block] elements + for each call. + +These filter functions are special in that the result must either +be nil, in which case the list is left unchanged, or must be a +list of the correct type, i.e., the same type as the input +argument. Single elements are **not** allowed as return values, +as a single element in this context usually hints at a bug. + +See ["Remove spaces before normal citations"][Inlines filter +example] for an example. + +This functionality has been added in pandoc 2.9.2. + +[Inlines filter example]: #remove-spaces-before-citations + +## Traversal order + +The traversal order of filters can be selected by setting the key +`traverse` to either `'topdown'` or `'typewise'`; the default is +`'typewise'`. + +Example: + +``` lua +local filter = { + traverse = 'topdown', + -- ... filter functions ... +} +return {filter} +``` + +Support for this was added in pandoc 2.17; previous versions +ignore the `traverse` setting. + +### Typewise traversal + +Element filter functions within a filter set are called in a +fixed order, skipping any which are not present: + + 1. functions for [*Inline* elements](#type-inline), + 2. the [`Inlines`](#inlines-filter) filter function, + 2. functions for [*Block* elements](#type-block) , + 2. the [`Blocks`](#inlines-filter) filter function, + 3. the [`Meta`](#type-meta) filter function, and last + 4. the [`Pandoc`](#type-pandoc) filter function. + +It is still possible to force a different order by explicitly +returning multiple filter sets. For example, if the filter for +*Meta* is to be run before that for *Str*, one can write + +``` lua +-- ... filter definitions ... + +return { + { Meta = Meta }, -- (1) + { Str = Str } -- (2) +} +``` + +Filter sets are applied in the order in which they are returned. +All functions in set (1) are thus run before those in (2), +causing the filter function for *Meta* to be run before the +filtering of *Str* elements is started. + +### Topdown traversal + +It is sometimes more natural to traverse the document tree +depth-first from the root towards the leaves, and all in a single +run. + +For example, a block list `[Plain [Str "a"], Para [Str +"b"]]`{.haskell} will try the following filter functions, in +order: `Blocks`, `Plain`, `Inlines`, `Str`, `Para`, `Inlines`, +`Str`. + +Topdown traversals can be cut short by returning `false` as a +second value from the filter function. No child-element of +the returned element is processed in that case. + +For example, to exclude the contents of a footnote from being +processed, one might write + +``` lua +traverse = 'topdown' +function Note (n) + return n, false +end +``` + diff --git a/wasm/examples/mediawiki-to-docx-with-equations/options.json b/wasm/examples/mediawiki-to-docx-with-equations/options.json new file mode 100644 index 000000000..a8f168ca1 --- /dev/null +++ b/wasm/examples/mediawiki-to-docx-with-equations/options.json @@ -0,0 +1,6 @@ +{ + "from": "mediawiki", + "to": "docx", + "output-file": "vectors.docx", + "standalone": true +} diff --git a/wasm/examples/mediawiki-to-docx-with-equations/stdin b/wasm/examples/mediawiki-to-docx-with-equations/stdin new file mode 100644 index 000000000..18cb37bbb --- /dev/null +++ b/wasm/examples/mediawiki-to-docx-with-equations/stdin @@ -0,0 +1,8 @@ +Just as the components of a vector change when we change the [[basis (linear algebra)|basis]] of the vector space, the components of a tensor also change under such a transformation. Each type of tensor comes equipped with a ''transformation law'' that details how the components of the tensor respond to a [[change of basis]]. The components of a vector can respond in two distinct ways to a [[change of basis]] (see [[covariance and contravariance of vectors]]), where the new [[basis vectors]] \mathbf{\hat{e}}_i are expressed in terms of the old basis vectors \mathbf{e}_j as, +:\mathbf{\hat{e}}_i = \sum_{j=1}^n \mathbf{e}_j R^j_i = \mathbf{e}_j R^j_i . + +Here ''R'''' j''''i'' are the entries of the change of basis matrix, and in the rightmost expression the [[summation]] sign was suppressed: this is the [[Einstein summation convention]], which will be used throughout this article.The Einstein summation convention, in brief, requires the sum to be taken over all values of the index whenever the same symbol appears as a subscript and superscript in the same term. For example, under this convention B_i C^i = B_1 C^1 + B_2 C^2 + \cdots B_n C^n The components ''v''''i'' of a column vector '''v''' transform with the [[matrix inverse|inverse]] of the matrix ''R'', +:\hat{v}^i = \left(R^{-1}\right)^i_j v^j, + +where the hat denotes the components in the new basis. This is called a ''contravariant'' transformation law, because the vector components transform by the ''inverse'' of the change of basis. In contrast, the components, ''w''''i'', of a covector (or row vector), '''w''', transform with the matrix ''R'' itself, +:\hat{w}_i = w_j R^j_i . \ No newline at end of file diff --git a/wasm/examples/ris-to-formatted-markdown-bibliography/options.json b/wasm/examples/ris-to-formatted-markdown-bibliography/options.json new file mode 100644 index 000000000..ff17f00b8 --- /dev/null +++ b/wasm/examples/ris-to-formatted-markdown-bibliography/options.json @@ -0,0 +1,9 @@ +{ + "to": "markdown_strict", + "from": "ris", + "standalone": false, + "embed-resources": false, + "citeproc": true, + "html-math-method": "mathml", + "wrap": "auto" +} diff --git a/wasm/examples/ris-to-formatted-markdown-bibliography/stdin b/wasm/examples/ris-to-formatted-markdown-bibliography/stdin new file mode 100644 index 000000000..f0ba798ff --- /dev/null +++ b/wasm/examples/ris-to-formatted-markdown-bibliography/stdin @@ -0,0 +1,20 @@ +TY - JOUR +T1 - On computable numbers, with an application to the Entscheidungsproblem +A1 - Turing, Alan Mathison +JO - Proceedings of London Mathematical Society +VL - 47 +IS - 1 +SP - 230 +EP - 265 +Y1 - 1937 +ER - +TY - JOUR +AU - Shannon, Claude E. +PY - 1948 +DA - July +TI - A Mathematical Theory of Communication +T2 - Bell System Technical Journal +SP - 379 +EP - 423 +VL - 27 +ER - diff --git a/wasm/examples/rst-table-from-yaml-data/custom.rst b/wasm/examples/rst-table-from-yaml-data/custom.rst new file mode 100644 index 000000000..cc7eb0d5d --- /dev/null +++ b/wasm/examples/rst-table-from-yaml-data/custom.rst @@ -0,0 +1,7 @@ ++------------------+----------+-----------------------------------------------+ +| Species | Calories | Location | ++==================+==========+===============================================+ +$for(fish)$ +${ it:species()/left 16 "| " " | "}${ it.calories/right 8 "" " | " }${ it.location/left 45 "" " |"} ++------------------+----------+-----------------------------------------------+ +$endfor$ \ No newline at end of file diff --git a/wasm/examples/rst-table-from-yaml-data/options.json b/wasm/examples/rst-table-from-yaml-data/options.json new file mode 100644 index 000000000..1ec0364f3 --- /dev/null +++ b/wasm/examples/rst-table-from-yaml-data/options.json @@ -0,0 +1,8 @@ +{ + "to": "rst", + "from": "markdown", + "standalone": true, + "citeproc": false, + "html-math-method": "plain", + "template": "custom.rst" +} diff --git a/wasm/examples/rst-table-from-yaml-data/species.rst b/wasm/examples/rst-table-from-yaml-data/species.rst new file mode 100644 index 000000000..4558c2d7c --- /dev/null +++ b/wasm/examples/rst-table-from-yaml-data/species.rst @@ -0,0 +1,2 @@ +${ it.species_name/uppercase } +*${ it.scientific_name }* diff --git a/wasm/examples/rst-table-from-yaml-data/stdin b/wasm/examples/rst-table-from-yaml-data/stdin new file mode 100644 index 000000000..5a0fe6a9c --- /dev/null +++ b/wasm/examples/rst-table-from-yaml-data/stdin @@ -0,0 +1,721 @@ +--- +# Data from https://www.fishwatch.gov +fish: +- calories: 92 + human_health: + texture: Firm and meaty. + environmental_considerations: + species_name: Shortfin Squid + diseases_in_salmon: + path: | + /profiles/shortfin-squid + habitat_impacts: | + Fishing gears used to harvest shortfin squid have minimal impacts on + habitat. + location: | + - Shortfin squid inhabits the continental shelf and slope waters of + the Northwest Atlantic Ocean, from Newfoundland to the central east + coast of Florida. + - In the northwest Atlantic Ocean, shortfin squid are most often + caught along the continental shelf break in depths between 150 to + 275 meters. + color: | + Raw squid is ivory colored with orange speckling and a brown stripe that + runs down the mantle. Cooked squid is opaque white. + species_aliases: | + [Illex squid](/species-aliases/illex-squid), [Summer + squid](/species-aliases/summer-squid) + image_gallery: + harvest_type: Wild + selenium: 44.8 mcg + management: + scientific_name: Illex illecebrosus + production: + fat_total: 1.38 g + bycatch: | + Regulations are in place to minimize bycatch. + availability: | + Summer and fall. + research: + fishing_rate: | + At recommended level. + sugars_total: | + 0 g + taste: | + Mild, and subtly sweet. + +   + health_benefits: | + Squid are an excellent source of selenium, riboflavin, and vitamin B12. + disease_treatment_and_prevention: + species_illustration_photo: + src: | + https://www.fishwatch.gov/sites/default/files/Squid\_Illex\_NB\_W.png + title: | + Shortfin Squid + alt: | + shortfin squid + saturated_fatty_acids_total: | + 0.358 g + quote: | + U.S. wild-caught shortfin squid is a smart seafood choice because it is + sustainably managed and responsibly harvested under U.S. regulations. + carbohydrate: | + 3.08 g + serving_weight: | + 100 g + ecosystem_services: + source: | + U.S. wild-caught from Maine to North Carolina. + noaa_fisheries_region: | + Greater Atlantic + animal_health: + population_status: | + - According to the latest assessment, shortfin squid is not subject to + overfishing. There is currently not enough information to determine + the population size, so it is unknown. + population: | + The population level is unknown. The species has a lifespan of less than + one year. + protein: | + 15.58 g + environmental_effects: +   + cholesterol: | + 233 mg + displayed_seafood_profile_illustration: + fiber_total_dietary: | + 0 g + sodium: | + 44 mg + feeds: + servings: | + 1 +- calories: 90 + human_health: + texture: The meat is firm and somewhat fibrous. The tail meat is firmer than the + meat from the claws. + environmental_considerations: + species_name: American Lobster + diseases_in_salmon: + path: | + /profiles/american-lobster + habitat_impacts: | + Fishing gears used to harvest American lobster have minimal impacts on + habitat. + location: | + - American lobsters are found in the northwest Atlantic Ocean from + Labrador to Cape Hatteras. They’re most abundant in coastal waters + from Maine through New Jersey, and are also common offshore to + depths of 2,300 feet from Maine through North Carolina. + color: | + The meat is white with red tinges. + species_aliases: | + [Lobster](/species-aliases/lobster) + image_gallery: + - src: | + https://www.fishwatch.gov/sites/default/files/1.JPG + title: | + American Lobster + alt: | + American Lobster + - src: | + https://www.fishwatch.gov/sites/default/files/2\_6.jpg + title: | + American Lobster + alt: | + American Lobster + - src: | + https://www.fishwatch.gov/sites/default/files/3\_5.jpg + title: | + American Lobster + alt: | + American Lobster + - src: | + https://www.fishwatch.gov/sites/default/files/4\_0.png + title: | + American Lobster + alt: | + American Lobster + - src: | + https://www.fishwatch.gov/sites/default/files/5\_3.jpg + title: | + American Lobster + alt: | + American Lobster + harvest_type: Wild + selenium: 41.4 mcg + management: + scientific_name: Homarus americanus + production: + fat_total: 0.9 g + bycatch: | + Regulations are in place to minimize bycatch. + availability: | + Year-round. In New England, where most lobsters are landed, the peak + harvest season extends from May to November. + research: | + - State scientists, in cooperation with the lobster industry, are + conducting projects to assist with the effective management of the + lobster resource. Many states have established [ventless trap + survey](http://www.asmfc.org/fisheries-science/surveys)s to quantify + the abundance of juvenile lobsters. By removing escape vents from + the lobster traps and randomly placing those traps within certain + depth categories and geographic areas, researchers can assess the + abundance of juvenile lobsters and the potential for young lobsters + to reach a size or life stage that can be caught by the fishing gear + (recruitment) in the future. These surveys complement longstanding + fishery-independent bottom trawl surveys conducted by NOAA Fisheries + and the states. Because trawl gear cannot effectively sample rocky + or shallow coastal bottom types, the ventless trap surveys attempt + to fill this data gap by using fixed lobster gear without escape + vents. + fishing_rate: | + At recommended levels. + sugars_total: | + 0 g + taste: | + Mild and sweet. + health_benefits: | + Lobster is low in saturated fat and is a very good source of protein and + selenium. The FDA + [advises](https://www.fda.gov/downloads/food/guidanceregulation/ucm252395.pdf) + consumers to not eat the tomalley, the light-green substance found in + the lobster. + disease_treatment_and_prevention: + species_illustration_photo: + src: | + https://www.fishwatch.gov/sites/default/files/Lobster\_American\_NB\_Web.png + title: | + American Lobster + alt: | + American Lobster + saturated_fatty_acids_total: | + 0.18 g + quote: | + U.S. wild-caught American lobster is a smart seafood choice because it + is sustainably managed and responsibly harvested under U.S. regulations. + carbohydrate: | + 0.5 g + serving_weight: | + 100 g (raw) + ecosystem_services: + source: | + U.S. wild-caught from Maine to North Carolina. + noaa_fisheries_region: | + Greater Atlantic + animal_health: + population_status: | + - According to the [2015 stock + assessment](http://www.asmfc.org/uploads/file/55d61d73AmLobsterStockAssmt_PeerReviewReport_Aug2015_red2.pdf) + conducted by the [Atlantic States Marine Fisheries + Commission](http://www.asmfc.org/) (ASMFC), there is record high + stock abundance and recruitment in the Gulf of Maine and Georges + Bank, and record low abundance and recruitment failure in Southern + New England. The Gulf of Maine and Georges Bank stock is not + overfished. However, the ASMFC considers the Southern New England + stock severely depleted due to environmental factors and fishing + pressure. Neither stock is subject to overfishing. + - Since 2012, [Young of Year + surveys](http://umaine.edu/wahlelab/american-lobster-settlement-index-alsi/american-lobster-settlement-index/) + in the Gulf of Maine and George’s Bank stock have shown consistent + declines, which could indicate future declines in recruitment and + landings. + population: | + Above target population levels in the Gulf of Maine and Georges Bank. + Significantly below target levels in Southern New England. + protein: | + 18.80 g + environmental_effects: + cholesterol: | + 95 mg + displayed_seafood_profile_illustration: + fiber_total_dietary: | + 0 g + sodium: | + 296 mg + feeds: + servings: | + 1 +- calories: 90 + human_health: + texture: Very lean with medium to firm texture and medium sized flakes. + environmental_considerations: + species_name: Yellowtail rockfish + diseases_in_salmon: + path: | + /profiles/yellowtail-rockfish + habitat_impacts: | + Most fishing gear used to harvest yellowtail rockfish rarely contacts + the ocean floor and has minimal impacts on habitat. Area closures and + gear restrictions protect sensitive rocky, cold-water coral and sponge + habitats from bottom trawl gear. + location: | + - Yellowtail rockfish are found along the Pacific coast of North + America and range from Kodiak Island, Alaska to Baja California, + Mexico. + color: | + Meat is glistening bright white with a pinkish sheen. + species_aliases: | + [Yellowtail rockfish](/species-aliases/yellowtail-rockfish), + [Greenie](/species-aliases/greenie), [Yellow sea + perch](/species-aliases/yellow-sea-perch), [Rock + Cod](/species-aliases/rock-cod), [Pacific + Snapper](/species-aliases/pacific-snapper) + image_gallery: + harvest_type: Wild + selenium: 63 mcg + management: + scientific_name: Sebastes flavidus + production: + fat_total: 1.34 g + bycatch: | + Regulations are in place to minimize bycatch of overfished and protected + species. + availability: | + Year-round. + research: | + - NOAA’s [Northwest](https://www.nwfsc.noaa.gov/) and [Alaska](Alaska) + Fisheries Science Centers survey the abundance of yellowtail + rockfish off the West Coast and Alaska. + - Yellowtail rockfish is not typically assessed as part of a + single-species abundance survey. It is more commonly assessed along + with other groundfish. + fishing_rate: | + At recommended levels. + sugars_total: | + 0 + taste: | + Very mild, slightly sweet flavor. + health_benefits: | + Rockfish are high in selenium. + disease_treatment_and_prevention: + species_illustration_photo: + src: | + https://www.fishwatch.gov/sites/default/files/Rockfish\_Yellowtail\_NB\_W.png + title: | + Yellowtail rockfish + alt: | + Yellowtail rockfish + saturated_fatty_acids_total: | + 0.34 g + quote: | + U.S. wild-caught Yellowtail rockfish is a smart seafood choice because + it is sustainably managed and responsibly harvested under U.S. + regulations. + carbohydrate: | + 0 + serving_weight: | + 100 g (raw) + ecosystem_services: + source: | + U.S. wild-caught from Kodiak Island Alaska to Baja California. + noaa_fisheries_region: | + West Coast, Alaska + animal_health: + population_status: | + - According to the [2017 stock + assessment](https://www.pcouncil.org/wp-content/uploads/2018/01/YTRK_2017_Final.pdf), + the northern Pacific coast stock of yellowtail rockfish is not + overfished and not subject to overfishing. + - The yellowtail rockfish stock on the West Coast is part of the + southern Pacific coast minor shelf rockfish complex. The overfished + status of this complex is unknown. The stock complex is not subject + to overfishing based on [2016 catch + data](https://www.nwfsc.noaa.gov/research/divisions/fram/observation/pdf/Groundfish_Mortality_2016.pdf). + population: | + The northern Pacific coast stock is above its target population level. + The southern Pacific coast stock is unknown. + protein: | + 18.36 g + environmental_effects: + cholesterol: | + 50 mg + displayed_seafood_profile_illustration: + fiber_total_dietary: | + 0 + sodium: | + 74 mg + feeds: + servings: | + 1 +- calories: 90 + human_health: + texture: Lean and medium-firm, with a fine flake. + environmental_considerations: + species_name: Bocaccio + diseases_in_salmon: + path: | + /profiles/bocaccio + habitat_impacts: | + Area closures and gear restrictions protect sensitive rocky, cold-water + coral and sponge habitats from bottom trawl gear. + location: | + - Bocaccio are found between Punta Blanca, Baja California, and the + Gulf of Alaska off Krozoff and Kodiak Islands. Within this range, + bocaccio is most common between Oregon and northern Baja California. + - There are two partially isolated populations; one southern + population centered in California, and one northern population + centered in British Columbia.  + color: | + Whole fish should have shiny and bright skin. The raw flesh is white, + but turns opaque white when cooked. + species_aliases: | + [Bocaccio](/species-aliases/bocaccio), [Rock + Salmon](/species-aliases/rock-salmon), [Salmon + Rockfish](/species-aliases/salmon-rockfish), [Pacific Red + Snapper](/species-aliases/pacific-red-snapper), [Pacific + Snapper](/species-aliases/pacific-snapper), [Oregon Red + Snapper](/species-aliases/oregon-red-snapper), [Oregon + Snapper](/species-aliases/oregon-snapper), + [Longjaw](/species-aliases/longjaw), [Merou](/species-aliases/merou), + [Jack](/species-aliases/jack), [Snapper](/species-aliases/snapper), + [Rock Cod](/species-aliases/rock-cod), + [Rockfish](/species-aliases/rockfish) + image_gallery: + harvest_type: Wild + selenium: 63 mcg + management: + scientific_name: Sebastes paucispinis + production: + fat_total: 1.34 g + bycatch: | + Regulations are in place to minimize bycatch. + availability: | + Year-round. + research: | + - [New Fishing Opportunities Emerge from Resurgence of West Coast + Groundfish](https://www.fisheries.noaa.gov/feature-story/new-fishing-opportunities-emerge-resurgence-west-coast-groundfish) + - [Rebuilding success continues for West Coast + groundfish](https://www.westcoast.fisheries.noaa.gov/stories/2017/19_06192017_.html) + - [Threatened Yelloweye and Endangered Bocaccio in Puget Sound/Georgia + Basin](https://www.westcoast.fisheries.noaa.gov/protected_species/rockfish/rockfish_in_puget_sound.html) + fishing_rate: | + At recommended level. + sugars_total: | + 0 + taste: | + Delicate, nutty, sweet flavor. + health_benefits: | + Low in saturated fat and very high in selenium, phosphorus, and + potassium. + disease_treatment_and_prevention: + species_illustration_photo: + src: | + https://www.fishwatch.gov/sites/default/files/Bocaccio\_NB\_W.png + title: | + Bocaccio rockfish. + alt: | + Illustration of a Bocaccio rockfish. + saturated_fatty_acids_total: | + 0.34 g + quote: | + U.S. wild-caught bocaccio is a smart seafood choice because it is + sustainably managed and responsibly harvested under U.S. regulations. + carbohydrate: | + 0 + serving_weight: | + 100 g (raw) + ecosystem_services: + source: | + U.S. wild-caught from California to Alaska. + noaa_fisheries_region: | + West Coast, Alaska + animal_health: + population_status: | + - According to the [2018 stock + assessment](https://www.pcouncil.org/wp-content/uploads/2018/02/FINAL_2017_Bocaccio_Update_Assessment_February_2_2018.pdf), + the bocaccio stock on the southern Pacific coast is not overfished, + and is not subject to overfishing. The stock rebuilt in 2017, faster + than estimated in the rebuilding plan, due in large part to several + strong year classes and an improved understanding of the + productivity of this stock. + - Along the northern Pacific coast, bocaccio is part of the northern + Pacific coast minor shelf rockfish complex and the status of this + complex is unknown. + - In the Gulf of Alaska, bocaccio is part of the other rockfish + complex. + - According to the [2017 stock + assessment](https://www.afsc.noaa.gov/REFM/Docs/2017/GOAorock.pdf), + the status of this complex is unknown. + population: | + Above target population levels. + protein: | + 18.36 g + environmental_effects: + cholesterol: | + 50 mg + displayed_seafood_profile_illustration: + fiber_total_dietary: | + 0 + sodium: | + 74 mg + feeds: + servings: | + 1 +- calories: 110 + human_health: + texture: A lean fish with fine-grained, dense meat. When cooked, the meat is firm + yet flaky and tender. + environmental_considerations: + species_name: Atlantic Halibut + diseases_in_salmon: + path: | + /profiles/atlantic-halibut + habitat_impacts: | + Trawl gear used to harvest Atlantic halibut have minimal or temporary + effects on habitat. Area closures and gear restrictions protect + sensitive habitats from bottom trawl gear. Hook and line gear has little + or no impact on habitat. + location: | + - Atlantic halibut are found from Labrador and Greenland to Iceland, + and from the Barents Sea south to the Bay of Biscay and Virginia. + - In U.S. waters, halibut is most common in the Gulf of Maine. + color: | + Uncooked, white and almost translucent. It should not look dull, + yellowish or dried out. When cooked, the meat is white. + species_aliases: | + [Atlantic halibut](/species-aliases/atlantic-halibut), + [Halibut](/species-aliases/halibut) + image_gallery: + - src: | + https://www.fishwatch.gov/sites/default/files/1%20-%20atl\_halibut\_noa.jpg + title: | + Atlantic halibut face and mouth. Photo credit: NOAA. + alt: | + Picture of an Atlantic halibut face and mouth. + - src: | + https://www.fishwatch.gov/sites/default/files/2%20-%20nefsc.jpg + title: | + Atlantic halibut. Photo credit: NOAA. + alt: | + Picture of Atlantic halibut. + - src: | + https://www.fishwatch.gov/sites/default/files/3%20-%20halibut2\_fullsize.jpg + title: | + Picture of Atlantic halibut. Photo credit: NOAA. + alt: | + Picture of Atlantic halibut. + harvest_type: Wild + selenium: 36.5 mcg + management: + scientific_name: Hippoglossus hippoglossus + production: + fat_total: 2.29 g + bycatch: | + Regulations are in place to minimize bycatch. + availability: | + Year-round. + research: | + - Scientists at NOAA’s [Northeast Fisheries Science + Center](https://www.nefsc.noaa.gov/) conduct research bottom trawl + surveys throughout the Northeast continental shelf every year during + the fall and spring. These surveys collect data on the environment + as well as biological samples from fish caught during research + trawling. The data from these and other sources are used by + scientists in stock assessments to estimate population size and + fishing pressure. + fishing_rate: | + At recommended levels. + sugars_total: | + 0 + taste: | + Halibut has a very mild, sweet taste. + health_benefits: | + Halibut is low in saturated fat and sodium, and is a very good source of + protein, niacin, phosphorus, and selenium. + disease_treatment_and_prevention: + species_illustration_photo: + src: | + https://www.fishwatch.gov/sites/default/files/atlantic-halibut-illustration.png + title: | + Illustration of Atlantic Halibut. + alt: | + Illustration of Atlantic Halibut. + saturated_fatty_acids_total: | + 0.325 g + quote: | + Although populations are well below target levels, U.S. wild-caught + Atlantic halibut is still a smart seafood choice because it is + sustainably managed under a rebuilding plan that allows limited harvest + by U.S. fishermen. + carbohydrate: | + 0 + serving_weight: | + 100 g (raw) + ecosystem_services: + source: | + Wild-caught from Maine to Connecticut. + noaa_fisheries_region: | + Greater Atlantic + animal_health: + population_status: | + - The Atlantic halibut stock is at a very low level. Fishing is still + allowed, but at reduced levels. + - According to the [2012 stock + assessment](https://www.nefsc.noaa.gov/publications/crd/crd1206/), + the Atlantic halibut stock is overfished, but is not subject to + overfishing. The estimated biomass is only 3 percent of its target + level. It will remain in a rebuilding plan for the foreseeable + future. + population: | + Significantly below target population levels. + protein: | + 20.81 g + environmental_effects: + cholesterol: | + 32 mg + displayed_seafood_profile_illustration: + fiber_total_dietary: | + 0 + sodium: | + 54 mg + feeds: + servings: | + 1 +- calories: 90 + human_health: + texture: Firm, coarse flake. + environmental_considerations: + species_name: Shortspine Thornyhead + diseases_in_salmon: + path: | + /profiles/shortspine-thornyhead + habitat_impacts: | + The trawl, longline, and pot gear used to harvest shortspine thornyhead + have minimal or temporary effects on habitat. Area closures and gear + restrictions protect sensitive rocky, cold-water coral, and sponge + habitats from bottom trawl gear. + location: | + - Shortspine thornyhead are found from the Bering Sea to Baja + California, Mexico. + color: | + White. + species_aliases: | + [Thornyhead](/species-aliases/thornyhead), [Idiot + fish](/species-aliases/idiot-fish), [Idiot + cod](/species-aliases/idiot-cod), [Rockfish](/species-aliases/rockfish) + image_gallery: + - src: | + https://www.fishwatch.gov/sites/default/files/1%20photo-west-coast-region-photo-gallery.jpg + title: | + Close-up photo of a shortspine thornyhead. (Photo credit: NOAA) + alt: | + Close-up photo of a shortspine thornyhead. (Photo credit: NOAA) + - src: | + https://www.fishwatch.gov/sites/default/files/2%20basket%20of%20shortspine%20thornyhead.jpg + title: | + Basket of shortspine thornyhead. (Photo credit: NOAA) + alt: | + Basket of shortspine thornyhead. (Photo credit: NOAA) + - src: | + https://www.fishwatch.gov/sites/default/files/3%20graphic%20with%20morphology%20ID\_large.jpg + title: | + Shortspine thornyhead graphic identifying several physical + characteristics, including head spines, pelvic and anal fins. (Photo + credit: NOAA) + alt: | + Shortspine thornyhead graphic identifying several physical + characteristics, including head spines, pelvic and anal fins. (Photo + credit: NOAA) + - src: | + https://www.fishwatch.gov/sites/default/files/4%20Head-on%20view%20of%20shortspine%20thornyhead.jpg + title: | + Head-on view of shortspine thornyhead. (Photo credit: NOAA) + alt: | + Head-on view of shortspine thornyhead. (Photo credit: NOAA) + - src: | + https://www.fishwatch.gov/sites/default/files/5%20shortspine%20thornyhead%20amongst%20its%20habitat.jpg + title: | + Shortspine thornyhead rockfish snuggled amongst a sea star, smaller + brittle stars, and sea cucumbers with white tentacles on a mixed rocky + and mud-covered habitat. (Photo credit: NOAA/OER) + alt: | + Shortspine thornyhead rockfish snuggled amongst a sea star, smaller + brittle stars, and sea cucumbers with white tentacles on a mixed rocky + and mud-covered habitat. (Photo credit: NOAA/OER) + harvest_type: Wild + selenium: 63 mcg + management: + scientific_name: Sebastolobus alascanus + production: + fat_total: 1.34 g + bycatch: | + Regulations are in place to minimize bycatch of overfished and protected + species. + availability: | + Year-round. + research: | + [Tagging study of shortspine thornyhead in + Alaska](http://agris.fao.org/agris-search/search.do?recordID=US201700202112) + confirms that the management range is appropriate. + fishing_rate: | + At recommended levels. + sugars_total: | + 0 + taste: | + Sweet and mild. + health_benefits: | + Rockfish are high in selenium. + disease_treatment_and_prevention: + species_illustration_photo: + src: | + https://www.fishwatch.gov/sites/default/files/shortspine-thornyhead-illustration.png + title: | + Illustration of shortspine thornyhead. + alt: | + Illustration of shortspine thornyhead. + saturated_fatty_acids_total: | + 0.34 g + quote: | + U.S. wild-caught shortspine thornyhead is a smart seafood choice because + it is sustainably managed and responsibly harvested under U.S. + regulations. + carbohydrate: | + 0 + serving_weight: | + 100 g (raw) + ecosystem_services: + source: | + U.S. wild-caught from the Bering Sea to Baja California, Mexico. + noaa_fisheries_region: | + West Coast + animal_health: + population_status: | + - According to the [2013 stock + assessment](https://www.pcouncil.org/wp-content/uploads/Shortspine_2013_Assessment.pdf), + shortspine thornyhead on the Pacific Coast are not overfished and + are not subject to overfishing based on the [2016 catch + data](https://www.nwfsc.noaa.gov/research/divisions/fram/observation/pdf/Groundfish_Mortality_2016.pdf). + - In the Gulf of Alaska, shortspine thornyhead are part of the + thornyhead rockfish complex, which also contains longspine and + broadfin thornyhead. + - According to the [2018 stock + assessment](https://www.fisheries.noaa.gov/resource/data/2018-assessment-thornyhead-stock-complex-gulf-alaska), + the status of this complex is unknown. + - According to the 2017 catch data, the complex was not subject to + overfishing, and the fishery’s total allowable catch has not + been attained since 1995. + - In the Bering Sea and Aleutian Islands, shortspine thornyhead are + part of the other rockfish complex. + - According to the [2018 stock + assessment](https://www.fisheries.noaa.gov/resource/data/2018-assessment-other-rockfish-stock-complex-bering-sea-and-aleutian-islands), + the status of this complex is unknown. + - According to the 2017 catch data, the complex was not subject to + overfishing. + population: | + Above target population levels on the Pacific Coast. + protein: | + 18.36 g + environmental_effects: + cholesterol: | + 50 mg + displayed_seafood_profile_illustration: + fiber_total_dietary: | + 0 + sodium: | + 74 mg + feeds: + servings: | + 1 +... diff --git a/wasm/index.html b/wasm/index.html new file mode 100644 index 000000000..6271605f8 --- /dev/null +++ b/wasm/index.html @@ -0,0 +1,2486 @@ + + + + + + Pandoc in the browser + + + + + +
+

pandoc.wasm

+ Convert documents without leaving the browser +
+ +
+
+ + +
+
+
+ + + + + +
+
+
+
+
+
+
+
+ + +
+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+
📄
+
Drop files here or click to browse
+
Supports: .md, .docx, .html, .tex, .rst, .epub, .odt, and more
+
+ +
+
+ 📄 + {{ name }} + {{ formatFileSize(files[name].size) }} + +
+
+
+ + +
+ +
+ + +
+
+ Additional files (images, includes, etc.) + + + + +
+
+
+ 🖼 + {{ name }} + {{ formatFileSize(file.size) }} + +
+
+
+
+
+ + +
+
+
+ + + + + + + + + + + + + + +
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+

+ Controls how tracked changes and comments in Word documents are handled during conversion. +

+
+ + +
+
+
+
From ({{ inputFormat }})
+
+
+ + +
+
+
+
+
To ({{ effectiveOutputFormat }})
+
+
+ + +
+
+
+
+
+ + +
+
+ + +
+
+ + + + +
+
+
+ +
+
+ + +
+
+ + +
+
+ + + + +
+
+ + + + +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + + + +
+
+ + + +
+
+ 📄 + {{ file.name }} + +
+
+
+
+ + +
+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + + +
+
+ 🎨 + {{ file.name }} + +
+
+
+
+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+ + +
+
+
+ +
+

+ Output will be generated as Typst markup, then compiled to PDF. +

+
+ +
+
+
+ + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
+ +
+
+ + +
+
+
+ + +
+
+
+ + + + +
+
+ + + +
+
+ 🔠 + {{ file.name }} + +
+
+
+
+ + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+ + + + +
+
+ + + + +
+
+ + + +
+
+ 📄 + {{ file.name }} + +
+
+
+
+ + + +
+
+ 📄 + {{ file.name }} + +
+
+
+
+ + + +
+
+ 📄 + {{ file.name }} + +
+
+
+
+ + + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ + + + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + +
+
+
+ + +
+
+ + +
+
+
+
+
+ + +
+
+

Converting...

+
+ + +
+
+
+ + +
+
+
{{ msg.text }}
+
+
{{ outputPreview }}
+
+
+
+ + +
+
+
+

Loading pandoc.wasm...

+
+
+
+ + + + diff --git a/wasm/pandoc.js b/wasm/pandoc.js new file mode 100644 index 000000000..3d3fee96a --- /dev/null +++ b/wasm/pandoc.js @@ -0,0 +1,141 @@ +/* pandoc.js: JavaScript interface to pandoc.wasm. + Copyright (c) 2025 Tweag I/O Limited and John MacFarlane. MIT License. + + Interface: await pandoc(options, stdin, files) + + - options is a JavaScript object representing pandoc options: this should + correspond to the format used in pandoc's default files. + - stdin is a string or nil + - files is a JavaScript object whose keys are filenames and whose values + are the data in the corresponding file, as Blobs. + + The return value is a JavaScript object with 3 properties, stdout, stderr, + and warnings, all strings. warnings is a JSON-encoded version of the warnings + produced by pandoc. If the pandoc process produces an output file, it will be + added to files. +*/ + +import { + WASI, + OpenFile, + File, + ConsoleStdout, + PreopenDirectory, +} from "https://cdn.jsdelivr.net/npm/@bjorn3/browser_wasi_shim@0.3.0/dist/index.js"; + +const args = ["pandoc.wasm", "+RTS", "-H64m", "-RTS"]; +const env = []; +const in_file = new File(new Uint8Array(), { readonly: true }); +const out_file = new File(new Uint8Array(), { readonly: false }); +const err_file = new File(new Uint8Array(), { readonly: false }); +const warnings_file = new File(new Uint8Array(), { readonly: false }); +const fileSystem = new Map(); +const fds = [ + new OpenFile(new File(new Uint8Array(), { readonly: true })), + ConsoleStdout.lineBuffered((msg) => console.log(`[WASI stdout] ${msg}`)), + ConsoleStdout.lineBuffered((msg) => console.warn(`[WASI stderr] ${msg}`)), + new PreopenDirectory("/", fileSystem), +]; +const options = { debug: false }; +const wasi = new WASI(args, env, fds, options); +const { instance } = await WebAssembly.instantiateStreaming( + fetch("./pandoc.wasm?sha1=XX"), + { + wasi_snapshot_preview1: wasi.wasiImport, + } +); + +wasi.initialize(instance); +instance.exports.__wasm_call_ctors(); + +function memory_data_view() { + return new DataView(instance.exports.memory.buffer); +} + +const argc_ptr = instance.exports.malloc(4); +memory_data_view().setUint32(argc_ptr, args.length, true); +const argv = instance.exports.malloc(4 * (args.length + 1)); +for (let i = 0; i < args.length; ++i) { + const arg = instance.exports.malloc(args[i].length + 1); + new TextEncoder().encodeInto( + args[i], + new Uint8Array(instance.exports.memory.buffer, arg, args[i].length) + ); + memory_data_view().setUint8(arg + args[i].length, 0); + memory_data_view().setUint32(argv + 4 * i, arg, true); +} +memory_data_view().setUint32(argv + 4 * args.length, 0, true); +const argv_ptr = instance.exports.malloc(4); +memory_data_view().setUint32(argv_ptr, argv, true); + +instance.exports.hs_init_with_rtsopts(argc_ptr, argv_ptr); + +export async function getExtensionsForFormat(options) { + const opts_str = JSON.stringify(options); + const opts_ptr = instance.exports.malloc(opts_str.length); + new TextEncoder().encodeInto( + opts_str, + new Uint8Array(instance.exports.memory.buffer, opts_ptr, opts_str.length) + ); + // add input files to fileSystem + fileSystem.clear() + const out_file = new File(new Uint8Array(), { readonly: false }); + const err_file = new File(new Uint8Array(), { readonly: false }); + fileSystem.set("stdout", out_file); + fileSystem.set("stderr", err_file); + instance.exports.get_extensions_for_format(opts_ptr, opts_str.length); + + return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(out_file.data)); +} + +export async function pandoc(options, stdin, files) { + const opts_str = JSON.stringify(options); + const opts_ptr = instance.exports.malloc(opts_str.length); + new TextEncoder().encodeInto( + opts_str, + new Uint8Array(instance.exports.memory.buffer, opts_ptr, opts_str.length) + ); + // add input files to fileSystem + fileSystem.clear() + const in_file = new File(new Uint8Array(), { readonly: true }); + const out_file = new File(new Uint8Array(), { readonly: false }); + const err_file = new File(new Uint8Array(), { readonly: false }); + const warnings_file = new File(new Uint8Array(), { readonly: false }); + fileSystem.set("stdin", in_file); + fileSystem.set("stdout", out_file); + fileSystem.set("stderr", err_file); + fileSystem.set("warnings", warnings_file); + for (const file in files) { + await addFile(file, files[file], true); + } + // add output file if any + if (options["output-file"]) { + await addFile(options["output-file"], new Blob(), false); + } + if (stdin) { + in_file.data = new TextEncoder().encode(stdin); + } + instance.exports.wasm_main(opts_ptr, opts_str.length); + + if (options["output-file"]) { + files[options["output-file"]] = + new Blob([fileSystem.get(options["output-file"]).data]); + } + const rawWarnings = new TextDecoder("utf-8", { fatal: true }) + .decode(warnings_file.data); + let warnings = []; + if (rawWarnings) { + warnings = JSON.parse(rawWarnings); + } + return { + stdout: new TextDecoder("utf-8", { fatal: true }).decode(out_file.data), + stderr: new TextDecoder("utf-8", { fatal: true }).decode(err_file.data), + warnings: warnings + }; +} + +async function addFile(filename, blob, readonly) { + const buffer = await blob.arrayBuffer(); + const file = new File(new Uint8Array(buffer), { readonly: readonly }); + fileSystem.set(filename, file); +} -- cgit v1.2.3