package shakuhachi
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
A music collection manager
Install
dune-project
Dependency
Authors
Maintainers
Sources
0.1.0.tar.gz
sha256=bb7f91cc44c09f922d2a614e9e01fd0d2976840bacf839a8b99de63c6fc5b3b8
sha512=f02827db4228b017bb2ad7d64cb1c0667831ec2341e6f759266ec834e40627c2affeace143c6d5e769b3acce63f889b3cbd1a9ca4768091840e8fce1d4750f86
doc/src/shakuhachi.query/parser.ml.html
Source file parser.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156(**********************************************************************************************) (* *) (* This file is part of shakuhachi: a music collection manager *) (* Copyright (C) 2025 Yves Ndiaye *) (* *) (* shakuhachi is free software: you can redistribute it and/or modify it under the terms *) (* of the GNU General Public License as published by the Free Software Foundation, *) (* either version 3 of the License, or (at your option) any later version. *) (* *) (* shakuhachi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; *) (* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *) (* PURPOSE. See the GNU General Public License for more details. *) (* You should have received a copy of the GNU General Public License along with shakuhachi. *) (* If not, see <http://www.gnu.org/licenses/>. *) (* *) (**********************************************************************************************) open Angstrom let is_digit = function '0' .. '9' -> true | _ -> false let number = map ~f:int_of_string (take_while1 is_digit) let number64 = map ~f:Int64.of_string (take_while1 is_digit) let number = choice [ number; map ~f:( ~- ) @@ (char '-' *> number) ] let number64 = choice [ number64; map ~f:Int64.neg @@ (char '-' *> number64) ] let whitespace next = skip_while (function ' ' -> true | _ -> false) *> next let sexp_escape_char = Util.sexp_escape_char let length = choice [ map2 number (char ':' *> number) ~f:(fun min sec -> (min * 60) + sec); number; ] let string_sexp f = let scanner_quoted state = let parser = scan_state (state, String.empty) (fun (state, buffer) c -> match state with | `Escaped -> (* Horrendous but can not use buffer. *) let buffer = Printf.sprintf "%s%c" buffer c in Some (`Unscaped, buffer) | `Unscaped -> ( match c with | '\\' -> Some (`Escaped, buffer) | '"' -> None | _ -> let buffer = Printf.sprintf "%s%c" buffer c in Some (state, buffer) ) ) in map ~f:(fun (_, buffer) -> buffer) parser in let p = choice [ char '"' *> scanner_quoted `Unscaped <* char '"'; Angstrom.take_while (fun c -> not (List.mem c sexp_escape_char)); ] in map p ~f let string_all k = map (take_while (Fun.const true)) ~f:k let sfield_choice ~pstring p i f = p *> char ':' *> choice [ (* [true] for regex, i for case sensibility. *) char ':' *> pstring (fun s -> f true i s); pstring (fun s -> f false i s); ] let sfield_cs ~pstring name f = let name = Printf.sprintf "%%%s" name in sfield_choice ~pstring (string name) false f let sfield_ci ~pstring name f = sfield_choice ~pstring (string name) true f let sfield ~pstring name f = choice [ sfield_cs ~pstring name f; sfield_ci ~pstring name f ] let string_field ~pstring = choice [ sfield ~pstring Keys.title Field.String.title; sfield ~pstring Keys.sort_name Field.String.sort_name; sfield ~pstring Keys.artist Field.String.artist; sfield ~pstring Keys.album Field.String.album; sfield ~pstring Keys.album_artist Field.String.album_artist; sfield ~pstring Keys.composer Field.String.composer; sfield ~pstring Keys.genre Field.String.genre; sfield ~pstring Keys.path Field.String.path; sfield ~pstring Keys.extension Field.String.extension; ] (** Bool *) let bfield name f = string name *> char ':' *> choice [ map (string_ci "true") ~f:(fun _ -> f true); map (string_ci "false") ~f:(fun _ -> f false); map number ~f:(fun n -> f (n <> 0)); ] let flag = bfield Keys.flag Field.Bool.flag let art = bfield Keys.art Field.Bool.art let bool_field = choice [ art; flag ] (* Int *) let range parser = let oparser = option None (map ~f:Option.some parser) in map2 oparser (string ".." *> oparser) ~f:Range.range let field_range name parser k = string name *> char ':' *> map ~f:k (choice [ range parser; map parser ~f:Range.value ]) let int_field = choice [ field_range Keys.id number64 Field.Int.id; field_range Keys.size number64 Field.Int.size; field_range Keys.track number Field.Int.track; field_range Keys.year number Field.Int.year; field_range Keys.disc number Field.Int.disc; field_range Keys.plays number Field.Int.plays; field_range Keys.length length Field.Int.length; field_range Keys.rating number Field.Int.rating; field_range Keys.album_count number Field.Int.album_count; ] (* Float *) let field ~pstring = choice [ map ~f:Field.string (string_field ~pstring); map ~f:Field.int int_field; map ~f:Field.bool bool_field; ] let substring ~pstring = pstring Node.substring let node ~pstring ~substr = choice [ map ~f:Node.field (field ~pstring); substring ~pstring:substr ] let node_cli = node ~pstring:string_all ~substr:string_all let node_sexp = node ~pstring:string_sexp ~substr:string_sexp
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>