+78 -93 +/-6 browse
1 | diff --git a/dune-project b/dune-project |
2 | index 3adfbb4..5c9ec06 100644 |
3 | --- a/dune-project |
4 | +++ b/dune-project |
5 | @@ -1,28 +1,2 @@ |
6 | (lang dune 2.7) |
7 | - |
8 | (name note) |
9 | - (version 0.0.2) |
10 | - |
11 | - (generate_opam_files true) |
12 | - |
13 | - (source (github kevinschoon/note)) |
14 | - (license AGPL3) |
15 | - (authors "Kevin Schoon <kevinschoon@gmail.com>") |
16 | - (maintainers "Kevin Schoon <kevinschoon@gmail.com>") |
17 | - |
18 | - (package |
19 | - (name note) |
20 | - (synopsis "Note is a simple CLI based note taking program") |
21 | - (description "Note is a simple CLI based note taking program") |
22 | - (depends |
23 | - (base |
24 | - (>= v0.14.0)) |
25 | - (core |
26 | - (>= v0.14.0)) |
27 | - (dune |
28 | - (>= 2.7)) |
29 | - (ezjsonm |
30 | - (>= 1.2.0)) |
31 | - (stdio ( >= v0.14.0)) |
32 | - (yaml |
33 | - (>= 2.1.0)))) |
34 | diff --git a/lib/cmd.ml b/lib/cmd.ml |
35 | index c39a005..a3729b2 100644 |
36 | --- a/lib/cmd.ml |
37 | +++ b/lib/cmd.ml |
38 | @@ -25,15 +25,15 @@ let encode_value value = function |
39 | | Json -> ( |
40 | match value with |
41 | | Config config -> Ezjsonm.to_string (Config.to_json config) |
42 | - | Note note -> Ezjsonm.to_string (Note.to_json ~note) ) |
43 | + | Note note -> Ezjsonm.to_string (Note.to_json note) ) |
44 | | Yaml -> ( |
45 | match value with |
46 | | Config config -> Yaml.to_string_exn (Config.to_json config) |
47 | - | Note note -> Yaml.to_string_exn (Note.to_json ~note) ) |
48 | + | Note note -> Yaml.to_string_exn (Note.to_json note) ) |
49 | | Text -> ( |
50 | match value with |
51 | | Config config -> Config.to_string config |
52 | - | Note note -> Note.to_string ~note ) |
53 | + | Note note -> Note.to_string note ) |
54 | |
55 | let create_note = |
56 | let open Command.Let_syntax in |
57 | @@ -66,13 +66,13 @@ let create_note = |
58 | | Some _ -> |
59 | (* reading from stdin so write directly to note *) |
60 | let content = In_channel.input_all In_channel.stdin in |
61 | - let note = Note.build ~title ~tags ~content in |
62 | + let note = Note.build ~tags ~content title in |
63 | Io.create |
64 | ~callback:(get cfg "on_modification") |
65 | - ~content:(Note.to_string ~note) target_file |
66 | + ~content:(Note.to_string note) target_file |
67 | | None -> |
68 | - let note = Note.build ~title ~tags ~content:"" in |
69 | - let init_content = Note.to_string ~note in |
70 | + let note = Note.build ~tags ~content:"" title in |
71 | + let init_content = Note.to_string note in |
72 | Io.create_on_change |
73 | ~callback:(get cfg "on_modification") |
74 | ~editor:(get_exn cfg "editor") init_content target_file] |
75 | @@ -125,7 +125,7 @@ let list_notes = |
76 | Filename.concat (get_exn cfg "state_dir") (Slug.to_string s)) |
77 | slugs |
78 | in |
79 | - let notes = Note.filter (Note.read_notes ~paths) filters in |
80 | + let notes = Note.filter (Note.read_notes paths) filters in |
81 | List.iter ~f:(fun x -> print_endline (Note.get_title x)) notes] |
82 | |
83 | let cat_note = |
84 | @@ -153,7 +153,7 @@ let cat_note = |
85 | Filename.concat (get_exn cfg "state_dir") (Slug.to_string s)) |
86 | slugs |
87 | in |
88 | - let notes = Note.filter (Note.read_notes ~paths) filters in |
89 | + let notes = Note.filter (Note.read_notes paths) filters in |
90 | List.iter |
91 | ~f:(fun note -> print_endline (encode_value (Note note) encoding)) |
92 | notes] |
93 | @@ -186,7 +186,7 @@ let edit_note = |
94 | slugs |
95 | in |
96 | let notes = |
97 | - Note.filter_with_paths (Note.read_notes_with_paths ~paths) filters |
98 | + Note.filter_with_paths (Note.read_notes_with_paths paths) filters |
99 | in |
100 | match List.length notes with |
101 | | 0 -> failwith "no note found" |
102 | @@ -222,7 +222,7 @@ let delete_note = |
103 | slugs |
104 | in |
105 | let notes = |
106 | - Note.filter_with_paths (Note.read_notes_with_paths ~paths) filters |
107 | + Note.filter_with_paths (Note.read_notes_with_paths paths) filters |
108 | in |
109 | match List.length notes with |
110 | | 0 -> failwith "no note found" |
111 | diff --git a/lib/dune b/lib/dune |
112 | index 59076cc..0c5fa95 100644 |
113 | --- a/lib/dune |
114 | +++ b/lib/dune |
115 | @@ -1,5 +1,5 @@ |
116 | (library |
117 | (name note_lib) |
118 | - (preprocess (pps ppx_jane)) |
119 | - (libraries base core ezjsonm jsonpath stdio yaml) |
120 | - ) |
121 | + (preprocess |
122 | + (pps ppx_jane)) |
123 | + (libraries base core ezjsonm omd stdio yaml)) |
124 | diff --git a/lib/note.ml b/lib/note.ml |
125 | index 287957d..59cd8bd 100644 |
126 | --- a/lib/note.ml |
127 | +++ b/lib/note.ml |
128 | @@ -1,68 +1,73 @@ |
129 | open Core |
130 | open Stdio |
131 | |
132 | - type t = { |
133 | - title : string; |
134 | - tags : string list; |
135 | - content : string; |
136 | - } |
137 | + type t = Ezjsonm.t * Omd.t |
138 | |
139 | - let build ~title ~tags ~content = |
140 | - { title; tags; content} |
141 | + let build ?(tags = []) ?(content = "") title = |
142 | + let frontmatter = |
143 | + Ezjsonm.dict |
144 | + [ ("title", Ezjsonm.string title); ("tags", Ezjsonm.strings tags) ] |
145 | + in |
146 | + (frontmatter, Omd.of_string content) |
147 | |
148 | - let get_title t = t.title |
149 | + let get_title t = |
150 | + match Ezjsonm.find_opt (Ezjsonm.value (fst t)) [ "title" ] with |
151 | + | Some v -> Ezjsonm.get_string v |
152 | + | None -> "" |
153 | |
154 | - let to_json ~note = |
155 | + let get_tags t = |
156 | + match Ezjsonm.find_opt (Ezjsonm.value (fst t)) [ "tags" ] with |
157 | + | Some v -> Ezjsonm.get_strings v |
158 | + | None -> [] |
159 | + |
160 | + let to_json t = |
161 | Ezjsonm.dict |
162 | [ |
163 | - ("title", Ezjsonm.string note.title); |
164 | - ("tags", Ezjsonm.strings note.tags); |
165 | - ("content", Ezjsonm.string note.content); |
166 | + ("frontmatter", Ezjsonm.value (fst t)); |
167 | + ("content", Ezjsonm.string (Omd.to_text (snd t))); |
168 | ] |
169 | |
170 | - let to_string ~note = |
171 | - let dict = |
172 | - Ezjsonm.dict |
173 | - [ |
174 | - ("title", Ezjsonm.string note.title); ("tags", Ezjsonm.strings note.tags); |
175 | - ] |
176 | - in |
177 | - let front_matter = Yaml.to_string_exn dict in |
178 | - String.concat ~sep:"\n" [ "---"; front_matter; "---"; note.content ] |
179 | + let to_string t = |
180 | + let front_matter = Yaml.to_string_exn (Ezjsonm.value (fst t)) in |
181 | + String.concat ~sep:"\n" [ "---"; front_matter; "---"; Omd.to_text (snd t) ] |
182 | |
183 | - let of_string ~data = |
184 | + (*TODO: Change to Option*) |
185 | + let of_string data = |
186 | let indexes = String.substr_index_all ~may_overlap:true ~pattern:"---" data in |
187 | if List.length indexes >= 2 then |
188 | let meta_str = |
189 | String.slice data (List.nth_exn indexes 0 + 3) (List.nth_exn indexes 1) |
190 | in |
191 | - let content = |
192 | - String.slice data (List.nth_exn indexes 1 + 3) (String.length data) |
193 | + let frontmatter : Ezjsonm.t = match (Yaml.of_string_exn meta_str) with |
194 | + | `O v -> `O v |
195 | + | `A v -> `A v |
196 | + | _ -> failwith "frontmatter is a partial fragment, should be either a dictionary or list" |
197 | + in |
198 | + let markdown : Omd.t = |
199 | + Omd.of_string |
200 | + (String.slice data (List.nth_exn indexes 1 + 3) (String.length data)) |
201 | in |
202 | - let value = Yaml.of_string_exn meta_str in |
203 | - let title = Ezjsonm.get_string (Ezjsonm.find value [ "title" ]) in |
204 | - let tags = Ezjsonm.get_strings (Ezjsonm.find value [ "tags" ]) in |
205 | - Some { title; content; tags } |
206 | + Some (frontmatter, markdown) |
207 | else None |
208 | |
209 | - let of_string_exn ~data = |
210 | - let note = of_string ~data in |
211 | + let of_string_exn data = |
212 | + let note = of_string data in |
213 | match note with Some note -> note | None -> failwith "bad note content" |
214 | |
215 | - let read_note ~path = |
216 | + let read_note path = |
217 | let data = In_channel.read_all path in |
218 | - of_string ~data |
219 | + of_string data |
220 | |
221 | - let read_note_exn ~path = |
222 | - let note = read_note ~path in |
223 | + let read_note_exn path = |
224 | + let note = read_note path in |
225 | match note with Some note -> note | None -> failwith "failed to read note" |
226 | |
227 | - let read_notes ~paths = List.map ~f:(fun path -> read_note_exn ~path) paths |
228 | + let read_notes paths = List.map ~f:(fun path -> read_note_exn path) paths |
229 | |
230 | - let read_notes_with_paths ~paths = |
231 | - List.map ~f:(fun path -> (read_note_exn ~path, path)) paths |
232 | + let read_notes_with_paths paths = |
233 | + List.map ~f:(fun path -> (read_note_exn path, path)) paths |
234 | |
235 | - let filter notes filters = |
236 | + let filter (notes : t list) filters = |
237 | if List.length filters = 0 then notes |
238 | (* return everything if there are no filters *) |
239 | else |
240 | @@ -70,14 +75,17 @@ let filter notes filters = |
241 | ~f:(fun accm note -> |
242 | (* first look by name *) |
243 | let matches = |
244 | - List.count ~f:(fun filter -> String.equal note.title filter) filters |
245 | + List.count |
246 | + ~f:(fun filter -> String.equal (get_title note) filter) |
247 | + filters |
248 | in |
249 | if matches > 0 then note :: accm |
250 | else |
251 | (* then compare each tag with each filter *) |
252 | let matches = |
253 | List.count |
254 | - ~f:(fun filter -> List.mem ~equal:String.equal note.tags filter) |
255 | + ~f:(fun filter -> |
256 | + List.mem ~equal:String.equal (get_tags note) filter) |
257 | filters |
258 | in |
259 | if matches > 0 then note :: accm else accm) |
260 | @@ -87,19 +95,21 @@ let filter_with_paths notes filters = |
261 | if List.length filters = 0 then notes |
262 | (* return everything if there are no filters *) |
263 | else |
264 | - List.fold |
265 | - ~init:([] : (t * string) list) |
266 | + List.fold ~init:[] |
267 | ~f:(fun accm (note, path) -> |
268 | (* first look by name *) |
269 | let matches = |
270 | - List.count ~f:(fun filter -> String.equal note.title filter) filters |
271 | + List.count |
272 | + ~f:(fun filter -> String.equal (get_title note) filter) |
273 | + filters |
274 | in |
275 | if matches > 0 then (note, path) :: accm |
276 | else |
277 | (* then compare each tag with each filter *) |
278 | let matches = |
279 | List.count |
280 | - ~f:(fun filter -> List.mem ~equal:String.equal note.tags filter) |
281 | + ~f:(fun filter -> |
282 | + List.mem ~equal:String.equal (get_tags note) filter) |
283 | filters |
284 | in |
285 | if matches > 0 then (note, path) :: accm else accm) |
286 | diff --git a/lib/note.mli b/lib/note.mli |
287 | index 2bac40b..573cdfb 100644 |
288 | --- a/lib/note.mli |
289 | +++ b/lib/note.mli |
290 | @@ -1,31 +1,31 @@ |
291 | type t |
292 | |
293 | - val build : title:string -> tags:string list -> content:string -> t |
294 | + val build : ?tags:string list -> ?content:string -> string -> t |
295 | (** build a new note *) |
296 | |
297 | val get_title : t -> string |
298 | (** access the title of a note *) |
299 | |
300 | - val to_string : note:t -> string |
301 | + val to_string : t -> string |
302 | (** convert a note into a string *) |
303 | |
304 | - val of_string : data:string -> t option |
305 | + val of_string : string -> t option |
306 | (** decode a note from a string *) |
307 | |
308 | - val to_json : note:t -> [>Ezjsonm.t] |
309 | + val to_json : t -> [>Ezjsonm.t] |
310 | |
311 | - val of_string_exn : data:string -> t |
312 | + val of_string_exn : string -> t |
313 | |
314 | - val read_note : path:string -> t option |
315 | + val read_note : string -> t option |
316 | (** read a note from the path *) |
317 | |
318 | - val read_note_exn : path:string -> t |
319 | + val read_note_exn : string -> t |
320 | (** read a note from the path raising an exception on failure *) |
321 | |
322 | - val read_notes : paths:string list -> t list |
323 | + val read_notes : string list -> t list |
324 | (** read all of the note paths raising an exception of any failure *) |
325 | |
326 | - val read_notes_with_paths : paths:string list -> (t * string) list |
327 | + val read_notes_with_paths : string list -> (t * string) list |
328 | (** read all of the note paths returning a tuple of note and it's associated path rasiing an exception on any failure *) |
329 | |
330 | val filter : t list -> string list -> t list |
331 | diff --git a/note.opam b/note.opam |
332 | index 3f4fbb4..9cfd4db 100644 |
333 | --- a/note.opam |
334 | +++ b/note.opam |
335 | @@ -13,6 +13,7 @@ depends: [ |
336 | "core" {>= "v0.14.0"} |
337 | "dune" {>= "2.7" & >= "2.7"} |
338 | "ezjsonm" {>= "1.2.0"} |
339 | + "jsonpath" {>= "0.0.1"} |
340 | "stdio" {>= "v0.14.0"} |
341 | "yaml" {>= "2.1.0"} |
342 | "odoc" {with-doc} |