Skip to content

silent-brad/orgcaml

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OrgCaml

An OCaml library and CLI tool for parsing Org-mode documents into a typed AST and rendering them to HTML.

Features

  • Headings with TODO/DONE keyword support
  • Inline markup: *bold*, /italic/, ~code~, ===verbatim===
  • Links: [[url][description]] and [[url]] (image URLs render as <img>)
  • Image support: links to .png, .jpg, .svg, etc. auto-render as images
  • Lists: ordered and unordered
  • Source blocks with language annotation
  • Example blocks
  • Quote blocks
  • Tables with optional header rows
  • Horizontal rules
  • Directives: #+TITLE, #+AUTHOR, #+DATE, etc. parsed into document.properties

Quick Start

With Nix (recommended)

Build the CLI:

nix build .#orgcaml-bin
./result/bin/orgcaml-bin document.org

Enter a dev shell:

nix develop
dune build
dune runtest

With opam

opam install angstrom
dune build
dune runtest

CLI Usage

Convert an Org file to an HTML fragment:

orgcaml-bin document.org

Generate a full HTML page with <html>, <head>, and <body> tags:

orgcaml-bin --full-page document.org > output.html

Library Usage

Add orgcaml to your dune dependencies:

(executable
 (name my_app)
 (libraries orgcaml))

Then parse and render:

let () =
  let input = {|
* Hello World

This is *bold* and /italic/ text with a [[https://example.com][link]].

- First item
- Second item

print("hello")
|} in let doc = Orgcaml.Parser.parse input in let html = Orgcaml.Html.render_document doc in print_string html

Accessing Directives

Directives like #+TITLE: are parsed into document.properties:

let () =
  let doc = Orgcaml.Parser.parse "#+TITLE: My Doc\n#+DATE: 2026-04-22\n* Hello" in
  List.iter (fun (key, value) ->
    Printf.printf "%s = %s\n" key value
  ) doc.properties
  (* prints: TITLE = My Doc, DATE = 2026-04-22 *)

Listing Source Block Languages

Orgcaml.Parser.languages returns all languages used in #+BEGIN_SRC blocks:

let () =
  let doc = Orgcaml.Parser.parse input in
  let langs = Orgcaml.Parser.languages doc in
  List.iter print_endline langs

Working with the AST

You can also work with the parsed AST directly for custom processing:

let () =
  let doc = Orgcaml.Parser.parse "* TODO My heading\n\nA paragraph." in
  List.iter (function
    | Orgcaml.Ast.Heading { level; keyword; title } ->
      Printf.printf "H%d (kw=%s): %d inline elements\n"
        level
        (Option.value ~default:"none" keyword)
        (List.length title)
    | Orgcaml.Ast.Paragraph _ -> print_endline "Paragraph"
    | _ -> ()
  ) doc.content

AST Reference

type inline =
  | Text of string
  | Bold of inline list
  | Italic of inline list
  | Code of string
  | Verbatim of string
  | Link of { url : string; desc : inline list option }

type block =
  | Heading of { level : int; keyword : string option; title : inline list }
  | Paragraph of inline list
  | List of list_kind * list_item list
  | Src_block of { language : string option; contents : string }
  | Example_block of string
  | Quote_block of block list
  | Table of { header : inline list list option; rows : inline list list list }
  | Horizontal_rule

type document = { properties : (string * string) list; content : block list }

Nix Flake Outputs

OutputDescription
packages.orgcamlLibrary package (SDK)
packages.orgcaml-binCLI binary
packages.defaultAlias for orgcaml-bin
devShells.defaultDev shell with OCaml 5.3, dune, lsp, utop, odoc
checks.defaultRuns the test suite

Project Structure

orgcaml/
├── lib/
│   ├── ast.ml              # Document AST types
│   ├── inline_parser.ml    # Angstrom-based inline markup parser
│   ├── block_parser.ml     # Line-classification block parser
│   ├── parser.ml           # Top-level parse entry point
│   ├── html.ml             # AST → HTML renderer
│   └── orgcaml.ml          # Public module interface
├── examples/
│   ├── org_to_html.ml      # Org → full HTML page example
│   └── ast_walk.ml         # Parse and inspect the AST
├── bin/
│   └── main.ml             # CLI entry point
├── test/
│   └── test_orgcaml.ml     # Test suite
├── dune-project
├── flake.nix
├── orgcaml.opam            # Generated — library package
└── orgcaml-bin.opam        # Generated — CLI package

License

MIT

About

Org-mode parser and HTML renderer for OCaml

Topics

Resources

License

Stars

Watchers

Forks

Contributors