@@ -31,6 +31,21 @@ impl Actor for ExcludeAdd {
3131 cwd. as_path ( ) . map ( |p| p. display ( ) . to_string ( ) ) . unwrap_or_default ( )
3232 } ;
3333
34+ // Check if the current folder itself is matched by any of the patterns
35+ // If so, don't apply the filter - we're viewing inside a gitignored directory
36+ if let Some ( _cwd_path) = cwd. as_path ( ) {
37+ // Build a quick GlobSet to test if current folder matches any pattern
38+ let mut test_builder = GlobSetBuilder :: new ( ) ;
39+ for pattern in & opt. patterns {
40+ if pattern. starts_with ( '!' ) {
41+ // Skip negation patterns for this test
42+ continue ;
43+ } else if let Ok ( glob) = Glob :: new ( pattern) {
44+ test_builder. add ( glob) ;
45+ }
46+ }
47+ }
48+
3449 // Get existing patterns from config
3550 let config_patterns = YAZI . files . excludes_for_context ( & cwd_str) ;
3651
@@ -123,8 +138,92 @@ impl Actor for ExcludeAdd {
123138 }
124139 } ;
125140
126- // Apply to CWD
127- if apply ( cx. current_mut ( ) , ignore_filter. clone ( ) ) {
141+ // Apply to CWD and parent
142+ let cwd_changed = apply ( cx. current_mut ( ) , ignore_filter. clone ( ) ) ;
143+
144+ let parent_changed = if let Some ( p) = cx. parent_mut ( ) {
145+ let parent_str = if p. url . is_search ( ) {
146+ "search://**" . to_string ( )
147+ } else {
148+ p. url . as_path ( ) . map ( |p| p. display ( ) . to_string ( ) ) . unwrap_or_default ( )
149+ } ;
150+
151+ let parent_config_patterns = YAZI . files . excludes_for_context ( & parent_str) ;
152+ let mut parent_all_patterns = opt. patterns . clone ( ) ;
153+ parent_all_patterns. extend ( parent_config_patterns) ;
154+
155+ // Compile glob patterns for parent (same as CWD)
156+ let mut parent_ignores_builder = GlobSetBuilder :: new ( ) ;
157+ let mut parent_whitelists_builder = GlobSetBuilder :: new ( ) ;
158+
159+ for pattern in & parent_all_patterns {
160+ if let Some ( negated) = pattern. strip_prefix ( '!' ) {
161+ if let Ok ( glob) = Glob :: new ( negated) {
162+ parent_whitelists_builder. add ( glob) ;
163+ }
164+ } else if let Ok ( glob) = Glob :: new ( pattern) {
165+ parent_ignores_builder. add ( glob) ;
166+ }
167+ }
168+
169+ let parent_ignores = parent_ignores_builder. build ( ) . ok ( ) ;
170+ let parent_whitelists = parent_whitelists_builder. build ( ) . ok ( ) ;
171+
172+ let parent_matcher: Option < Arc < dyn Fn ( & std:: path:: Path ) -> Option < bool > + Send + Sync > > =
173+ if parent_ignores. is_some ( ) || parent_whitelists. is_some ( ) {
174+ let context = parent_str. clone ( ) ;
175+ Some ( Arc :: new ( move |path : & std:: path:: Path | {
176+ // First check config patterns (for user overrides/negation)
177+ if let Some ( result) = YAZI . files . matches_path ( path, & context) {
178+ return Some ( result) ;
179+ }
180+
181+ // For absolute paths, try both the full path and relative components
182+ let paths_to_check: Vec < & std:: path:: Path > = if path. is_absolute ( ) {
183+ let mut paths = vec ! [ path] ;
184+ if let Some ( components) = path. to_str ( ) {
185+ for ( i, _) in components. match_indices ( '/' ) . skip ( 1 ) {
186+ if let Some ( subpath) = components. get ( i + 1 ..) {
187+ paths. push ( std:: path:: Path :: new ( subpath) ) ;
188+ }
189+ }
190+ }
191+ paths
192+ } else {
193+ vec ! [ path]
194+ } ;
195+
196+ // Check whitelist first (negation takes precedence)
197+ if let Some ( ref wl) = parent_whitelists {
198+ for p in & paths_to_check {
199+ if wl. is_match ( p) {
200+ return Some ( false ) ; // Explicitly NOT ignored
201+ }
202+ }
203+ }
204+
205+ // Check ignore patterns
206+ if let Some ( ref ig) = parent_ignores {
207+ for p in & paths_to_check {
208+ if ig. is_match ( p) {
209+ return Some ( true ) ; // Should be ignored
210+ }
211+ }
212+ }
213+
214+ None
215+ } ) )
216+ } else {
217+ None
218+ } ;
219+
220+ let parent_filter = IgnoreFilter :: from_patterns ( parent_matcher) ;
221+ apply ( p, parent_filter)
222+ } else {
223+ false
224+ } ;
225+
226+ if cwd_changed || parent_changed {
128227 act ! ( mgr: hover, cx) ?;
129228 act ! ( mgr: update_paged, cx) ?;
130229 }
@@ -141,23 +240,65 @@ impl Actor for ExcludeAdd {
141240 let mut hovered_all_patterns = opt. patterns ;
142241 hovered_all_patterns. extend ( hovered_config_patterns) ;
143242
243+ // Compile glob patterns for hovered (same as CWD)
244+ let mut hovered_ignores_builder = GlobSetBuilder :: new ( ) ;
245+ let mut hovered_whitelists_builder = GlobSetBuilder :: new ( ) ;
246+
247+ for pattern in & hovered_all_patterns {
248+ if let Some ( negated) = pattern. strip_prefix ( '!' ) {
249+ if let Ok ( glob) = Glob :: new ( negated) {
250+ hovered_whitelists_builder. add ( glob) ;
251+ }
252+ } else if let Ok ( glob) = Glob :: new ( pattern) {
253+ hovered_ignores_builder. add ( glob) ;
254+ }
255+ }
256+
257+ let hovered_ignores = hovered_ignores_builder. build ( ) . ok ( ) ;
258+ let hovered_whitelists = hovered_whitelists_builder. build ( ) . ok ( ) ;
259+
144260 let hovered_matcher: Option < Arc < dyn Fn ( & std:: path:: Path ) -> Option < bool > + Send + Sync > > =
145- if !hovered_all_patterns . is_empty ( ) {
261+ if hovered_ignores . is_some ( ) || hovered_whitelists . is_some ( ) {
146262 let context = hovered_str. clone ( ) ;
147- let patterns = hovered_all_patterns. clone ( ) ;
148263 Some ( Arc :: new ( move |path : & std:: path:: Path | {
264+ // First check config patterns (for user overrides/negation)
149265 if let Some ( result) = YAZI . files . matches_path ( path, & context) {
150266 return Some ( result) ;
151267 }
152- for pattern in & patterns {
153- if let Some ( negated) = pattern. strip_prefix ( '!' ) {
154- if path. to_str ( ) . map_or ( false , |p| p. contains ( negated) ) {
155- return Some ( false ) ;
268+
269+ // For absolute paths, try both the full path and relative components
270+ let paths_to_check: Vec < & std:: path:: Path > = if path. is_absolute ( ) {
271+ let mut paths = vec ! [ path] ;
272+ if let Some ( components) = path. to_str ( ) {
273+ for ( i, _) in components. match_indices ( '/' ) . skip ( 1 ) {
274+ if let Some ( subpath) = components. get ( i + 1 ..) {
275+ paths. push ( std:: path:: Path :: new ( subpath) ) ;
276+ }
277+ }
278+ }
279+ paths
280+ } else {
281+ vec ! [ path]
282+ } ;
283+
284+ // Check whitelist first (negation takes precedence)
285+ if let Some ( ref wl) = hovered_whitelists {
286+ for p in & paths_to_check {
287+ if wl. is_match ( p) {
288+ return Some ( false ) ; // Explicitly NOT ignored
289+ }
290+ }
291+ }
292+
293+ // Check ignore patterns
294+ if let Some ( ref ig) = hovered_ignores {
295+ for p in & paths_to_check {
296+ if ig. is_match ( p) {
297+ return Some ( true ) ; // Should be ignored
156298 }
157- } else if path. to_str ( ) . map_or ( false , |p| p. contains ( pattern) ) {
158- return Some ( true ) ;
159299 }
160300 }
301+
161302 None
162303 } ) )
163304 } else {
0 commit comments