Commits

Anonymous committed 20b3397

Add the possibility to specify custom exporters for source pages

An exporter is a command that takes in input a page with a given
extension, and outputs html to stdout. It is now possible to specify
custom exporters by pages extensions (it can override the builtin
markdown parser).

Two example exporters are provided :

- a simple exporter that outputs input file, useful to embed some html
in the template
- an exporter for .org files, using mlorg
(http://kiwi.iuwt.fr/~asmanur/projets/mlorg/)

  • Participants
  • Parent commits 72c8065

Comments (0)

Files changed (5)

data/config.stone

 (* Advanced configuration variables        ------ *)
 (* You may not need to change them for the moment *)
 
+Exports = [
+  (".embed.html", "cat %{file}%");
+  (".org", "mlorg --set exporters.html.wrap=false --output - --backend html %{file}%")
+]
+
 (* Permissions of the files & directories generated in site/ *)
 DirPerm  = 493 (* 0o755 *)
 FilePerm = 420 (* 0o644 *)
 type config = {
   site_title : string;
   bar_pages : page list;
+  exports : (string * string) list;
   dir_perm : int;
   file_perm : int
 }
     (tuple2_wrappers string_wrappers string_wrappers)
     ~group
     ["Pages"] [] "List of the pages" in
+  let exports = new list_cp
+    (tuple2_wrappers string_wrappers string_wrappers)
+    ~group
+    ["Exports"] [] "Custom exporters (to html) for source files" in
   let dir_perm = new int_cp ~group ["DirPerm"] Params.dir_perm
     "Permission for the created directories" in
   let file_perm = new int_cp ~group ["FilePerm"] Params.file_perm
   group#read filename;
   { site_title = title#get;
     bar_pages = List.map (fun (f, t) -> { file = f; title = t }) pages#get;
+    exports = exports#get;
     dir_perm = dir_perm#get;
     file_perm = file_perm#get
   }
 open Util
 open Params
 
-let bar ?current bar_pages =
+let custom_exporter command = fun file ->
+  let command = Str.global_replace
+    (Str.regexp "%{file}%")
+    (Filename.quote file)
+    command in
+  let cin = Unix.open_process_in command in
+  let output = Buffer.create 800 in
+  (try
+    while true do
+      Buffer.add_string output (input_line cin);
+      Buffer.add_char output '\n'
+    done
+  with End_of_file -> ());
+  ignore (Unix.close_process_in cin);
+  output
+  |> Buffer.contents
+  |> Html.of_string
+
+let markdown_exporter = fun file ->
+  string_dump file
+  |> Markdown_github.of_string
+  |> Markdown.to_html
+
+let targets conf pages =
+  let exports =
+    (List.map (fun (suf, exp) -> (suf, custom_exporter exp)) conf.Conf.exports)
+    @ [ (".md", markdown_exporter);
+        (".markdown", markdown_exporter) ] in
+  List.fold_left (fun targets page ->
+    try
+      let (suf, exp) = List.find ((Filename.check_suffix page) % fst)
+        exports in
+      (page, ((Filename.chop_suffix page suf) ^ ".html", exp))::targets
+    with Not_found -> targets
+  ) [] pages
+
+let bar ?current bar_pages targets =
   let open Conf in
   let maybe_equal opt x = match opt with
     | None -> false
     | Some y -> x = y in
   let item {file = f; title = t} =
-    let path, pref, _, suf = fname_split f in
-    let link = path ^ pref ^ ".html" in
-    if maybe_equal current t then (
+    let link =
+      (try
+        fst (List.assoc f targets)
+       with Not_found -> f) in
+    if maybe_equal current f then (
       <:xml<
         <li class="current"><a href="$str:link$">$str:t$</a></li>
       >> 
-  ) else (
+    ) else (
       <:xml<
         <li><a href="$str:link$">$str:t$</a></li>
       >>
-  )
+    )
   in
   <:xml<
     <div id="bar">
     </div>
   >>
 
-let page folder template conf filename =
+let page folder template conf targets filename =
   let open Conf in
-  let path, prefix, dot, suffix = fname_split filename in
-  let in_file = folder ^ pages ^ filename in 
-  let out_file = ref (folder ^ site ^ path ^ "/" ^ prefix) in
-  mkpath (folder ^ site ^ path) dir_perm;
-  let content = string_dump in_file in
-  let out_str = ref "" in
-  (match suffix with
-  | "md" | "markdown" ->
-    out_file := !out_file ^ ".html";
-    let current =
-      (try let page = (List.find (fun x -> x.file = filename)
-                         conf.bar_pages) in
-           Some page.title
+  let prefix = filename |> Filename.basename |> Filename.chop_extension in
+  let filepath = filename |> Filename.dirname in
+
+  let in_file = folder /^ pages /^ filename in
+  try
+    let (out_file, exporter) = List.assoc filename targets in
+    let out_file = folder /^ site /^ out_file in
+    let out_path = Filename.dirname out_file in
+    mkpath out_path dir_perm;
+
+    let html_content = exporter in_file in
+    let bar_item = 
+      (try let it = (List.find (fun x -> x.file = filename)
+                       conf.bar_pages) in
+           Some it
        with Not_found -> None) in
-    let page_title = match current with
-      | Some t -> t
+    let current = match bar_item with
+      | Some it -> Some it.file
+      | None -> None in
+    let page_title = match bar_item with
+      | Some it -> it.title
       | None -> prefix in
-    let css_path = (gen_backpath (depth path)) ^ static ^ css in
+    let css_path = (gen_backpath (depth filepath)) /^ static /^ css in
     let css = <:xml<<link href=$str:css_path$ type="text/css" rel="stylesheet"/> >> in
-    let html_content = 
-      try Markdown.to_html (Markdown_github.of_string content) with
-        Parsing.Parse_error -> die ("Error : unable to parse " ^ in_file) in
     let html_page = Template.fill template
       conf.site_title page_title
       css
-      (bar ?current conf.bar_pages)
+      (bar ?current conf.bar_pages targets)
       html_content in
-    out_str := (try Html.to_string html_page with
-      Parsing.Parse_error -> die ("Error : unable do generate page " ^ in_file))
+    let out_str = (try Html.to_string html_page with
+      Parsing.Parse_error -> die ("Error : unable to generate page " ^ in_file)) in
+    dump_string conf.file_perm out_file out_str
 
-  | _ -> 
-    out_file := !out_file ^ dot ^ suffix;
-    out_str := content);
-      
-  dump_string conf.file_perm !out_file !out_str
+  with Not_found ->
+    let out_file = folder /^ site /^ filename in
+    copy_bin_file conf.file_perm in_file out_file
     (* Open the template file once *)
     let template_str = string_dump (folder /^ data /^ template) in
 
+    (* Found target name for each page we'll have to generate.
+       The result is an association list. *)
+    let targets = Gen.targets conf all_pages in
+
     (* Generate all the pages in /pages/ and its subdirectories *)
     List.iter (fun page -> 
-      Gen.page folder template_str conf page)
+      Gen.page folder template_str conf targets page)
       all_pages;
 
     (* Copy the stylesheet into site/static/ *)
     String.blit Filename.dir_sep 0 path (back_len * i + parent_len) sep_len;
   done;
   path
-    
-(* Split an absolute filename into three strings :
-   - the path to the file
-   - the prefix of the file (name without extension)
-   - the dot (if present)
-   - the extension (suffix) (if present)
-
-   For example : 
-   "/home/toto/note.txt" -> ("/home/toto", "note", ".", "txt")
-   "/home/toto/bla" -> ("/home/toto", "bla", "", "")
-*)
-let fname_split filename =
-  let path_prefix, dot, suffix =
-    try let n = String.rindex filename '.' in
-        (String.sub filename 0 n,
-         ".",
-         String.sub filename (n+1) (String.length filename - n - 1))
-    with _ -> (filename, "", "") in
-  let path, prefix =
-    try let n = String.rindex path_prefix '/' in
-        (String.sub path_prefix 0 n,
-         String.sub path_prefix (n+1) (String.length path_prefix - n - 1))
-    with _ -> ("", path_prefix) in
-  (path, prefix, dot, suffix)
 
 let (|>) x f = f x
 let (@@) f x = f x