commit 8ee072f7d5cf41c5e75b2f50870dfba241436077 Author: Reynir Björnsson Date: Tue Sep 24 11:58:17 2024 +0200 Initial commit diff --git a/bin/dune b/bin/dune new file mode 100644 index 0000000..6447bea --- /dev/null +++ b/bin/dune @@ -0,0 +1,4 @@ +(executable + (public_name kortfat) + (name main) + (libraries kortfat cmarkit)) diff --git a/bin/main.ml b/bin/main.ml new file mode 100644 index 0000000..fca6979 --- /dev/null +++ b/bin/main.ml @@ -0,0 +1,19 @@ +let read_markdown file = + let s = + let ic = open_in file in + (* XXX: probably doesn't work on Windows *) + let len = In_channel.length ic |> Int64.to_int in + Fun.protect (fun () -> really_input_string ic len) + ~finally:(fun () -> close_in ic) + in + Cmarkit.Doc.of_string ~file s + +let kortfat files = + let mds = List.map read_markdown files in + let doc = Kortfat.kortfat mds in + Cmarkit_commonmark.of_doc doc + |> print_endline + +let () = + let files = List.tl (Array.to_list Sys.argv) in + kortfat files diff --git a/dune-project b/dune-project new file mode 100644 index 0000000..f8a936b --- /dev/null +++ b/dune-project @@ -0,0 +1,26 @@ +(lang dune 3.16) + +(name kortfat) + +(generate_opam_files true) + +(source + (github username/reponame)) + +(authors "Author Name") + +(maintainers "Maintainer Name") + +(license LICENSE) + +(documentation https://url/to/documentation) + +(package + (name kortfat) + (synopsis "A short synopsis") + (description "A longer description") + (depends ocaml dune cmarkit) + (tags + (topics "to describe" your project))) + +; See the complete stanza docs at https://dune.readthedocs.io/en/stable/reference/dune-project/index.html diff --git a/kortfat.opam b/kortfat.opam new file mode 100644 index 0000000..e266be4 --- /dev/null +++ b/kortfat.opam @@ -0,0 +1,32 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: "A short synopsis" +description: "A longer description" +maintainer: ["Maintainer Name"] +authors: ["Author Name"] +license: "LICENSE" +tags: ["topics" "to describe" "your" "project"] +homepage: "https://github.com/username/reponame" +doc: "https://url/to/documentation" +bug-reports: "https://github.com/username/reponame/issues" +depends: [ + "ocaml" + "dune" {>= "3.16"} + "cmarkit" + "odoc" {with-doc} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +dev-repo: "git+https://github.com/username/reponame.git" diff --git a/lib/dune b/lib/dune new file mode 100644 index 0000000..2b0ee4f --- /dev/null +++ b/lib/dune @@ -0,0 +1,3 @@ +(library + (name kortfat) + (libraries cmarkit)) diff --git a/lib/kortfat.ml b/lib/kortfat.ml new file mode 100644 index 0000000..698a777 --- /dev/null +++ b/lib/kortfat.ml @@ -0,0 +1,72 @@ +module SM = Map.Make(String) + +let heading_to_string heading = + Cmarkit.Block.Heading.inline heading + |> Cmarkit.Inline.to_plain_text ~break_on_soft:false + |> List.map (String.concat "") + |> String.concat "\n" + +let aggregate t doc = + let rec aggregate t heading = function + | [] -> t + | Cmarkit.Block.Heading (heading, _) :: rest -> + let heading = heading_to_string heading in + let t = + SM.update heading + (function + | None -> Some [] + | Some blocks -> Some blocks) + t + in + aggregate t heading rest + | block :: rest -> + let t = + SM.update heading + (function + | None -> + Some [ block ] + | Some blocks -> + Some (block :: blocks)) + t + in + aggregate t heading rest + in + match Cmarkit.Doc.block doc with + | Cmarkit.Block.Blocks (blocks, _) -> + aggregate t "" blocks + | Cmarkit.Block.Heading (heading, _) -> + let heading = heading_to_string heading in + SM.update heading + (function + | None -> Some [] + | Some blocks -> Some blocks) + t + | block -> + SM.update "" + (function + | None -> + Some [ block ] + | Some blocks -> + Some (block :: blocks)) + t + +let kortfat docs = + let rev_t = List.fold_left aggregate SM.empty docs in + let t = SM.map List.rev rev_t in + let blocks = + SM.fold + (fun heading blocks acc -> + let heading = + Cmarkit.Block.Heading + (Cmarkit.Block.Heading.make + ~level:2 + (Cmarkit.Inline.Text + (heading, Cmarkit.Meta.none)), + Cmarkit.Meta.none) + in + heading :: blocks @ acc) + t + [] + in + Cmarkit.Block.Blocks (blocks, Cmarkit.Meta.none) + |> Cmarkit.Doc.make