Author: Kevin Schoon [kevinschoon@gmail.com]
Hash: 530ff773f52c9074388a58b21da59a13ee2ce225
Timestamp: Thu, 01 Jul 2021 18:19:21 +0000 (3 years ago)

+81 -90 +/-5 browse
re-introduce mli for note lib
1diff --git a/bin/note.ml b/bin/note.ml
2index e88536d..eb988cf 100644
3--- a/bin/note.ml
4+++ b/bin/note.ml
5 @@ -5,16 +5,16 @@ open Note_lib
6
7 let cfg = Config.config_path |> Config.load
8
9- let options : Note.Adapter.options =
10+ let options : Note.options =
11 {
12 state_dir = cfg.state_dir;
13 on_modification = cfg.on_modification;
14 editor = cfg.editor;
15 }
16
17- let get_title (note : Note.note) = note.frontmatter.path
18+ let get_title (note : Note.t) = (note |> Note.frontmatter).path
19
20- let get_tags (note : Note.note) = note.frontmatter.tags
21+ let get_tags (note : Note.t) = (note |> Note.frontmatter).tags
22
23 let to_keys ~kind notes =
24 match kind with
25 @@ -77,7 +77,7 @@ is provided then all notes will be listed.
26 fun () ->
27 let paths = match paths with [] -> [ "/" ] | paths -> paths in
28 paths
29- |> List.map ~f:(fun path -> options |> Note.Adapter.load ~path)
30+ |> List.map ~f:(fun path -> options |> Note.load ~path)
31 |> List.iter ~f:(fun notes ->
32 let note = notes |> Note.fst in
33 note |> Note.to_string |> print_endline)]
34 @@ -105,7 +105,7 @@ on_modification callback will be invoked if the file is committed to disk.
35 | Some _ -> Some (In_channel.stdin |> In_channel.input_all)
36 | None -> None
37 in
38- options |> Note.Adapter.create ~description ~tags ~content ~path]
39+ options |> Note.create ~description ~tags ~content ~path]
40
41 let remove_note =
42 let open Command.Let_syntax in
43 @@ -114,10 +114,12 @@ let remove_note =
44 [%map_open
45 let path = anon ("path" %: name_arg) in
46 fun () ->
47- let message = (Format.sprintf "Are you sure you want to delete note %s?" path) in
48- match options |> Note.Adapter.find ~path with
49+ let message =
50+ Format.sprintf "Are you sure you want to delete note %s?" path
51+ in
52+ match options |> Note.find ~path with
53 | Some _ ->
54- let callback () = options |> Note.Adapter.remove ~path in
55+ let callback () = options |> Note.remove ~path in
56 Util.prompt ~callback message
57 | None -> failwith "not found"]
58
59 @@ -134,7 +136,7 @@ Select a note that matches the filter criteria and open it in your text editor.
60 and _ =
61 flag "description" (optional_with_default "" string) ~doc:"description"
62 in
63- fun () -> options |> Note.Adapter.edit ~path]
64+ fun () -> options |> Note.edit ~path]
65
66 let list_notes =
67 let open Command.Let_syntax in
68 @@ -149,7 +151,7 @@ is provided then all notes will be listed.
69 fun () ->
70 let paths = match paths with [] -> [ "/" ] | paths -> paths in
71 paths
72- |> List.map ~f:(fun path -> options |> Note.Adapter.load ~path)
73+ |> List.map ~f:(fun path -> options |> Note.load ~path)
74 |> List.iter ~f:(fun notes ->
75 notes |> Display.convert_tree |> Display.Hierarchical.to_string
76 |> print_endline)]
77 diff --git a/lib/display.ml b/lib/display.ml
78index 408a575..37f468f 100644
79--- a/lib/display.ml
80+++ b/lib/display.ml
81 @@ -15,7 +15,7 @@ module Tabular = struct
82 | Some entry -> sprintf entry.styles "%s" text
83 | None -> sprintf [ Foreground Default ] "%s" text
84
85- let to_cells ?(paint = false) ~columns ~styles (notes : Note.note list) =
86+ let to_cells ?(paint = false) ~columns ~styles (notes : Note.t list) =
87 let header =
88 List.map
89 ~f:(fun column ->
90 @@ -38,21 +38,21 @@ module Tabular = struct
91 ~f:(fun column ->
92 match column with
93 | `Title ->
94- let text_value = note.frontmatter.path in
95+ let text_value = (note |> Note.frontmatter).path in
96 (text_value, String.length text_value, default_padding)
97 | `Description ->
98 let text_value =
99- match note.frontmatter.description with
100+ match (note |> Note.frontmatter).description with
101 | Some text_value -> text_value
102 | None -> ""
103 in
104 (text_value, String.length text_value, default_padding)
105 | `Tags ->
106 let text_value =
107- String.concat ~sep:"|" note.frontmatter.tags
108+ String.concat ~sep:"|" (note |> Note.frontmatter).tags
109 in
110 let text_length = String.length text_value in
111- let tags = note.frontmatter.tags in
112+ let tags = (note |> Note.frontmatter).tags in
113 let tags =
114 if paint then
115 List.map ~f:(fun tag -> paint_tag styles tag) tags
116 @@ -62,7 +62,7 @@ module Tabular = struct
117 (text_value, text_length, default_padding)
118 | `LineCount ->
119 let count =
120- note.content |> String.split_lines |> List.length
121+ note |> Note.content |> String.split_lines |> List.length
122 in
123 let text_value = count |> Core.sprintf "%d" in
124 (text_value, String.length text_value, default_padding))
125 @@ -185,7 +185,7 @@ end
126
127 let rec convert_tree tree =
128 let (Note.Tree (note, others)) = tree in
129- let title = Filename.basename note.frontmatter.path in
130+ let title = Filename.basename (note |> Note.frontmatter).path in
131 let title = "[" ^ title ^ "]" in
132 Hierarchical.Tree (title, List.map ~f:convert_tree others)
133
134 diff --git a/lib/note.ml b/lib/note.ml
135index ca90229..831ea96 100644
136--- a/lib/note.ml
137+++ b/lib/note.ml
138 @@ -41,9 +41,13 @@ module Frontmatter = struct
139 content |> Ezjsonm.dict
140 end
141
142- type note = { frontmatter : Frontmatter.t; content : string }
143+ type t = { frontmatter : Frontmatter.t; content : string }
144
145- and tree = Tree of (note * tree list)
146+ and tree = Tree of (t * tree list)
147+
148+ let frontmatter note = note.frontmatter
149+
150+ let content note = note.content
151
152 let fst tree =
153 let (Tree (note, _)) = tree in
154 @@ -60,7 +64,7 @@ tags: []
155 # This is a Note!
156 |}
157
158- let rec flatten ~accm tree =
159+ let rec flatten ?(accm = []) tree =
160 let (Tree (note, others)) = tree in
161 List.fold ~init:(note :: accm) ~f:(fun accm note -> flatten ~accm note) others
162
163 @@ -110,7 +114,7 @@ let of_string ?(path = None) content =
164 meta_str |> Yaml.of_string_exn |> Frontmatter.of_json ~path
165 in
166 (* read second half of note as "content" *)
167- let content = String.slice content ((List.nth_exn indexes 1)+3) 0 in
168+ let content = String.slice content (List.nth_exn indexes 1 + 3) 0 in
169 { frontmatter; content }
170 else { frontmatter = Frontmatter.empty; content }
171
172 @@ -227,3 +231,5 @@ module Adapter = struct
173 options.on_modification |> run_or_noop
174 | None -> failwith "not found"
175 end
176+
177+ include Adapter
178 diff --git a/lib/note.mli b/lib/note.mli
179new file mode 100644
180index 0000000..377c501
181--- /dev/null
182+++ b/lib/note.mli
183 @@ -0,0 +1,42 @@
184+ module Frontmatter : sig
185+ type t = { path : string; description : string option; tags : string list }
186+ end
187+
188+ type t
189+
190+ type tree = Tree of (t * tree list)
191+
192+ val fst : tree -> t
193+
194+ type options = {
195+ state_dir : string;
196+ editor : string;
197+ on_modification : string option;
198+ }
199+
200+ val to_string : t -> string
201+
202+ val of_string : ?path:string option -> string -> t
203+
204+ val to_json : t -> Ezjsonm.value
205+
206+ val frontmatter : t -> Frontmatter.t
207+ val content : t -> string
208+
209+ val flatten : ?accm:t list -> tree -> t list
210+
211+ val load : path:string -> options -> tree
212+
213+ val find : path:string -> options -> t option
214+
215+ val create :
216+ ?description:string option ->
217+ ?tags:string list ->
218+ ?content:string option ->
219+ path:string ->
220+ options ->
221+ unit
222+
223+ val remove : path:string -> options -> unit
224+
225+ val edit : path:string -> options -> unit
226 diff --git a/test/note_test.ml b/test/note_test.ml
227index 919e08b..e2d5857 100644
228--- a/test/note_test.ml
229+++ b/test/note_test.ml
230 @@ -10,91 +10,34 @@ description: "baz"
231 ---
232 # Hello World|} in
233 let n1 = n1 |> Note.of_string in
234- Alcotest.(check string) "path" "/fuu" n1.frontmatter.path ;
235- let tag = n1.frontmatter.tags |> List.hd_exn in
236+ Alcotest.(check string) "path" "/fuu" (n1 |> Note.frontmatter).path ;
237+ let tag = (n1 |> Note.frontmatter).tags |> List.hd_exn in
238 Alcotest.(check string) "tag" "bar" tag ;
239- let description = (Option.value_exn n1.frontmatter.description) in
240+ let description = (Option.value_exn (n1 |> Note.frontmatter).description) in
241 Alcotest.(check string) "description" "baz" description ;
242- let content = n1.content in
243+ let content = (n1 |> Note.content) in
244 Alcotest.(check string) "content" "\n# Hello World" content
245
246
247- let load_manifest () =
248- let state_dir = Filename.temp_dir "note-test" "" in
249- let manifest = Manifest.load_or_init state_dir in
250- let note_root =
251- Note.of_string
252- {|
253- ---
254- path: "/"
255- description: "all notes desend from here"
256- tags: []
257- ---
258- # Root Note
259- |}
260- in
261- let note_0 =
262- Note.of_string
263- {|
264- ---
265- path: "/note-0"
266- description: "this is a note"
267- tags: ["fuu", "bar"]
268- ---
269- |}
270- in
271- let note_1 =
272- Note.of_string
273- {|
274- ---
275- path: "/note-0/note-1"
276- description: "this is another note"
277- tags: ["baz", "qux"]
278- ---
279- |}
280- in
281- let manifest = manifest |> Manifest.create ~path:"/" in
282- let item = manifest.items |> List.hd_exn in
283- let slug = item.slug |> Slug.to_string in
284- Out_channel.write_all ~data:(note_root |> Note.to_string) slug;
285- let manifest = manifest |> Manifest.create ~path:"/note-0" in
286- let item = manifest.items |> List.hd_exn in
287- let slug = item.slug |> Slug.to_string in
288- Out_channel.write_all ~data:(note_0 |> Note.to_string) slug;
289- manifest |> Manifest.save;
290- let manifest = manifest |> Manifest.create ~path:"/note-0/note-1" in
291- let item = manifest.items |> List.hd_exn in
292- let slug = item.slug |> Slug.to_string in
293- Out_channel.write_all ~data:(note_1 |> Note.to_string) slug;
294- manifest |> Manifest.save;
295- let manifest = Manifest.load_or_init state_dir in
296- let root =
297- Note.Tree
298- ( Note.of_string ~path:(Some "/") Note.root_template,
299- Note.resolve_manifest ~path:"/" manifest )
300- in
301- let (Note.Tree (_, others)) = root in
302- Alcotest.(check int) "one" 1 (others |> List.length)
303-
304 let adapter () =
305- let options : Note.Adapter.options =
306+ let options : Note.options =
307 {
308 state_dir = Filename.temp_dir "note-test" "";
309 editor = "true";
310 on_modification = None;
311 }
312 in
313- let tree = options |> Note.Adapter.load ~path:"/" in
314+ let tree = options |> Note.load ~path:"/" in
315 Alcotest.(check int)
316 "initialized" 1
317 (tree |> Note.flatten ~accm:[] |> List.length);
318- options |> Note.Adapter.create ~content:(Some "bar") ~path:"/fuu";
319- let tree = options |> Note.Adapter.load ~path:"/" in
320+ options |> Note.create ~content:(Some "bar") ~path:"/fuu";
321+ let tree = options |> Note.load ~path:"/" in
322 Alcotest.(check int)
323 "note added" 2
324 (tree |> Note.flatten ~accm:[] |> List.length);
325- options |> Note.Adapter.remove ~path:"/fuu";
326- let tree = options |> Note.Adapter.load ~path:"/" in
327+ options |> Note.remove ~path:"/fuu";
328+ let tree = options |> Note.load ~path:"/" in
329 Alcotest.(check int)
330 "note removed" 1
331 (tree |> Note.flatten ~accm:[] |> List.length)
332 @@ -103,7 +46,5 @@ let () =
333 Alcotest.run "Note"
334 [
335 ("parse", [ Alcotest.test_case "parse" `Quick parsing ]);
336- ( "load_manifest",
337- [ Alcotest.test_case "load manifest" `Quick load_manifest ] );
338 ("adapter", [ Alcotest.test_case "adapter" `Quick adapter ]);
339 ]