package ocamlformat
Source file Indent.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(**************************************************************************) (* *) (* OCamlFormat *) (* *) (* Copyright (c) Facebook, Inc. and its affiliates. *) (* *) (* This source code is licensed under the MIT license found in *) (* the LICENSE file in the root directory of this source tree. *) (* *) (**************************************************************************) open Migrate_ast module Ocp_indent = struct let run ~source ~in_lines ~on_indent ~init = let config, _, _ = IndentConfig.local_default () in let output : _ IndentPrinter.output = { debug= false ; config ; in_lines ; adaptive= true ; indent_empty= false ; kind= Numeric on_indent } in let stream = Nstream.of_string source in IndentPrinter.proceed output stream IndentBlock.empty init end module Valid_ast = struct let loc_of_line loctree locs line = let rec aux = function | [] -> None | (h : Location.t) :: t -> if h.loc_start.pos_lnum = line then Some h else if h.loc_start.pos_lnum <= line && line <= h.loc_end.pos_lnum then match Loc_tree.children loctree h with | [] -> Some h | children -> Some (Option.value (aux children) ~default:h) else aux t in aux locs let matching_loc locs locs' loc : Location.t = match List.zip locs locs' with | Ok assoc -> ( let equal x y = Location.compare x y = 0 in match List.Assoc.find assoc ~equal loc with | Some loc -> loc | None -> impossible "Cannot find matching location in formatted output." ) | Unequal_lengths -> impossible "Cannot match pre-post formatting locations." let indent_range fragment ~unformatted:(ast, txt_src) ~formatted:(fmted_ast, fmted_src) ~lines ~range = let low, high = Range.get range in let loctree, locs = Loc_tree.of_ast fragment ast in let _, locs' = Loc_tree.of_ast fragment fmted_ast in let indent_line i = match loc_of_line loctree locs i with | Some loc -> ( let fmted_loc = matching_loc locs locs' loc in let fmted_lnum = fmted_loc.loc_start.pos_lnum in match Source.find_first_token_on_line fmted_src fmted_lnum with | Some (_, loc) -> Some (Position.column loc.loc_start) | None -> None ) | None -> None in let rec aux ?prev acc idx_ocpi i = if i > high then (List.rev acc, idx_ocpi) else match match List.nth lines (i - 1) with | Some _ -> ( match indent_line i with | Some indent -> ( match prev with | Some prev_indent when indent = prev_indent -> `Maybe indent | _ -> `Ok indent ) | None -> `Ok 0 ) | None -> `Ok 0 with | `Ok x -> aux ~prev:x (`Ok x :: acc) idx_ocpi (i + 1) | `Maybe x -> aux ~prev:x (`Maybe x :: acc) (i :: idx_ocpi) (i + 1) in let prev = let i = low - 1 in match List.nth lines (i - 1) with | Some _ -> indent_line i | None -> None in let aux_ret, idx_ocpi = aux ?prev [] [] low in let rec on_indent i (aux_ret, res) = match aux_ret with | [] -> impossible "list expected to contain at least a `Maybe item" | `Ok x :: t -> on_indent i (t, x :: res) | `Maybe x :: t -> (t, (if i = 0 then x else i) :: res) in let aux_ret, ret = Ocp_indent.run ~source:txt_src ~init:(aux_ret, []) ~on_indent ~in_lines:(List.mem idx_ocpi ~equal:Int.equal) in List.rev @@ List.fold_left aux_ret ~init:ret ~f:(fun t -> function | `Ok h -> h :: t | `Maybe _ -> impossible "all `Maybe were handled by ocp-indent" ) end module Partial_ast = struct let indent_range ~source ~range = let low, high = Range.get range in List.rev @@ Ocp_indent.run ~source ~init:[] ~in_lines:(fun i -> low <= i && i <= high) ~on_indent:(fun i acc -> i :: acc) end