let main () =   let open Meta_result in   succeedf "mkdir -p %s" configuration#output_directory;   begin match configuration#api_doc_directory with   | Some s -> succeedf "rsync -a %s/ %s/api" s configuration#output_directory   | None -> say "Warning, no API docs"   end;   let menu_md =     sprintf "- [Home](index.html)\n"     :: (List.map configuration#input_files ~f:(fun path ->         match File_kind.identify_file path with         | `Markdown m         | `Ocaml_implementation m ->           let base = Filename.basename m in           let title = configuration#title ~with_prefix:false base in           sprintf "- [%s](%s.html)\n" title base         | other -> ""))     @ [       (match configuration#api_doc_directory with        | Some _ -> sprintf "- [API Documentation](./api/index.html)\n"        | None -> "");       configuration#add_to_menu; ]     |> String.concat ~sep:""   in   let first_pass_result : (unit, _) t =     Markdown.to_html ~configuration menu_md     >>= fun menu ->     Markdown.to_html_and_toc ~configuration (read_file configuration#index_file)     >>= fun (content, toc) ->     let title = configuration#title "Home" in     Template.make_page ~menu ~title ~stylesheets:configuration#stylesheets ~toc content     >>= fun markdown_index ->     write_file (configuration#output_directory // "index.html") ~content:markdown_index;     List.fold ~init:(return ()) configuration#input_files ~f:begin fun prev path ->       prev >>= fun () ->       match File_kind.identify_file path with       | `Markdown m ->         let base = Filename.basename m in         let title = configuration#title base in         Markdown.to_html_and_toc ~configuration (read_file path)         >>= fun (content, toc) ->         Template.make_page ~menu ~title ~stylesheets:configuration#stylesheets ~toc content         >>= fun content ->         write_file (configuration#output_directory // sprintf "%s.html" base) ~content;         return ()       | `Ocaml_implementation impl ->         let base = Filename.basename impl in         let title = configuration#title base in         Ocaml.to_html ~configuration (read_file path)         >>= fun (content, toc) ->         Template.make_page ~title ~menu  ~stylesheets:configuration#stylesheets ~toc content         >>= fun content ->         write_file (configuration#output_directory // sprintf "%s.html" base) ~content;         return ()       | m ->         succeedf "cp %s %s/" (Filename.quote path) configuration#output_directory;         return ()     end   in   List.dedup first_pass_result.more_things_todo |> List.iter ~f:begin function   | `Create_man_page cmd ->     let actual_cmd =       let stripped = String.strip cmd in       List.find_map configuration#command_substitutions ~f:(fun (left, right) ->           match String.(sub stripped ~index:0 ~length:(length left)) with           | Some prefix when prefix = left ->             Some (right                   ^ String.(sub_exn stripped ~index:(length left)                               ~length:(length stripped - length left)))           | _ -> None) |> Option.value ~default:stripped     in     let output_file = configuration#output_directory // Markdown.code_url cmd in     begin try       let bash_cmd =         sprintf "set -o pipefail ; %s=groff | groff -Thtml -mandoc > %s"           actual_cmd output_file in       succeedf "bash -c %s" (Filename.quote bash_cmd)     with     | e ->       ignore (         succeedf "(echo '```' ; %s ; echo '```') > %s" actual_cmd output_file;         Markdown.to_html_and_toc ~configuration (read_file output_file)         >>= fun (content, toc) ->         Markdown.to_html ~configuration menu_md         >>= fun menu ->         Template.make_page ~menu ~title:cmd ~stylesheets:configuration#stylesheets ~toc:"" content         >>= fun content ->         write_file (output_file) ~content;         return ()       );     end;   end;   ()