Skip to content

Commit 0bb2fc6

Browse files
authored
Conside include, extend-include for the native server (#12252)
## Summary This PR updates the native server to consider the `include` and `extend-include` file resolver settings. fixes: #12242 ## Test Plan Note: Settings reloading doesn't work for nested configs which is fixed in #12253 so the preview here only showcases root level config. https://github.com/astral-sh/ruff/assets/67177269/e8969128-c175-4f98-8114-0d692b906cc8
1 parent 855d62c commit 0bb2fc6

10 files changed

Lines changed: 101 additions & 47 deletions

File tree

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ruff_server/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ ruff_workspace = { workspace = true }
2828

2929
anyhow = { workspace = true }
3030
crossbeam = { workspace = true }
31-
globset = { workspace = true }
3231
jod-thread = { workspace = true }
3332
lsp-server = { workspace = true }
3433
lsp-types = { workspace = true }

crates/ruff_server/src/fix.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ use ruff_linter::{
99
};
1010
use ruff_notebook::SourceValue;
1111
use ruff_source_file::LineIndex;
12-
use ruff_workspace::resolver::match_any_exclusion;
1312

1413
use crate::{
1514
edit::{Replacement, ToRangeExt},
15+
resolve::is_document_excluded,
1616
session::DocumentQuery,
1717
PositionEncoding,
1818
};
@@ -33,18 +33,12 @@ pub(crate) fn fix_all(
3333

3434
// If the document is excluded, return an empty list of fixes.
3535
let package = if let Some(document_path) = document_path.as_ref() {
36-
if let Some(exclusion) = match_any_exclusion(
36+
if is_document_excluded(
3737
document_path,
38-
&file_resolver_settings.exclude,
39-
&file_resolver_settings.extend_exclude,
40-
Some(&linter_settings.exclude),
38+
file_resolver_settings,
39+
Some(linter_settings),
4140
None,
4241
) {
43-
tracing::debug!(
44-
"Ignored path via `{}`: {}",
45-
exclusion,
46-
document_path.display()
47-
);
4842
return Ok(Fixes::default());
4943
}
5044

crates/ruff_server/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ mod edit;
1212
mod fix;
1313
mod format;
1414
mod lint;
15+
mod resolve;
1516
mod server;
1617
mod session;
1718
mod trace;

crates/ruff_server/src/lint.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ use ruff_python_codegen::Stylist;
1919
use ruff_python_index::Indexer;
2020
use ruff_source_file::{LineIndex, Locator};
2121
use ruff_text_size::{Ranged, TextRange};
22-
use ruff_workspace::resolver::match_any_exclusion;
2322

2423
use crate::{
2524
edit::{NotebookRange, ToRangeExt},
25+
resolve::is_document_excluded,
2626
session::DocumentQuery,
2727
PositionEncoding, DIAGNOSTIC_NAME,
2828
};
@@ -72,18 +72,12 @@ pub(crate) fn check(
7272

7373
// If the document is excluded, return an empty list of diagnostics.
7474
let package = if let Some(document_path) = document_path.as_ref() {
75-
if let Some(exclusion) = match_any_exclusion(
75+
if is_document_excluded(
7676
document_path,
77-
&file_resolver_settings.exclude,
78-
&file_resolver_settings.extend_exclude,
79-
Some(&linter_settings.exclude),
77+
file_resolver_settings,
78+
Some(linter_settings),
8079
None,
8180
) {
82-
tracing::debug!(
83-
"Ignored path via `{}`: {}",
84-
exclusion,
85-
document_path.display()
86-
);
8781
return DiagnosticsMap::default();
8882
}
8983

crates/ruff_server/src/resolve.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use std::path::Path;
2+
3+
use ruff_linter::settings::LinterSettings;
4+
use ruff_workspace::resolver::{match_any_exclusion, match_any_inclusion};
5+
use ruff_workspace::{FileResolverSettings, FormatterSettings};
6+
7+
/// Return `true` if the document at the given [`Path`] should be excluded.
8+
///
9+
/// The tool-specific settings should be provided if the request for the document is specific to
10+
/// that tool. For example, a diagnostics request should provide the linter settings while the
11+
/// formatting request should provide the formatter settings.
12+
///
13+
/// The logic for the resolution considers both inclusion and exclusion and is as follows:
14+
/// 1. Check for global `exclude` and `extend-exclude` options along with tool specific `exclude`
15+
/// option (`lint.exclude`, `format.exclude`).
16+
/// 2. Check for global `include` and `extend-include` options.
17+
pub(crate) fn is_document_excluded(
18+
path: &Path,
19+
resolver_settings: &FileResolverSettings,
20+
linter_settings: Option<&LinterSettings>,
21+
formatter_settings: Option<&FormatterSettings>,
22+
) -> bool {
23+
if let Some(exclusion) = match_any_exclusion(
24+
path,
25+
&resolver_settings.exclude,
26+
&resolver_settings.extend_exclude,
27+
linter_settings.map(|s| &*s.exclude),
28+
formatter_settings.map(|s| &*s.exclude),
29+
) {
30+
tracing::debug!("Ignored path via `{}`: {}", exclusion, path.display());
31+
return true;
32+
}
33+
34+
if let Some(inclusion) = match_any_inclusion(
35+
path,
36+
&resolver_settings.include,
37+
&resolver_settings.extend_include,
38+
) {
39+
tracing::debug!("Included path via `{}`: {}", inclusion, path.display());
40+
false
41+
} else {
42+
// Path is excluded by not being in the inclusion set.
43+
true
44+
}
45+
}

crates/ruff_server/src/server/api/requests/format.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ use lsp_types::{self as types, request as req};
22
use types::TextEdit;
33

44
use ruff_source_file::LineIndex;
5-
use ruff_workspace::resolver::match_any_exclusion;
65

76
use crate::edit::{Replacement, ToRangeExt};
87
use crate::fix::Fixes;
8+
use crate::resolve::is_document_excluded;
99
use crate::server::api::LSPResult;
1010
use crate::server::{client::Notifier, Result};
1111
use crate::session::{DocumentQuery, DocumentSnapshot};
@@ -85,14 +85,12 @@ fn format_text_document(
8585

8686
// If the document is excluded, return early.
8787
if let Some(file_path) = query.file_path() {
88-
if let Some(exclusion) = match_any_exclusion(
88+
if is_document_excluded(
8989
&file_path,
90-
&file_resolver_settings.exclude,
91-
&file_resolver_settings.extend_exclude,
90+
file_resolver_settings,
9291
None,
93-
Some(&formatter_settings.exclude),
92+
Some(formatter_settings),
9493
) {
95-
tracing::debug!("Ignored path via `{}`: {}", exclusion, file_path.display());
9694
return Ok(None);
9795
}
9896
}

crates/ruff_server/src/server/api/requests/format_range.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use lsp_types::{self as types, request as req, Range};
22

3-
use ruff_workspace::resolver::match_any_exclusion;
4-
53
use crate::edit::{RangeExt, ToRangeExt};
4+
use crate::resolve::is_document_excluded;
65
use crate::server::api::LSPResult;
76
use crate::server::{client::Notifier, Result};
87
use crate::session::{DocumentQuery, DocumentSnapshot};
@@ -50,14 +49,12 @@ fn format_text_document_range(
5049

5150
// If the document is excluded, return early.
5251
if let Some(file_path) = query.file_path() {
53-
if let Some(exclusion) = match_any_exclusion(
52+
if is_document_excluded(
5453
&file_path,
55-
&file_resolver_settings.exclude,
56-
&file_resolver_settings.extend_exclude,
54+
file_resolver_settings,
5755
None,
58-
Some(&formatter_settings.exclude),
56+
Some(formatter_settings),
5957
) {
60-
tracing::debug!("Ignored path via `{}`: {}", exclusion, file_path.display());
6158
return Ok(None);
6259
}
6360
}

crates/ruff_server/src/session/index/ruff_settings.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
use globset::Candidate;
21
use ruff_linter::{
32
display_settings, fs::normalize_path_to, settings::types::FilePattern,
43
settings::types::PreviewMode,
54
};
6-
use ruff_workspace::resolver::match_candidate_exclusion;
5+
use ruff_workspace::resolver::match_exclusion;
76
use ruff_workspace::{
87
configuration::{Configuration, FormatConfiguration, LintConfiguration, RuleSelection},
98
pyproject::{find_user_settings_toml, settings_toml},
@@ -41,6 +40,7 @@ impl std::fmt::Display for RuffSettings {
4140
display_settings! {
4241
formatter = f,
4342
fields = [
43+
self.file_resolver,
4444
self.linter,
4545
self.formatter
4646
]
@@ -146,20 +146,14 @@ impl RuffSettingsIndex {
146146
.range(..directory.clone())
147147
.rfind(|(path, _)| directory.starts_with(path))
148148
{
149-
let candidate = Candidate::new(&directory);
150-
let basename = Candidate::new(file_name);
151-
if match_candidate_exclusion(
152-
&candidate,
153-
&basename,
154-
&settings.file_resolver.exclude,
155-
) {
149+
if match_exclusion(&directory, file_name, &settings.file_resolver.exclude) {
156150
tracing::debug!("Ignored path via `exclude`: {}", directory.display());
157151

158152
walker.skip_current_dir();
159153
continue;
160-
} else if match_candidate_exclusion(
161-
&candidate,
162-
&basename,
154+
} else if match_exclusion(
155+
&directory,
156+
file_name,
163157
&settings.file_resolver.extend_exclude,
164158
) {
165159
tracing::debug!(

crates/ruff_workspace/src/resolver.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,39 @@ pub fn match_any_exclusion(
683683
None
684684
}
685685

686+
#[derive(Debug, Copy, Clone)]
687+
pub enum InclusionKind {
688+
/// The inclusion came from the `include` setting.
689+
Include,
690+
/// The inclusion came from the `extend-include` setting.
691+
ExtendInclude,
692+
}
693+
694+
impl std::fmt::Display for InclusionKind {
695+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
696+
match self {
697+
InclusionKind::Include => write!(f, "include"),
698+
InclusionKind::ExtendInclude => write!(f, "extend-include"),
699+
}
700+
}
701+
}
702+
703+
/// Return the [`InclusionKind`] for a given [`Path`], if the path match any of the inclusion
704+
/// criteria.
705+
pub fn match_any_inclusion(
706+
path: &Path,
707+
include: &GlobSet,
708+
extend_include: &GlobSet,
709+
) -> Option<InclusionKind> {
710+
if include.is_match(path) {
711+
Some(InclusionKind::Include)
712+
} else if extend_include.is_match(path) {
713+
Some(InclusionKind::ExtendInclude)
714+
} else {
715+
None
716+
}
717+
}
718+
686719
#[cfg(test)]
687720
mod tests {
688721
use std::fs::{create_dir, File};

0 commit comments

Comments
 (0)