type t = { meta: Meta.t; body: string; } [@@deriving lens { submodule = true }] let blank ?(uuid=(Meta.Id.generate ())) () = { meta = Meta.blank ~uuid (); body = "" } let title ymd = let mtitle = ymd.meta.Meta.title in if String.length mtitle > 0 then mtitle else let open Omd in try List.find (function H1 _ -> true | _ -> false) (Omd.of_string ymd.body) |> function H1 h -> to_text h | _ -> "" with Not_found -> "" let categorised categs ymd = Meta.CategorySet.categorised categs ymd.meta.Meta.categories let with_kv ymd (k,v) = match k with | "body" -> { ymd with body = String.trim v } | _ -> { ymd with meta = Meta.with_kv ymd.meta (k,v) } let meta_pair_of_string line = match Re.Str.(bounded_split (regexp ": *")) line 2 with | [ key; value ] -> Re.Str.(replace_first (regexp "^#\\+") "" key), value | [ key ] -> Re.Str.(replace_first (regexp "^#\\+") "" key), "" | _ -> prerr_endline line; ("","") let meta_of_string front_matter = let fields = List.map meta_pair_of_string (String.split_on_char '\n' front_matter) in List.fold_left Meta.with_kv (Meta.blank ()) fields exception Syntax_error of string let front_matter_body_split s = if Re.Str.(string_match (regexp ".*:.*")) s 0 then match Re.Str.(bounded_split (regexp "\n\n")) s 2 with | front::body::[] -> (front, body) | _ -> ("", s) else ("", s) let of_string s = let (front_matter, body) = front_matter_body_split s in try let note = { meta = meta_of_string front_matter; body } in { note with meta = { note.meta with title = title note } } with _ -> prerr_endline ("Failed parsing" ^ s); blank () let to_string ymd = Meta.to_string ymd.meta ^ "\n" ^ ymd.body