3 Generic functions to build lenses
5 Author: Raphael Pinson <raphink@gmail.com>
8 This file is licensed under the LGPL v2+, like the rest of Augeas.
11 This file provides generic functions to build Augeas lenses
19 (************************************************************************
20 * Group: GENERIC CONSTRUCTIONS
21 ************************************************************************)
23 (************************************************************************
25 * Put a lens inside brackets
28 * l:lens - the left bracket lens
29 * r: lens - the right bracket lens
30 * lns:lens - the lens to put inside brackets
31 ************************************************************************)
32 let brackets (l:lens) (r:lens) (lns:lens) = l . lns . r
35 (************************************************************************
36 * Group: LIST CONSTRUCTIONS
37 ************************************************************************)
39 (************************************************************************
41 * Build a list of identical lenses separated with a given separator
42 * (at least 2 elements)
45 * lns:lens - the lens to repeat in the list
46 * sep:lens - the separator lens, which can be taken from the <Sep> module
47 ************************************************************************)
48 let list (lns:lens) (sep:lens) = lns . ( sep . lns )+
51 (************************************************************************
53 * Same as <list>, but there might be only one element in the list
56 * lns:lens - the lens to repeat in the list
57 * sep:lens - the separator lens, which can be taken from the <Sep> module
58 ************************************************************************)
59 let opt_list (lns:lens) (sep:lens) = lns . ( sep . lns )*
62 (************************************************************************
63 * Group: LABEL OPERATIONS
64 ************************************************************************)
66 (************************************************************************
68 * Replace a pattern with a different label in the tree,
69 * thus emulating a key but allowing to replace the keyword
70 * with a different value than matched
73 * m:regexp - the pattern to match
74 * d:string - the default value when a node in created
75 * l:string - the label to apply for such nodes
76 ************************************************************************)
77 let xchg (m:regexp) (d:string) (l:string) = del m d . label l
79 (************************************************************************
81 * Same as <xchg>, but the pattern is the default string
84 * m:string - the string to replace, also used as default
85 * l:string - the label to apply for such nodes
86 ************************************************************************)
87 let xchgs (m:string) (l:string) = xchg m m l
90 (************************************************************************
91 * Group: SUBNODE CONSTRUCTIONS
92 ************************************************************************)
94 (************************************************************************
95 * View: key_value_line
96 * A subnode with a keyword, a separator and a storing lens,
100 * kw:regexp - the pattern to match as key
101 * sep:lens - the separator lens, which can be taken from the <Sep> module
102 * sto:lens - the storing lens
103 ************************************************************************)
104 let key_value_line (kw:regexp) (sep:lens) (sto:lens) =
105 [ key kw . sep . sto . eol ]
107 (************************************************************************
108 * View: key_value_line_comment
109 * Same as <key_value_line>, but allows to have a comment in the end of a line
113 * kw:regexp - the pattern to match as key
114 * sep:lens - the separator lens, which can be taken from the <Sep> module
115 * sto:lens - the storing lens
116 * comment:lens - the comment lens, which can be taken from <Util>
117 ************************************************************************)
118 let key_value_line_comment (kw:regexp) (sep:lens) (sto:lens) (comment:lens) =
119 [ key kw . sep . sto . (eol|comment) ]
121 (************************************************************************
123 * Same as <key_value_line>, but does not end with an end of line
126 * kw:regexp - the pattern to match as key
127 * sep:lens - the separator lens, which can be taken from the <Sep> module
128 * sto:lens - the storing lens
129 ************************************************************************)
130 let key_value (kw: regexp) (sep:lens) (sto:lens) =
131 [ key kw . sep . sto ]
133 (************************************************************************
136 * Store a key/value pair where key and value are separated by whitespace
137 * and the value goes to the end of the line. Leading and trailing
138 * whitespace is stripped from the value. The end of line is consumed by
142 * kw:regexp - the pattern to match as key
143 ************************************************************************)
144 let key_ws_value (kw:regexp) =
145 key_value_line kw Util.del_ws_spc (store Rx.space_in)
147 (************************************************************************
149 * A simple flag subnode, consisting of a single key
152 * kw:regexp - the pattern to match as key
153 ************************************************************************)
154 let flag (kw:regexp) = [ key kw ]
156 (************************************************************************
158 * A simple flag line, consisting of a single key
161 * kw:regexp - the pattern to match as key
162 ************************************************************************)
163 let flag_line (kw:regexp) = [ key kw . eol ]
166 (************************************************************************
167 * Group: BLOCK CONSTRUCTIONS
168 ************************************************************************)
170 (************************************************************************
171 * View: block_generic
172 * A block enclosed in brackets
175 * entry:lens - the entry to be stored inside the block.
176 * This entry should include <Util.empty>
177 * or its equivalent if necessary.
178 * entry_noindent:lens - the entry to be stored inside the block,
179 * without indentation.
180 * This entry should not include <Util.empty>
181 * entry_noeol:lens - the entry to be stored inside the block,
183 * This entry should not include <Util.empty>
184 * entry_noindent_noeol:lens - the entry to be stored inside the block,
185 * without indentation or eol.
186 * This entry should not include <Util.empty>
187 * comment:lens - the comment lens used in the block
188 * comment_noindent:lens - the comment lens used in the block,
189 * without indentation.
190 * ldelim_re:regexp - regexp for the left delimiter
191 * rdelim_re:regexp - regexp for the right delimiter
192 * ldelim_default:string - default value for the left delimiter
193 * rdelim_default:string - default value for the right delimiter
194 ************************************************************************)
196 (entry:lens) (entry_noindent:lens)
197 (entry_noeol:lens) (entry_noindent_noeol:lens)
198 (comment:lens) (comment_noindent:lens)
199 (ldelim_re:regexp) (rdelim_re:regexp)
200 (ldelim_default:string) (rdelim_default:string) =
201 let block_single = entry_noindent_noeol | comment_noindent
202 in let block_start = entry_noindent | comment_noindent
203 in let block_middle = (entry | comment)*
204 in let block_end = entry_noeol | comment
205 in del ldelim_re ldelim_default
206 . ( ( block_start . block_middle . block_end )
208 . del rdelim_re rdelim_default
210 (************************************************************************
211 * View: block_setdefault
212 * A block enclosed in brackets
215 * entry:lens - the entry to be stored inside the block.
216 * This entry should not include <Util.empty>,
217 * <Util.comment> or <Util.comment_noindent>,
218 * should not be indented or finish with an eol.
219 * ldelim_re:regexp - regexp for the left delimiter
220 * rdelim_re:regexp - regexp for the left delimiter
221 * ldelim_default:string - default value for the left delimiter
222 * rdelim_default:string - default value for the right delimiter
223 ************************************************************************)
224 let block_setdelim (entry:lens)
227 (ldelim_default:string)
228 (rdelim_default:string) =
229 block_generic (Util.empty | Util.indent . entry . eol)
230 (entry . eol) (Util.indent . entry) entry
231 Util.comment Util.comment_noindent
233 ldelim_default rdelim_default
235 (* Variable: block_ldelim_re *)
236 let block_ldelim_re = /[ \t\n]+\{[ \t\n]*/
238 (* Variable: block_rdelim_re *)
239 let block_rdelim_re = /[ \t\n]*\}/
241 (* Variable: block_ldelim_default *)
242 let block_ldelim_default = " {\n"
244 (* Variable: block_rdelim_default *)
245 let block_rdelim_default = "}"
247 (************************************************************************
249 * A block enclosed in brackets
252 * entry:lens - the entry to be stored inside the block.
253 * This entry should not include <Util.empty>,
254 * <Util.comment> or <Util.comment_noindent>,
255 * should not be indented or finish with an eol.
256 ************************************************************************)
257 let block (entry:lens) = block_setdelim entry
258 block_ldelim_re block_rdelim_re
259 block_ldelim_default block_rdelim_default
261 (* Variable: block_ldelim_newlines_re *)
262 let block_ldelim_newlines_re = /[ \t\n]*\{([ \t\n]*\n)?/
264 (* Variable: block_rdelim_newlines_re *)
265 let block_rdelim_newlines_re = /[ \t]*\}/
267 (* Variable: block_ldelim_newlines_default *)
268 let block_ldelim_newlines_default = "\n{\n"
270 (* Variable: block_rdelim_newlines_default *)
271 let block_rdelim_newlines_default = "}"
273 (************************************************************************
274 * View: block_newline
275 * A block enclosed in brackets, with newlines forced
276 * and indentation defaulting to a tab.
279 * entry:lens - the entry to be stored inside the block.
280 * This entry should not include <Util.empty>,
281 * <Util.comment> or <Util.comment_noindent>,
282 * should be indented and finish with an eol.
283 ************************************************************************)
284 let block_newlines (entry:lens) (comment:lens) =
285 del block_ldelim_newlines_re block_ldelim_newlines_default
286 . ((entry | comment) . (Util.empty | entry | comment)*)?
287 . del block_rdelim_newlines_re block_rdelim_newlines_default
289 (************************************************************************
290 * View: block_newlines_spc
291 * A block enclosed in brackets, with newlines forced
292 * and indentation defaulting to a tab. The opening brace
293 * must be preceded by whitespace
296 * entry:lens - the entry to be stored inside the block.
297 * This entry should not include <Util.empty>,
298 * <Util.comment> or <Util.comment_noindent>,
299 * should be indented and finish with an eol.
300 ************************************************************************)
301 let block_newlines_spc (entry:lens) (comment:lens) =
302 del (/[ \t\n]/ . block_ldelim_newlines_re) block_ldelim_newlines_default
303 . ((entry | comment) . (Util.empty | entry | comment)*)?
304 . del block_rdelim_newlines_re block_rdelim_newlines_default
306 (************************************************************************
308 * A named <block> enclosed in brackets
311 * kw:regexp - the regexp for the block name
312 * entry:lens - the entry to be stored inside the block
313 * this entry should not include <Util.empty>
314 ************************************************************************)
315 let named_block (kw:regexp) (entry:lens) = [ key kw . block entry . eol ]
318 (************************************************************************
319 * Group: COMBINATORICS
320 ************************************************************************)
322 (************************************************************************
323 * View: combine_two_ord
324 * Combine two lenses, ensuring first lens is first
327 * a:lens - the first lens
328 * b:lens - the second lens
329 ************************************************************************)
330 let combine_two_ord (a:lens) (b:lens) = a . b
332 (************************************************************************
337 * a:lens - the first lens
338 * b:lens - the second lens
339 ************************************************************************)
340 let combine_two (a:lens) (b:lens) =
341 combine_two_ord a b | combine_two_ord b a
343 (************************************************************************
344 * View: combine_two_opt_ord
345 * Combine two lenses optionally, ensuring first lens is first
346 * (a, and optionally b)
349 * a:lens - the first lens
350 * b:lens - the second lens
351 ************************************************************************)
352 let combine_two_opt_ord (a:lens) (b:lens) = a . b?
354 (************************************************************************
355 * View: combine_two_opt
356 * Combine two lenses optionally
357 * (either a, b, or both, in any order)
360 * a:lens - the first lens
361 * b:lens - the second lens
362 ************************************************************************)
363 let combine_two_opt (a:lens) (b:lens) =
364 combine_two_opt_ord a b | combine_two_opt_ord b a
366 (************************************************************************
367 * View: combine_three_ord
368 * Combine three lenses, ensuring first lens is first
369 * (a followed by either b, c, in any order)
372 * a:lens - the first lens
373 * b:lens - the second lens
374 * c:lens - the third lens
375 ************************************************************************)
376 let combine_three_ord (a:lens) (b:lens) (c:lens) =
377 combine_two_ord a (combine_two b c)
379 (************************************************************************
380 * View: combine_three
381 * Combine three lenses
384 * a:lens - the first lens
385 * b:lens - the second lens
386 * c:lens - the third lens
387 ************************************************************************)
388 let combine_three (a:lens) (b:lens) (c:lens) =
389 combine_three_ord a b c
390 | combine_three_ord b a c
391 | combine_three_ord c b a
394 (************************************************************************
395 * View: combine_three_opt_ord
396 * Combine three lenses optionally, ensuring first lens is first
397 * (a followed by either b, c, or any of them, in any order)
400 * a:lens - the first lens
401 * b:lens - the second lens
402 * c:lens - the third lens
403 ************************************************************************)
404 let combine_three_opt_ord (a:lens) (b:lens) (c:lens) =
405 combine_two_opt_ord a (combine_two_opt b c)
407 (************************************************************************
408 * View: combine_three_opt
409 * Combine three lenses optionally
410 * (either a, b, c, or any of them, in any order)
413 * a:lens - the first lens
414 * b:lens - the second lens
415 * c:lens - the third lens
416 ************************************************************************)
417 let combine_three_opt (a:lens) (b:lens) (c:lens) =
418 combine_three_opt_ord a b c
419 | combine_three_opt_ord b a c
420 | combine_three_opt_ord c b a