1
1
use bstr:: { BStr , BString , ByteSlice } ;
2
2
use std:: borrow:: Cow ;
3
- use std:: path:: PathBuf ;
3
+ use std:: path:: { Path , PathBuf } ;
4
4
5
5
use crate :: entry:: { PathspecMatch , Status } ;
6
6
use crate :: walk:: function:: { can_recurse, emit_entry} ;
@@ -13,7 +13,7 @@ use crate::{entry, walk, Entry};
13
13
/// Git mostly silently ignores IO errors and stops iterating seemingly quietly, while we error loudly.
14
14
#[ allow( clippy:: too_many_arguments) ]
15
15
pub ( super ) fn recursive (
16
- is_top_level : bool ,
16
+ may_collapse : bool ,
17
17
current : & mut PathBuf ,
18
18
current_bstr : & mut BString ,
19
19
current_info : classify:: Outcome ,
@@ -30,7 +30,7 @@ pub(super) fn recursive(
30
30
} ) ?;
31
31
32
32
let mut num_entries = 0 ;
33
- let mark = state. mark ( is_top_level ) ;
33
+ let mark = state. mark ( may_collapse ) ;
34
34
let mut prevent_collapse = false ;
35
35
for entry in entries {
36
36
let entry = entry. map_err ( |err| Error :: DirEntry {
@@ -64,8 +64,18 @@ pub(super) fn recursive(
64
64
) ?;
65
65
66
66
if can_recurse ( current_bstr. as_bstr ( ) , info, opts. for_deletion , delegate) {
67
- let ( action, subdir_prevent_collapse) =
68
- recursive ( false , current, current_bstr, info, ctx, opts, delegate, out, state) ?;
67
+ let subdir_may_collapse = state. may_collapse ( current) ;
68
+ let ( action, subdir_prevent_collapse) = recursive (
69
+ subdir_may_collapse,
70
+ current,
71
+ current_bstr,
72
+ info,
73
+ ctx,
74
+ opts,
75
+ delegate,
76
+ out,
77
+ state,
78
+ ) ?;
69
79
prevent_collapse |= subdir_prevent_collapse;
70
80
if action != Action :: Continue {
71
81
return Ok ( ( action, prevent_collapse) ) ;
@@ -94,10 +104,11 @@ pub(super) fn recursive(
94
104
Ok ( ( res, prevent_collapse) )
95
105
}
96
106
97
- #[ derive( Default ) ]
98
107
pub ( super ) struct State {
99
108
/// The entries to hold back until it's clear what to do with them.
100
109
pub on_hold : Vec < Entry > ,
110
+ /// The path the user is currently in, as seen from the workdir root.
111
+ worktree_relative_current_dir : Option < PathBuf > ,
101
112
}
102
113
103
114
impl State {
@@ -119,17 +130,60 @@ impl State {
119
130
120
131
/// Keep track of state we need to later resolve the state.
121
132
/// Top-level directories are special, as they don't fold.
122
- fn mark ( & self , is_top_level : bool ) -> Mark {
133
+ fn mark ( & self , may_collapse : bool ) -> Mark {
123
134
Mark {
124
135
start_index : self . on_hold . len ( ) ,
125
- is_top_level ,
136
+ may_collapse ,
126
137
}
127
138
}
139
+
140
+ pub ( super ) fn new ( worktree_root : & Path , current_dir : & Path , is_delete_mode : bool ) -> Self {
141
+ dbg ! ( current_dir, worktree_root) ;
142
+ let worktree_relative_current_dir = if is_delete_mode {
143
+ gix_path:: realpath_opts ( worktree_root, current_dir, gix_path:: realpath:: MAX_SYMLINKS )
144
+ . ok ( )
145
+ . and_then ( |real_worktree_root| current_dir. strip_prefix ( real_worktree_root) . ok ( ) . map ( ToOwned :: to_owned) )
146
+ . map ( |relative_cwd| worktree_root. join ( relative_cwd) )
147
+ } else {
148
+ None
149
+ } ;
150
+ Self {
151
+ on_hold : Vec :: new ( ) ,
152
+ worktree_relative_current_dir,
153
+ }
154
+ }
155
+
156
+ /// Returns `true` if the worktree-relative `directory_to_traverse` is not the current working directory.
157
+ /// This is only the case when
158
+ pub ( super ) fn may_collapse ( & self , directory_to_traverse : & Path ) -> bool {
159
+ dbg ! ( self . worktree_relative_current_dir. as_ref( ) , directory_to_traverse) ;
160
+ self . worktree_relative_current_dir
161
+ . as_ref ( )
162
+ . map_or ( true , |cwd| cwd != directory_to_traverse)
163
+ }
164
+
165
+ pub ( super ) fn emit_remaining (
166
+ & mut self ,
167
+ is_top_level : bool ,
168
+ opts : Options ,
169
+ out : & mut walk:: Outcome ,
170
+ delegate : & mut dyn walk:: Delegate ,
171
+ ) {
172
+ if self . on_hold . is_empty ( ) {
173
+ return ;
174
+ }
175
+
176
+ _ = Mark {
177
+ start_index : 0 ,
178
+ may_collapse : is_top_level,
179
+ }
180
+ . emit_all_held ( self , opts, out, delegate) ;
181
+ }
128
182
}
129
183
130
184
struct Mark {
131
185
start_index : usize ,
132
- is_top_level : bool ,
186
+ may_collapse : bool ,
133
187
}
134
188
135
189
impl Mark {
@@ -211,7 +265,7 @@ impl Mark {
211
265
ctx : & mut Context < ' _ > ,
212
266
delegate : & mut dyn walk:: Delegate ,
213
267
) -> Option < Action > {
214
- if self . is_top_level {
268
+ if ! self . may_collapse {
215
269
return None ;
216
270
}
217
271
let ( mut expendable, mut precious, mut untracked, mut entries, mut matching_entries) = ( 0 , 0 , 0 , 0 , 0 ) ;
0 commit comments