refactor extract shared list-item classifiers into prose_format

Move unordered_item, ordered_item, and is_boundary_common from prose_markdown.ml and prose_org.ml into prose_format.ml. Both format parsers now delegate to the shared implementations. The Org parser extends is_boundary_common with its definition_item check.

Commit
e12db2a2dcaeb49267d6e99fa1b47bc7425f577b
Author
Claude Sonnet 4 <claude@anthropic.invalid>
Author date
Committer
Marius Peter <dev@marius-peter.com>
Committer date
Changed files
lib/prose/prose_format.ml
index e7a3fe19..e69323ac 100644..100644
@@ -67,6 +67,47 @@
67 67 | line :: rest when close line -> (List.rev collected, rest)
68 68 | line :: rest -> take_until close (line :: collected) rest
69 69
70 Added: (* {1 Shared list-item classifiers} *)
71 Added:
72 Added: (** Recognise an unordered list item ([-], [+], or indented [*]). *)
73 Added: let unordered_item line =
74 Added: let length = String.length line in
75 Added: let trimmed = String.trim line in
76 Added: let tlen = String.length trimmed in
77 Added: if tlen >= 2 && List.mem trimmed.[0] [ '-'; '+' ] && trimmed.[1] = ' ' then
78 Added: Some (String.sub trimmed 2 (tlen - 2) |> String.trim)
79 Added: else if
80 Added: tlen >= 2
81 Added: && trimmed.[0] = '*'
82 Added: && trimmed.[1] = ' '
83 Added: && length > 0
84 Added: && (line.[0] = ' ' || line.[0] = '\t')
85 Added: then Some (String.sub trimmed 2 (tlen - 2) |> String.trim)
86 Added: else None
87 Added:
88 Added: (** Recognise an ordered list item ([1.], [2)], etc.). *)
89 Added: let ordered_item line =
90 Added: let trimmed = String.trim line in
91 Added: let tlen = String.length trimmed in
92 Added: let rec digits i =
93 Added: if i < tlen && trimmed.[i] >= '0' && trimmed.[i] <= '9' then digits (i + 1)
94 Added: else i
95 Added: in
96 Added: let d = digits 0 in
97 Added: if d = 0 || d >= tlen then None
98 Added: else if
99 Added: (trimmed.[d] = '.' || trimmed.[d] = ')')
100 Added: && d + 1 < tlen
101 Added: && trimmed.[d + 1] = ' '
102 Added: then Some (String.sub trimmed (d + 2) (tlen - d - 2) |> String.trim)
103 Added: else None
104 Added:
105 Added: (** True when a line starts a new block (blank, or a list item). *)
106 Added: let is_boundary_common line =
107 Added: String.trim line = ""
108 Added: || Option.is_some (unordered_item line)
109 Added: || Option.is_some (ordered_item line)
110 Added:
70 111 (* {1 Anchor generation} *)
71 112
72 113 let new_anchor () =
lib/prose/prose_markdown.ml
index 44b04bd1..dae81d9a 100644..100644
@@ -26,37 +26,9 @@
26 26 ( level,
27 27 String.sub line (level + 1) (length - level - 1) |> trim_end_hashes )
28 28
29 Removed: let unordered_item line =
30 Removed: let length = String.length line in
31 Removed: let trimmed = String.trim line in
32 Removed: let tlen = String.length trimmed in
33 Removed: if tlen >= 2 && List.mem trimmed.[0] [ '-'; '+' ] && trimmed.[1] = ' ' then
34 Removed: Some (String.sub trimmed 2 (tlen - 2) |> String.trim)
35 Removed: else if
36 Removed: tlen >= 2
37 Removed: && trimmed.[0] = '*'
38 Removed: && trimmed.[1] = ' '
39 Removed: && length > 0
40 Removed: && (line.[0] = ' ' || line.[0] = '\t')
41 Removed: then Some (String.sub trimmed 2 (tlen - 2) |> String.trim)
42 Removed: else None
29 Added: let unordered_item = Prose_format.unordered_item
30 Added: let ordered_item = Prose_format.ordered_item
43 31
44 Removed: let ordered_item line =
45 Removed: let trimmed = String.trim line in
46 Removed: let tlen = String.length trimmed in
47 Removed: let rec digits i =
48 Removed: if i < tlen && trimmed.[i] >= '0' && trimmed.[i] <= '9' then digits (i + 1)
49 Removed: else i
50 Removed: in
51 Removed: let d = digits 0 in
52 Removed: if d = 0 || d >= tlen then None
53 Removed: else if
54 Removed: (trimmed.[d] = '.' || trimmed.[d] = ')')
55 Removed: && d + 1 < tlen
56 Removed: && trimmed.[d + 1] = ' '
57 Removed: then Some (String.sub trimmed (d + 2) (tlen - d - 2) |> String.trim)
58 Removed: else None
59 Removed:
60 32 let fence line =
61 33 let line = String.trim line in
62 34 if String.length line < 3 then None
@@ -72,10 +44,7 @@
72 44
73 45 (* {1 Block parsing} *)
74 46
75 Removed: let is_boundary_common line =
76 Removed: String.trim line = ""
77 Removed: || Option.is_some (unordered_item line)
78 Removed: || Option.is_some (ordered_item line)
47 Added: let is_boundary_common = Prose_format.is_boundary_common
79 48
80 49 let parse_blocks lines =
81 50 let is_boundary line =
lib/prose/prose_org.ml
index 62d63036..4820367c 100644..100644
@@ -96,37 +96,9 @@
96 96 ( min 6 level,
97 97 String.sub line (level + 1) (length - level - 1) |> String.trim )
98 98
99 Removed: let unordered_item line =
100 Removed: let length = String.length line in
101 Removed: let trimmed = String.trim line in
102 Removed: let tlen = String.length trimmed in
103 Removed: if tlen >= 2 && List.mem trimmed.[0] [ '-'; '+' ] && trimmed.[1] = ' ' then
104 Removed: Some (String.sub trimmed 2 (tlen - 2) |> String.trim)
105 Removed: else if
106 Removed: tlen >= 2
107 Removed: && trimmed.[0] = '*'
108 Removed: && trimmed.[1] = ' '
109 Removed: && length > 0
110 Removed: && (line.[0] = ' ' || line.[0] = '\t')
111 Removed: then Some (String.sub trimmed 2 (tlen - 2) |> String.trim)
112 Removed: else None
99 Added: let unordered_item = Prose_format.unordered_item
100 Added: let ordered_item = Prose_format.ordered_item
113 101
114 Removed: let ordered_item line =
115 Removed: let trimmed = String.trim line in
116 Removed: let tlen = String.length trimmed in
117 Removed: let rec digits i =
118 Removed: if i < tlen && trimmed.[i] >= '0' && trimmed.[i] <= '9' then digits (i + 1)
119 Removed: else i
120 Removed: in
121 Removed: let d = digits 0 in
122 Removed: if d = 0 || d >= tlen then None
123 Removed: else if
124 Removed: (trimmed.[d] = '.' || trimmed.[d] = ')')
125 Removed: && d + 1 < tlen
126 Removed: && trimmed.[d + 1] = ' '
127 Removed: then Some (String.sub trimmed (d + 2) (tlen - d - 2) |> String.trim)
128 Removed: else None
129 Removed:
130 102 let definition_item line =
131 103 let trimmed = String.trim line in
132 104 let tlen = String.length trimmed in
@@ -177,10 +149,7 @@
177 149 (* {1 Block parsing} *)
178 150
179 151 let is_boundary_common line =
180 Removed: String.trim line = ""
181 Removed: || Option.is_some (unordered_item line)
182 Removed: || Option.is_some (ordered_item line)
183 Removed: || Option.is_some (definition_item line)
152 Added: Prose_format.is_boundary_common line || Option.is_some (definition_item line)
184 153
185 154 let parse_blocks lines =
186 155 let is_boundary line =