@@ -5,9 +5,10 @@ use std::{
5
5
} ;
6
6
7
7
use git2:: { Oid , Repository } ;
8
+ use ropey:: Rope ;
8
9
use similar:: DiffTag ;
9
10
10
- use crate :: { LineDiff , LineDiffs , RepoRoot } ;
11
+ use crate :: { rope :: RopeLine , LineDiff , LineDiffs , RepoRoot } ;
11
12
12
13
pub struct Git {
13
14
repo : Repository ,
@@ -17,7 +18,7 @@ pub struct Git {
17
18
18
19
/// A cache mapping absolute file paths to file contents
19
20
/// in the HEAD commit.
20
- head_cache : HashMap < PathBuf , String > ,
21
+ head_cache : HashMap < PathBuf , Rope > ,
21
22
}
22
23
23
24
impl std:: fmt:: Debug for Git {
@@ -54,7 +55,7 @@ impl Git {
54
55
path. strip_prefix ( & self . root ) . ok ( )
55
56
}
56
57
57
- pub fn read_file_from_head ( & mut self , file : & Path ) -> Option < & str > {
58
+ pub fn read_file_from_head ( & mut self , file : & Path ) -> Option < & Rope > {
58
59
let current_head = Self :: head_commit_id ( & self . repo ) ?;
59
60
// TODO: Check cache validity on events like WindowChange
60
61
// instead of on every keypress ? Will require hooks.
@@ -70,30 +71,28 @@ impl Git {
70
71
let blob = object. peel_to_blob ( ) . ok ( ) ?;
71
72
let contents = std:: str:: from_utf8 ( blob. content ( ) ) . ok ( ) ?;
72
73
self . head_cache
73
- . insert ( file. to_path_buf ( ) , contents . to_string ( ) ) ;
74
+ . insert ( file. to_path_buf ( ) , Rope :: from_str ( contents ) ) ;
74
75
}
75
76
76
- self . head_cache . get ( file) . map ( |s| s . as_str ( ) )
77
+ self . head_cache . get ( file)
77
78
}
78
79
79
- pub fn line_diff_with_head ( & mut self , file : & Path , contents : & str ) -> LineDiffs {
80
- let base = match self . read_file_from_head ( file) {
81
- Some ( b ) => b ,
80
+ pub fn line_diff_with_head ( & mut self , file : & Path , contents : & Rope ) -> LineDiffs {
81
+ let old = match self . read_file_from_head ( file) {
82
+ Some ( rope ) => RopeLine :: from_rope ( rope ) ,
82
83
None => return LineDiffs :: new ( ) ,
83
84
} ;
84
- let mut config = similar:: TextDiff :: configure ( ) ;
85
- config. timeout ( std:: time:: Duration :: from_millis ( 250 ) ) ;
85
+ let new = RopeLine :: from_rope ( contents) ;
86
86
87
87
let mut line_diffs: LineDiffs = HashMap :: new ( ) ;
88
-
89
88
let mut mark_lines = |range : Range < usize > , change : LineDiff | {
90
89
for line in range {
91
90
line_diffs. insert ( line, change) ;
92
91
}
93
92
} ;
94
93
95
- let diff = config . diff_lines ( base , contents ) ;
96
- for op in diff. ops ( ) {
94
+ let diff = similar :: capture_diff_slices ( similar :: Algorithm :: Myers , & old , & new ) ;
95
+ for op in diff {
97
96
let ( tag, _, line_range) = op. as_tag_tuple ( ) ;
98
97
let start = line_range. start ;
99
98
match tag {
@@ -173,15 +172,16 @@ mod test {
173
172
exec_git_cmd ( "commit -m message" , git_dir) ;
174
173
175
174
let mut git = Git :: discover_from_path ( & file) . unwrap ( ) ;
175
+ let rope = Rope :: from_str ( contents) ;
176
176
assert_eq ! (
177
- Some ( contents ) ,
177
+ Some ( & rope ) ,
178
178
git. read_file_from_head( & file) ,
179
179
"Wrong blob contents from HEAD on clean index"
180
180
) ;
181
181
182
182
fs:: write ( & file, "new text" ) . expect ( "Could not write to file" ) ;
183
183
assert_eq ! (
184
- Some ( contents ) ,
184
+ Some ( & rope ) ,
185
185
git. read_file_from_head( & file) ,
186
186
"Wrong blob contents from HEAD when index is dirty"
187
187
) ;
0 commit comments