source: code/trunk/lib/text.ml@ 74

Last change on this file since 74 was 41, checked in by fox, 2 years ago

In-Reply-To header field. Note extra list.rev in convert

File size: 4.0 KB
Line 
1module String_map = Map.Make (String)
2type t = {
3 id: Id.t;
4 title: string;
5 authors: Person.Set.t;
6 date: Date.t;
7 string_map: string String_map.t;
8 stringset_map: String_set.t String_map.t;
9 body: string;
10 }
11
12let blank ?(id=(Id.generate ())) () = {
13 id;
14 title = "";
15 authors = Person.Set.empty;
16 date = Date.({ created = now (); edited = ""});
17 string_map = String_map.empty;
18 stringset_map = String_map.empty;
19 body = "";
20 }
21
22let compare = Stdlib.compare
23let newest a b = Date.(compare a.date b.date)
24let oldest a b = Date.(compare b.date a.date)
25
26let str key m =
27 try String_map.find (String.lowercase_ascii key) m.string_map
28 with Not_found -> ""
29
30let set key m =
31 try String_map.find (String.lowercase_ascii key) m.stringset_map
32 with Not_found -> String_set.empty
33
34let with_str_set ?(separator=String_set.of_csv_string) m key str =
35 { m with
36 stringset_map = String_map.add (String.lowercase_ascii key) (separator str)
37 m.stringset_map
38 }
39
40let with_kv x (k,v) =
41 let trim = String.trim in
42 match String.lowercase_ascii k with
43 | "body" -> { x with body = String.trim v }
44 | "title"-> { x with title = trim v }
45 | "id" -> (match v with "" -> x | s -> { x with id = s })
46 | "author"
47 | "authors" -> { x with authors = Person.Set.of_string (trim v)}
48 | "date" -> { x with date = Date.{ x.date with created = Date.of_string v }}
49 | "date-edited"-> { x with date = Date.{ x.date with edited = Date.of_string v }}
50 | "licences" | "topics" | "keywords" | "series" as k -> with_str_set x k v
51 | "references" | "in-reply-to" -> with_str_set
52 ~separator:(fun x -> String_set.map
53 (fun x -> String.(sub x 1 (length x-2))) (String_set.of_ssv_string x))
54 x k v
55 | k -> { x with string_map = String_map.add k (trim v) x.string_map }
56
57let kv_of_string line = match Str.(bounded_split (regexp ": *")) line 2 with
58 | [ key; value ] -> Str.(replace_first (regexp "^#\\+") "" key), value
59 | [ key ] -> Str.(replace_first (regexp "^#\\+") "" key), ""
60 | _ -> "",""
61
62let of_header front_matter =
63 let fields = List.map kv_of_string (Str.(split (regexp "\n")) front_matter) in
64 List.fold_left with_kv (blank ~id:Id.nil ()) fields
65
66let front_matter_body_split s =
67 if Str.(string_match (regexp ".*:.*")) s 0
68 then match Str.(bounded_split (regexp "^$")) s 2 with
69 | front::body::[] -> (front, body)
70 | _ -> ("", s)
71 else ("", s)
72
73let of_string s =
74 let front_matter, body = front_matter_body_split s in
75 try
76 let note = { (of_header front_matter) with body } in
77 if note.id <> Id.nil then Ok note else Error "Missing ID header"
78 with _ -> Error ("Failed parsing" ^ s)
79
80let str_set key m = String_set.to_string @@ set key m
81
82let to_string x =
83 let has_len v = String.length v > 0 in
84 let s field value = if has_len value then field ^ ": " ^ value ^ "\n" else "" in
85 let a value = if Person.Set.is_empty value then ""
86 else "Authors: " ^ Person.Set.to_string value ^ "\n" in
87 let d field value = match value with "" -> ""
88 | s -> field ^ ": " ^ Date.rfc_string s ^ "\n" in
89 let rows = [
90 s "ID" x.id;
91 d "Date" x.date.Date.created;
92 d "Edited" x.date.Date.edited;
93 s "Title" x.title;
94 a x.authors;
95 s "Licences" (str_set "licences" x);
96 s "Topics" (str_set "topics" x);
97 s "Keywords" (str_set "keywords" x);
98 s "References"(str_set "references" x); (*todo: add to output <>*)
99 s "In-Reply-To"(str_set "in-reply-to" x);
100 s "Series" (str_set "series" x);
101 s "Abstract" (str "abstract" x);
102 s "Alias" (str "Alias" x)
103 ] in
104 String.concat "" rows ^ "\n" ^ x.body
105
106let string_alias t =
107 let is_reserved = function
108 | '!' | '*' | '\'' | '(' | ')' | ';' | ':' | '@' | '&' | '=' | '+' | '$'
109 | ',' | '/' | '?' | '#' | '[' | ']' | ' ' | '\t' | '\x00' -> true
110 | _ -> false
111 in
112 let b = Buffer.create (String.length t) in
113 let filter char =
114 let open Buffer in
115 if is_reserved char then (try (if nth b (pred (length b)) <> '-' then add_char b '-') with Invalid_argument _ -> prerr_endline "reserved")
116 else add_char b char
117 in
118 String.(iter filter (lowercase_ascii t));
119 Buffer.contents b
120
121let alias t = match str "alias" t with "" -> string_alias t.title | x -> x
122let short_id t = Id.short t.id
Note: See TracBrowser for help on using the repository browser.