ruff/crates/ruff_server/src/resolve.rs
Dhruv Manilawala 869a9543e4
Root exclusions in the server to project root (#16043)
## Summary

fixes: #16041 

## Test Plan

Using the [project](https://github.com/bwcc-clan/polebot) in the linked
issue:

Notice how the project "polebot" is in the "play" directory which is
included in the `exclude` setting as:

```toml
exclude = ["play"]
```

**Before this fix**

```
DEBUG ruff:worker:0 ruff_server::resolve: Ignored path via `exclude`: /private/tmp/ruff-test/play/polebot/src/utils/log_tools.py
```

**After this fix**

```
DEBUG ruff:worker:2 ruff_server::resolve: Included path via `include`: /private/tmp/ruff-test/play/polebot/src/utils/log_tools.py
```

I also updated the same project to remove the "play" directory from the
`exclude` setting and made sure that anything under the `polebot/play`
directory is included:

```
DEBUG  ruff:worker:4 ruff_server::resolve: Included path via `include`: /private/tmp/ruff-test/play/polebot/play/test.py
```

And, excluded when I add the directory back:

```
DEBUG  ruff:worker:2 ruff_server::resolve: Ignored path via `exclude`: /private/tmp/ruff-test/play/polebot/play/test.py
```
2025-02-10 04:57:14 +00:00

83 lines
2.9 KiB
Rust

use std::path::Path;
use ruff_linter::settings::LinterSettings;
use ruff_workspace::resolver::{match_any_exclusion, match_any_inclusion};
use ruff_workspace::{FileResolverSettings, FormatterSettings};
use crate::edit::LanguageId;
/// Return `true` if the document at the given [`Path`] should be excluded from linting.
pub(crate) fn is_document_excluded_for_linting(
path: &Path,
resolver_settings: &FileResolverSettings,
linter_settings: &LinterSettings,
language_id: Option<LanguageId>,
) -> bool {
is_document_excluded(
path,
resolver_settings,
Some(linter_settings),
None,
language_id,
)
}
/// Return `true` if the document at the given [`Path`] should be excluded from formatting.
pub(crate) fn is_document_excluded_for_formatting(
path: &Path,
resolver_settings: &FileResolverSettings,
formatter_settings: &FormatterSettings,
language_id: Option<LanguageId>,
) -> bool {
is_document_excluded(
path,
resolver_settings,
None,
Some(formatter_settings),
language_id,
)
}
/// Return `true` if the document at the given [`Path`] should be excluded.
///
/// The tool-specific settings should be provided if the request for the document is specific to
/// that tool. For example, a diagnostics request should provide the linter settings while the
/// formatting request should provide the formatter settings.
///
/// The logic for the resolution considers both inclusion and exclusion and is as follows:
/// 1. Check for global `exclude` and `extend-exclude` options along with tool specific `exclude`
/// option (`lint.exclude`, `format.exclude`).
/// 2. Check for global `include` and `extend-include` options.
/// 3. Check if the language ID is Python, in which case the document is included.
/// 4. If none of the above conditions are met, the document is excluded.
fn is_document_excluded(
path: &Path,
resolver_settings: &FileResolverSettings,
linter_settings: Option<&LinterSettings>,
formatter_settings: Option<&FormatterSettings>,
language_id: Option<LanguageId>,
) -> bool {
if let Some(exclusion) = match_any_exclusion(
path,
resolver_settings,
linter_settings.map(|s| &*s.exclude),
formatter_settings.map(|s| &*s.exclude),
) {
tracing::debug!("Ignored path via `{}`: {}", exclusion, path.display());
return true;
}
if let Some(inclusion) = match_any_inclusion(path, resolver_settings) {
tracing::debug!("Included path via `{}`: {}", inclusion, path.display());
false
} else if let Some(LanguageId::Python) = language_id {
tracing::debug!("Included path via Python language ID: {}", path.display());
false
} else {
tracing::debug!(
"Ignored path as it's not in the inclusion set: {}",
path.display()
);
true
}
}