1
1
defmodule Diff.Hex.ChunkExtractor do
2
- @ enforce_keys [ :file_path , :from_line , :lines_to_read , :direction ]
3
- defstruct Enum . map ( @ enforce_keys , & { & 1 , nil } ) ++
4
- [
5
- errors: [ ] ,
6
- raw: nil ,
7
- parsed: nil
8
- ]
2
+ @ enforce_keys [ :file_path , :from_line , :to_line , :right_line ]
3
+ defstruct Enum . map ( @ enforce_keys , & { & 1 , nil } ) ++ [ errors: [ ] , raw: nil , parsed: nil ]
9
4
10
5
def run ( params ) do
11
- __MODULE__
12
- |> struct! ( params )
13
- |> parse_integers ( [ :from_line , :lines_to_read ] )
14
- |> validate_direction ( )
6
+ params
7
+ |> cast ( )
8
+ |> parse_integers ( [ :right_line , :from_line , :to_line ] )
9
+ |> normalize ( [ :from_line , :right_line ] )
10
+ |> validate_to_line ( )
15
11
|> system_read_raw_chunk ( )
16
12
|> parse_chunk ( )
17
- |> remove_trailing_newline ( )
13
+ |> case do
14
+ % { errors: [ ] } = chunk -> { :ok , chunk }
15
+ % { errors: _ } = chunk -> { :error , chunk }
16
+ end
17
+ end
18
+
19
+ defp cast ( params ) do
20
+ struct_keys =
21
+ struct ( __MODULE__ )
22
+ |> Map . from_struct ( )
23
+ |> Enum . map ( fn { key , _val } -> key end )
24
+
25
+ struct! ( __MODULE__ , Map . take ( params , struct_keys ) )
18
26
end
19
27
20
28
defp parse_integers ( chunk , fields ) do
@@ -25,7 +33,7 @@ defmodule Diff.Hex.ChunkExtractor do
25
33
value = chunk |> Map . get ( field ) |> parse_value ( )
26
34
27
35
case value do
28
- :error -> % { chunk | errors: { :parse_integer , "#{ field } must be a number" } }
36
+ :error -> % { chunk | errors: [ { :parse_integer , "#{ field } must be a number" } | chunk . errors ] }
29
37
integer -> Map . put ( chunk , field , integer )
30
38
end
31
39
end
@@ -36,26 +44,39 @@ defmodule Diff.Hex.ChunkExtractor do
36
44
with { int , _ } <- Integer . parse ( number ) , do: int
37
45
end
38
46
39
- defp validate_direction ( % { direction: direction } = chunk ) when direction in [ "up" , "down" ] do
47
+ defp normalize ( % { errors: [ _ | _ ] } = chunk , _ ) , do: chunk
48
+
49
+ defp normalize ( chunk , fields ) do
50
+ Enum . reduce ( fields , chunk , & normalize_field / 2 )
51
+ end
52
+
53
+ defp normalize_field ( field , chunk ) do
54
+ case Map . fetch! ( chunk , field ) do
55
+ value when value > 0 -> chunk
56
+ _ -> Map . put ( chunk , field , 1 )
57
+ end
58
+ end
59
+
60
+ defp validate_to_line ( % { errors: [ _ | _ ] } = chunk ) , do: chunk
61
+
62
+ defp validate_to_line ( % { from_line: from_line , to_line: to_line } = chunk )
63
+ when from_line < to_line do
40
64
chunk
41
65
end
42
66
43
- defp validate_direction ( chunk ) do
44
- error = { :direction , "direction must be either \" up \" or \" down \" " }
67
+ defp validate_to_line ( chunk ) do
68
+ error = { :param , "from_line parameter must be less than to_line " }
45
69
% { chunk | errors: [ error | chunk . errors ] }
46
70
end
47
71
48
72
defp system_read_raw_chunk ( % { errors: [ _ | _ ] } = chunk ) , do: chunk
49
73
50
74
defp system_read_raw_chunk ( chunk ) do
51
- chunk_sh = Application . app_dir ( :diff , [ "priv" , "chunk.sh" ] )
52
-
53
75
path = chunk . file_path
54
76
from_line = to_string ( chunk . from_line )
55
- lines_to_read = to_string ( chunk . lines_to_read )
56
- direction = chunk . direction
77
+ to_line = to_string ( chunk . to_line )
57
78
58
- case System . cmd ( chunk_sh , [ path , from_line , lines_to_read , direction ] , stderr_to_stdout: true ) do
79
+ case System . cmd ( "sed" , [ "-n" , " #{ from_line } , #{ to_line } p" , path ] , stderr_to_stdout: true ) do
59
80
{ raw_chunk , 0 } ->
60
81
% { chunk | raw: raw_chunk }
61
82
@@ -71,42 +92,21 @@ defmodule Diff.Hex.ChunkExtractor do
71
92
parsed =
72
93
chunk . raw
73
94
|> String . split ( "\n " )
74
- |> Enum . map ( fn line -> % { line_text: line } end )
75
-
76
- set_line_numbers ( % { chunk | parsed: parsed } )
95
+ |> remove_trailing_newline ( )
96
+ |> Enum . with_index ( chunk . from_line )
97
+ |> Enum . with_index ( chunk . right_line )
98
+ # prepend line with whitespace to compensate the space introduced by leading + and - in diffs
99
+ |> Enum . map ( fn { { line , from } , to } ->
100
+ % { text: " " <> line , from_line_number: from , to_line_number: to }
101
+ end )
102
+
103
+ % { chunk | parsed: parsed }
77
104
end
78
105
79
- defp set_line_numbers ( % { direction: "down" } = chunk ) do
80
- % { chunk | parsed: parsed_with_line_numbers ( chunk . parsed , chunk . from_line ) }
81
- end
82
-
83
- defp set_line_numbers ( % { direction: "up" } = chunk ) do
84
- offset = chunk . from_line - length ( chunk . parsed ) + 1
85
-
86
- % { chunk | parsed: parsed_with_line_numbers ( chunk . parsed , offset ) }
87
- end
88
-
89
- defp parsed_with_line_numbers ( parsed_chunk , starting_number ) when is_binary ( starting_number ) do
90
- parsed_with_line_numbers ( parsed_chunk , starting_number )
91
- end
92
-
93
- defp parsed_with_line_numbers ( parsed_chunk , starting_number ) do
94
- parsed_chunk
95
- |> Enum . with_index ( starting_number )
96
- |> Enum . map ( fn { line , line_number } -> Map . put_new ( line , :line_number , line_number ) end )
97
- end
98
-
99
- defp remove_trailing_newline ( % { errors: [ _ | _ ] } = chunk ) , do: { :error , chunk }
100
-
101
- defp remove_trailing_newline ( chunk ) do
102
- [ trailing_line | reversed_tail ] = Enum . reverse ( chunk . parsed )
103
-
104
- chunk =
105
- case trailing_line do
106
- % { line_text: "" } -> % { chunk | parsed: Enum . reverse ( reversed_tail ) }
107
- % { line_text: _text } -> chunk
108
- end
109
-
110
- { :ok , chunk }
106
+ defp remove_trailing_newline ( lines ) do
107
+ lines
108
+ |> Enum . reverse ( )
109
+ |> tl ( )
110
+ |> Enum . reverse ( )
111
111
end
112
112
end
0 commit comments