1
+ use std:: collections:: BTreeMap ;
2
+ use std:: path:: { Path , PathBuf } ;
3
+ use std:: sync:: Arc ;
4
+
5
+ use ignore:: { WalkBuilder , WalkState } ;
6
+
1
7
use ruff_linter:: {
2
8
display_settings, fs:: normalize_path_to, settings:: types:: FilePattern ,
3
9
settings:: types:: PreviewMode ,
@@ -8,12 +14,6 @@ use ruff_workspace::{
8
14
pyproject:: { find_user_settings_toml, settings_toml} ,
9
15
resolver:: { ConfigurationTransformer , Relativity } ,
10
16
} ;
11
- use std:: {
12
- collections:: BTreeMap ,
13
- path:: { Path , PathBuf } ,
14
- sync:: Arc ,
15
- } ;
16
- use walkdir:: WalkDir ;
17
17
18
18
use crate :: session:: settings:: { ConfigurationPreference , ResolvedEditorSettings } ;
19
19
@@ -30,7 +30,7 @@ pub struct RuffSettings {
30
30
}
31
31
32
32
pub ( super ) struct RuffSettingsIndex {
33
- /// Index from folder to the resoled ruff settings.
33
+ /// Index from folder to the resolved ruff settings.
34
34
index : BTreeMap < PathBuf , Arc < RuffSettings > > ,
35
35
fallback : Arc < RuffSettings > ,
36
36
}
@@ -126,70 +126,88 @@ impl RuffSettingsIndex {
126
126
}
127
127
128
128
// Add any settings within the workspace itself
129
- let mut walker = WalkDir :: new ( root) . into_iter ( ) ;
130
-
131
- while let Some ( entry) = walker. next ( ) {
132
- let Ok ( entry) = entry else {
133
- continue ;
134
- } ;
135
-
136
- // Skip non-directories.
137
- if !entry. file_type ( ) . is_dir ( ) {
138
- continue ;
139
- }
140
-
141
- let directory = entry. into_path ( ) ;
129
+ let mut builder = WalkBuilder :: new ( root) ;
130
+ builder. standard_filters ( true ) ;
131
+ builder. hidden ( false ) ;
132
+ builder. threads (
133
+ std:: thread:: available_parallelism ( )
134
+ . map_or ( 1 , std:: num:: NonZeroUsize :: get)
135
+ . min ( 12 ) ,
136
+ ) ;
137
+ let walker = builder. build_parallel ( ) ;
138
+
139
+ let index = std:: sync:: RwLock :: new ( index) ;
140
+ walker. run ( || {
141
+ Box :: new ( |result| {
142
+ let Ok ( entry) = result else {
143
+ return WalkState :: Continue ;
144
+ } ;
142
145
143
- // If the directory is excluded from the workspace, skip it.
144
- if let Some ( file_name) = directory. file_name ( ) {
145
- if let Some ( ( _, settings) ) = index
146
- . range ( ..directory. clone ( ) )
147
- . rfind ( |( path, _) | directory. starts_with ( path) )
146
+ // Skip non-directories.
147
+ if !entry
148
+ . file_type ( )
149
+ . is_some_and ( |file_type| file_type. is_dir ( ) )
148
150
{
149
- if match_exclusion ( & directory, file_name, & settings. file_resolver . exclude ) {
150
- tracing:: debug!( "Ignored path via `exclude`: {}" , directory. display( ) ) ;
151
-
152
- walker. skip_current_dir ( ) ;
153
- continue ;
154
- } else if match_exclusion (
155
- & directory,
156
- file_name,
157
- & settings. file_resolver . extend_exclude ,
158
- ) {
159
- tracing:: debug!(
160
- "Ignored path via `extend-exclude`: {}" ,
161
- directory. display( )
162
- ) ;
163
-
164
- walker. skip_current_dir ( ) ;
165
- continue ;
151
+ return WalkState :: Continue ;
152
+ }
153
+
154
+ let directory = entry. into_path ( ) ;
155
+ tracing:: debug!( "Visiting: {}" , directory. display( ) ) ;
156
+
157
+ // If the directory is excluded from the workspace, skip it.
158
+ if let Some ( file_name) = directory. file_name ( ) {
159
+ if let Some ( ( _, settings) ) = index
160
+ . read ( )
161
+ . unwrap ( )
162
+ . range ( ..directory. clone ( ) )
163
+ . rfind ( |( path, _) | directory. starts_with ( path) )
164
+ {
165
+ if match_exclusion ( & directory, file_name, & settings. file_resolver . exclude ) {
166
+ tracing:: debug!( "Ignored path via `exclude`: {}" , directory. display( ) ) ;
167
+ return WalkState :: Continue ;
168
+ } else if match_exclusion (
169
+ & directory,
170
+ file_name,
171
+ & settings. file_resolver . extend_exclude ,
172
+ ) {
173
+ tracing:: debug!(
174
+ "Ignored path via `extend-exclude`: {}" ,
175
+ directory. display( )
176
+ ) ;
177
+ return WalkState :: Continue ;
178
+ }
166
179
}
167
180
}
168
- }
169
181
170
- if let Some ( pyproject) = settings_toml ( & directory) . ok ( ) . flatten ( ) {
171
- let Ok ( settings) = ruff_workspace:: resolver:: resolve_root_settings (
172
- & pyproject,
173
- Relativity :: Parent ,
174
- & EditorConfigurationTransformer ( editor_settings, root) ,
175
- ) else {
176
- continue ;
177
- } ;
178
- index. insert (
179
- directory,
180
- Arc :: new ( RuffSettings {
181
- path : Some ( pyproject) ,
182
- file_resolver : settings. file_resolver ,
183
- linter : settings. linter ,
184
- formatter : settings. formatter ,
185
- } ) ,
186
- ) ;
187
- }
188
- }
182
+ if let Some ( pyproject) = settings_toml ( & directory) . ok ( ) . flatten ( ) {
183
+ let Ok ( settings) = ruff_workspace:: resolver:: resolve_root_settings (
184
+ & pyproject,
185
+ Relativity :: Parent ,
186
+ & EditorConfigurationTransformer ( editor_settings, root) ,
187
+ ) else {
188
+ return WalkState :: Continue ;
189
+ } ;
190
+ index. write ( ) . unwrap ( ) . insert (
191
+ directory,
192
+ Arc :: new ( RuffSettings {
193
+ path : Some ( pyproject) ,
194
+ file_resolver : settings. file_resolver ,
195
+ linter : settings. linter ,
196
+ formatter : settings. formatter ,
197
+ } ) ,
198
+ ) ;
199
+ }
200
+
201
+ WalkState :: Continue
202
+ } )
203
+ } ) ;
189
204
190
205
let fallback = Arc :: new ( RuffSettings :: fallback ( editor_settings, root) ) ;
191
206
192
- Self { index, fallback }
207
+ Self {
208
+ index : index. into_inner ( ) . unwrap ( ) ,
209
+ fallback,
210
+ }
193
211
}
194
212
195
213
pub ( super ) fn get ( & self , document_path : & Path ) -> Arc < RuffSettings > {
0 commit comments