package sexp_diff_kernel

  1. Overview
  2. Docs

Source file display.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
open Core_kernel
module U = Display_util_internal

module Display_options = struct
  module Layout = struct
    type t =
      | Single_column
      | Two_column
    [@@deriving compare, enumerate, sexp_of]
  end

  type t =
    { layout : Layout.t
    ; internal_options : U.Display_options.t
    }
  [@@deriving fields, sexp_of]

  let create ?collapse_threshold ?num_shown layout =
    { internal_options = U.Display_options.create ?collapse_threshold ?num_shown ()
    ; layout
    }
  ;;
end

let hide_message ~num_hidden = sprintf "...%d unchanged lines..." num_hidden
let all_hidden_message = "(no changes)"

let two_column_display_as_list ?display_options diff ~on_full_width_message ~on_line_pair
  =
  let lines = U.hideable_line_pairs ?display_options diff in
  let length ~project =
    List.map lines ~f:(function
      | Hidden num_hidden -> String.length (hide_message ~num_hidden)
      | All_hidden -> String.length all_hidden_message
      | Line_pair x -> U.Line.length (project x))
    |> List.max_elt ~compare:Int.compare
    |> Option.value ~default:0
  in
  let left_length = length ~project:U.Line_pair.fst in
  let right_length = length ~project:U.Line_pair.snd in
  let pad_to_left = left_length + 2 in
  let pad_to_right = right_length in
  let width = pad_to_left + pad_to_right in
  List.map lines ~f:(function
    | Hidden num_hidden -> on_full_width_message (hide_message ~num_hidden) ~width
    | All_hidden -> on_full_width_message all_hidden_message ~width
    | Line_pair line_pair ->
      let left = U.Line_pair.fst line_pair in
      let right = U.Line_pair.snd line_pair in
      let left_padding = String.make (pad_to_left - U.Line.length left) ' ' in
      let right_padding = String.make (pad_to_right - U.Line.length right) ' ' in
      on_line_pair ~left ~right ~left_padding ~right_padding)
;;

let center s ~width =
  let left_spaces = (width - String.length s) / 2 in
  let right_spaces = width - String.length s - left_spaces in
  [ String.make left_spaces ' '; s; String.make right_spaces ' ' ] |> String.concat
;;

let list_max l ~f = List.fold l ~init:0 ~f:(fun best x -> Int.max best (f x))

let display_single_column_as_string_with_custom_formatting
      ?display_options
      diff
      ~green
      ~red
      ~plain
  =
  let lines = U.hideable_line_pairs ?display_options diff in
  let to_text = U.Line.to_text ~green ~plain ~red in
  let width =
    list_max lines ~f:(function
      | All_hidden -> String.length all_hidden_message
      | Hidden num_hidden -> String.length (hide_message ~num_hidden)
      | Line_pair (Same line) -> String.length line.content
      | Line_pair (Different (left, right)) ->
        Int.max (String.length left.content) (String.length right.content))
  in
  List.bind lines ~f:(function
    | All_hidden -> [ all_hidden_message |> center ~width ]
    | Hidden num_hidden -> [ hide_message ~num_hidden |> center ~width ]
    | Line_pair (Same line) -> [ line |> to_text ]
    | Line_pair (Different (left, right)) ->
      [ left |> to_text; right |> to_text ]
      |> List.filter ~f:(String.exists ~f:(Fn.non Char.is_whitespace)))
;;

let display_two_column_as_string_with_custom_formatting
      ?display_options
      diff
      ~green
      ~red
      ~plain
  =
  let on_line_pair ~left ~right ~left_padding ~right_padding =
    [ U.Line.to_text ~green ~red ~plain left
    ; left_padding
    ; U.Line.to_text ~green ~red ~plain right
    ; right_padding
    ]
    |> String.concat
  in
  two_column_display_as_list
    ?display_options
    diff
    ~on_full_width_message:center
    ~on_line_pair
;;

let display_as_string_with_custom_formatting display_options diff ~green ~red ~plain =
  let display =
    match Display_options.layout display_options with
    | Single_column -> display_single_column_as_string_with_custom_formatting
    | Two_column -> display_two_column_as_string_with_custom_formatting
  in
  let display_options = Display_options.internal_options display_options in
  display diff ~display_options ~green ~red ~plain |> String.concat ~sep:"\n"
;;

let display_as_plain_string display_options diff =
  display_as_string_with_custom_formatting
    display_options
    diff
    ~green:(fun x -> "+" ^ x)
    ~red:(fun x -> "-" ^ x)
    ~plain:(fun x -> " " ^ x)
;;

let display_with_ansi_colors display_options diff =
  display_as_string_with_custom_formatting
    display_options
    diff
    ~green:(fun x -> sprintf "\027[32m%s\027[0m" x)
    ~red:(fun x -> sprintf "\027[31m%s\027[0m" x)
    ~plain:Fn.id
;;