You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
90 lines
2.7 KiB
90 lines
2.7 KiB
(*
|
|
* 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! IStd
|
|
|
|
module UnixDiff = struct
|
|
type t = Unchanged | New | Old [@@deriving compare]
|
|
|
|
let equal = [%compare.equal: t]
|
|
|
|
let directive_of_char c =
|
|
match c with
|
|
| 'U' ->
|
|
Unchanged
|
|
| 'N' ->
|
|
New
|
|
| 'O' ->
|
|
Old
|
|
| _ ->
|
|
Logging.die Logging.UserError "Unexpected char in input sequence. Failed parsing"
|
|
|
|
|
|
let process_raw_directives in_str =
|
|
if String.is_empty in_str then [] else String.to_list in_str |> List.map ~f:directive_of_char
|
|
|
|
|
|
let pp fmt d =
|
|
match d with
|
|
| Unchanged ->
|
|
Format.pp_print_char fmt 'U'
|
|
| New ->
|
|
Format.pp_print_char fmt 'N'
|
|
| Old ->
|
|
Format.pp_print_char fmt 'O'
|
|
|
|
|
|
module VISIBLE_FOR_TESTING_DO_NOT_USE_DIRECTLY = struct
|
|
type nonrec t = t = Unchanged | New | Old
|
|
|
|
let equal = equal
|
|
|
|
let process_raw_directives = process_raw_directives
|
|
|
|
let pp = pp
|
|
end
|
|
end
|
|
|
|
let parse_directives directives =
|
|
let rec aux ~d ~lines ~line_ptr ~pred_is_old =
|
|
(* O does not move the line-pointer *)
|
|
(* N moves the line-pointer and marks the line as affected *)
|
|
(* U moves the line-pointer, and marks the line as affected ONLY if it is preceded by O *)
|
|
match d with
|
|
| [] ->
|
|
List.rev lines
|
|
| UnixDiff.Old :: ds ->
|
|
aux ~d:ds ~lines ~line_ptr ~pred_is_old:true
|
|
| UnixDiff.New :: ds ->
|
|
aux ~d:ds ~lines:(line_ptr :: lines) ~line_ptr:(line_ptr + 1) ~pred_is_old:false
|
|
| UnixDiff.Unchanged :: ds ->
|
|
let lines' = if pred_is_old then line_ptr :: lines else lines in
|
|
aux ~d:ds ~lines:lines' ~line_ptr:(line_ptr + 1) ~pred_is_old:false
|
|
in
|
|
if List.is_empty directives then (* handle the case where both files are empty *)
|
|
[]
|
|
else if
|
|
(* handle the case where the new-file is empty *)
|
|
List.for_all ~f:(UnixDiff.equal UnixDiff.Old) directives
|
|
then [1]
|
|
else
|
|
let pred_is_old, directives' =
|
|
match directives with UnixDiff.Old :: ds -> (true, ds) | _ -> (false, directives)
|
|
in
|
|
aux ~d:directives' ~lines:[] ~line_ptr:1 ~pred_is_old
|
|
|
|
|
|
module VISIBLE_FOR_TESTING_DO_NOT_USE_DIRECTLY = struct
|
|
let parse_directives = parse_directives
|
|
end
|
|
|
|
(** Given a difference between two files, return the relevant lines in the new file; a line is
|
|
relevant when a change took place in it, or nearby. To generate a valid input for this
|
|
parser, use unix-diff command with the following formatter arguments:
|
|
diff --unchanged-line-format="U" --old-line-format="O" --new-line-format="N" File1 File2 *)
|
|
let parse_unix_diff str = UnixDiff.process_raw_directives str |> parse_directives
|