1
- use crate :: bstr:: { BStr , BString , ByteVec } ;
1
+ use crate :: bstr:: { BStr , BString , ByteSlice , ByteVec } ;
2
2
use crate :: ext:: ObjectIdExt ;
3
3
use crate :: { Repository , Tree } ;
4
4
use git_object:: TreeRefIter ;
5
5
use git_odb:: FindExt ;
6
+ use std:: collections:: VecDeque ;
6
7
7
8
/// The error return by methods on the [diff platform][Platform].
8
9
#[ derive( Debug , thiserror:: Error ) ]
@@ -100,6 +101,7 @@ pub struct Platform<'a, 'repo> {
100
101
#[ derive( Clone , Copy ) ]
101
102
enum Tracking {
102
103
FileName ,
104
+ Path ,
103
105
}
104
106
105
107
/// Configuration
@@ -109,6 +111,14 @@ impl<'a, 'repo> Platform<'a, 'repo> {
109
111
self . tracking = Some ( Tracking :: FileName ) ;
110
112
self
111
113
}
114
+
115
+ /// Keep track of the entire path of a change, relative to the repository.
116
+ ///
117
+ /// This makes the [`location`][Change::location] field usable.
118
+ pub fn track_path ( & mut self ) -> & mut Self {
119
+ self . tracking = Some ( Tracking :: Path ) ;
120
+ self
121
+ }
112
122
}
113
123
114
124
/// Add the item to compare to.
@@ -128,6 +138,7 @@ impl<'a, 'repo> Platform<'a, 'repo> {
128
138
other_repo : other. repo ,
129
139
tracking : self . tracking ,
130
140
location : BString :: default ( ) ,
141
+ path_deque : Default :: default ( ) ,
131
142
visit : for_each,
132
143
err : None ,
133
144
} ;
@@ -149,19 +160,47 @@ struct Delegate<'repo, 'other_repo, VisitFn, E> {
149
160
other_repo : & ' other_repo Repository ,
150
161
tracking : Option < Tracking > ,
151
162
location : BString ,
163
+ path_deque : VecDeque < BString > ,
152
164
visit : VisitFn ,
153
165
err : Option < E > ,
154
166
}
155
167
168
+ impl < A , B > Delegate < ' _ , ' _ , A , B > {
169
+ fn pop_element ( & mut self ) {
170
+ if let Some ( pos) = self . location . rfind_byte ( b'/' ) {
171
+ self . location . resize ( pos, 0 ) ;
172
+ } else {
173
+ self . location . clear ( ) ;
174
+ }
175
+ }
176
+
177
+ fn push_element ( & mut self , name : & BStr ) {
178
+ if !self . location . is_empty ( ) {
179
+ self . location . push ( b'/' ) ;
180
+ }
181
+ self . location . push_str ( name) ;
182
+ }
183
+ }
184
+
156
185
impl < ' repo , ' other_repo , VisitFn , E > git_diff:: tree:: Visit for Delegate < ' repo , ' other_repo , VisitFn , E >
157
186
where
158
187
VisitFn : for < ' delegate > FnMut ( Change < ' delegate , ' repo , ' other_repo > ) -> Result < Action , E > ,
159
188
E : std:: error:: Error + Sync + Send + ' static ,
160
189
{
161
- fn pop_front_tracked_path_and_set_current ( & mut self ) { }
190
+ fn pop_front_tracked_path_and_set_current ( & mut self ) {
191
+ if let Some ( Tracking :: Path ) = self . tracking {
192
+ self . location = self
193
+ . path_deque
194
+ . pop_front ( )
195
+ . expect ( "every call is matched with push_tracked_path_component" ) ;
196
+ }
197
+ }
162
198
163
- fn push_back_tracked_path_component ( & mut self , _component : & BStr ) {
164
- { }
199
+ fn push_back_tracked_path_component ( & mut self , component : & BStr ) {
200
+ if let Some ( Tracking :: Path ) = self . tracking {
201
+ self . push_element ( component) ;
202
+ self . path_deque . push_back ( self . location . clone ( ) ) ;
203
+ }
165
204
}
166
205
167
206
fn push_path_component ( & mut self , component : & BStr ) {
@@ -170,11 +209,18 @@ where
170
209
self . location . clear ( ) ;
171
210
self . location . push_str ( component) ;
172
211
}
212
+ Some ( Tracking :: Path ) => {
213
+ self . push_element ( component) ;
214
+ }
173
215
None => { }
174
216
}
175
217
}
176
218
177
- fn pop_path_component ( & mut self ) { }
219
+ fn pop_path_component ( & mut self ) {
220
+ if let Some ( Tracking :: Path ) = self . tracking {
221
+ self . pop_element ( ) ;
222
+ }
223
+ }
178
224
179
225
fn visit ( & mut self , change : git_diff:: tree:: visit:: Change ) -> git_diff:: tree:: visit:: Action {
180
226
use git_diff:: tree:: visit:: Change :: * ;
0 commit comments