mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 22:31:23 +00:00
Respect file exclusions in ruff server
(#11590)
## Summary Closes https://github.com/astral-sh/ruff/issues/11587. ## Test Plan - Added a lint error to `test_server.py` in `vscode-ruff`. - Validated that, prior to this change, diagnostics appeared in the file. - Validated that, with this change, no diagnostics were shown. - Validated that, with this change, no diagnostics were fixed on-save.
This commit is contained in:
parent
531ae5227c
commit
204c59e353
11 changed files with 235 additions and 43 deletions
|
@ -1,3 +1,7 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use ruff_linter::{
|
use ruff_linter::{
|
||||||
linter::{FixerResult, LinterResult},
|
linter::{FixerResult, LinterResult},
|
||||||
packaging::detect_package_root,
|
packaging::detect_package_root,
|
||||||
|
@ -5,8 +9,8 @@ use ruff_linter::{
|
||||||
};
|
};
|
||||||
use ruff_notebook::SourceValue;
|
use ruff_notebook::SourceValue;
|
||||||
use ruff_source_file::LineIndex;
|
use ruff_source_file::LineIndex;
|
||||||
use rustc_hash::FxHashMap;
|
use ruff_workspace::resolver::match_any_exclusion;
|
||||||
use std::borrow::Cow;
|
use ruff_workspace::FileResolverSettings;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
edit::{Replacement, ToRangeExt},
|
edit::{Replacement, ToRangeExt},
|
||||||
|
@ -20,12 +24,29 @@ pub(crate) type Fixes = FxHashMap<lsp_types::Url, Vec<lsp_types::TextEdit>>;
|
||||||
|
|
||||||
pub(crate) fn fix_all(
|
pub(crate) fn fix_all(
|
||||||
query: &DocumentQuery,
|
query: &DocumentQuery,
|
||||||
|
file_resolver_settings: &FileResolverSettings,
|
||||||
linter_settings: &LinterSettings,
|
linter_settings: &LinterSettings,
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
) -> crate::Result<Fixes> {
|
) -> crate::Result<Fixes> {
|
||||||
let document_path = query.file_path();
|
let document_path = query.file_path();
|
||||||
let source_kind = query.make_source_kind();
|
let source_kind = query.make_source_kind();
|
||||||
|
|
||||||
|
// If the document is excluded, return an empty list of fixes.
|
||||||
|
if let Some(exclusion) = match_any_exclusion(
|
||||||
|
document_path,
|
||||||
|
&file_resolver_settings.exclude,
|
||||||
|
&file_resolver_settings.extend_exclude,
|
||||||
|
Some(&linter_settings.exclude),
|
||||||
|
None,
|
||||||
|
) {
|
||||||
|
tracing::debug!(
|
||||||
|
"Ignored path via `{}`: {}",
|
||||||
|
exclusion,
|
||||||
|
document_path.display()
|
||||||
|
);
|
||||||
|
return Ok(Fixes::default());
|
||||||
|
}
|
||||||
|
|
||||||
let package = detect_package_root(
|
let package = detect_package_root(
|
||||||
document_path
|
document_path
|
||||||
.parent()
|
.parent()
|
||||||
|
|
|
@ -16,6 +16,8 @@ use ruff_python_index::Indexer;
|
||||||
use ruff_python_parser::AsMode;
|
use ruff_python_parser::AsMode;
|
||||||
use ruff_source_file::{LineIndex, Locator};
|
use ruff_source_file::{LineIndex, Locator};
|
||||||
use ruff_text_size::{Ranged, TextRange};
|
use ruff_text_size::{Ranged, TextRange};
|
||||||
|
use ruff_workspace::resolver::match_any_exclusion;
|
||||||
|
use ruff_workspace::FileResolverSettings;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -60,12 +62,29 @@ pub(crate) type Diagnostics = FxHashMap<lsp_types::Url, Vec<lsp_types::Diagnosti
|
||||||
|
|
||||||
pub(crate) fn check(
|
pub(crate) fn check(
|
||||||
query: &DocumentQuery,
|
query: &DocumentQuery,
|
||||||
|
file_resolver_settings: &FileResolverSettings,
|
||||||
linter_settings: &LinterSettings,
|
linter_settings: &LinterSettings,
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
) -> Diagnostics {
|
) -> Diagnostics {
|
||||||
let document_path = query.file_path();
|
let document_path = query.file_path();
|
||||||
let source_kind = query.make_source_kind();
|
let source_kind = query.make_source_kind();
|
||||||
|
|
||||||
|
// If the document is excluded, return an empty list of diagnostics.
|
||||||
|
if let Some(exclusion) = match_any_exclusion(
|
||||||
|
document_path,
|
||||||
|
&file_resolver_settings.exclude,
|
||||||
|
&file_resolver_settings.extend_exclude,
|
||||||
|
Some(&linter_settings.exclude),
|
||||||
|
None,
|
||||||
|
) {
|
||||||
|
tracing::debug!(
|
||||||
|
"Ignored path via `{}`: {}",
|
||||||
|
exclusion,
|
||||||
|
document_path.display()
|
||||||
|
);
|
||||||
|
return Diagnostics::default();
|
||||||
|
}
|
||||||
|
|
||||||
let package = detect_package_root(
|
let package = detect_package_root(
|
||||||
document_path
|
document_path
|
||||||
.parent()
|
.parent()
|
||||||
|
|
|
@ -10,6 +10,7 @@ pub(super) fn generate_diagnostics(snapshot: &DocumentSnapshot) -> Diagnostics {
|
||||||
if snapshot.client_settings().lint() {
|
if snapshot.client_settings().lint() {
|
||||||
crate::lint::check(
|
crate::lint::check(
|
||||||
snapshot.query(),
|
snapshot.query(),
|
||||||
|
snapshot.query().settings().file_resolver(),
|
||||||
snapshot.query().settings().linter(),
|
snapshot.query().settings().linter(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
use lsp_server::ErrorCode;
|
||||||
|
use lsp_types::{self as types, request as req};
|
||||||
|
use rustc_hash::FxHashSet;
|
||||||
|
use types::{CodeActionKind, CodeActionOrCommand};
|
||||||
|
|
||||||
use crate::edit::WorkspaceEditTracker;
|
use crate::edit::WorkspaceEditTracker;
|
||||||
use crate::lint::{fixes_for_diagnostics, DiagnosticFix};
|
use crate::lint::{fixes_for_diagnostics, DiagnosticFix};
|
||||||
use crate::server::api::LSPResult;
|
use crate::server::api::LSPResult;
|
||||||
|
@ -5,10 +10,6 @@ use crate::server::SupportedCodeAction;
|
||||||
use crate::server::{client::Notifier, Result};
|
use crate::server::{client::Notifier, Result};
|
||||||
use crate::session::DocumentSnapshot;
|
use crate::session::DocumentSnapshot;
|
||||||
use crate::DIAGNOSTIC_NAME;
|
use crate::DIAGNOSTIC_NAME;
|
||||||
use lsp_server::ErrorCode;
|
|
||||||
use lsp_types::{self as types, request as req};
|
|
||||||
use rustc_hash::FxHashSet;
|
|
||||||
use types::{CodeActionKind, CodeActionOrCommand};
|
|
||||||
|
|
||||||
use super::code_action_resolve::{resolve_edit_for_fix_all, resolve_edit_for_organize_imports};
|
use super::code_action_resolve::{resolve_edit_for_fix_all, resolve_edit_for_organize_imports};
|
||||||
|
|
||||||
|
@ -156,6 +157,7 @@ fn fix_all(snapshot: &DocumentSnapshot) -> crate::Result<CodeActionOrCommand> {
|
||||||
Some(resolve_edit_for_fix_all(
|
Some(resolve_edit_for_fix_all(
|
||||||
document,
|
document,
|
||||||
snapshot.resolved_client_capabilities(),
|
snapshot.resolved_client_capabilities(),
|
||||||
|
snapshot.query().settings().file_resolver(),
|
||||||
snapshot.query().settings().linter(),
|
snapshot.query().settings().linter(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
)?),
|
)?),
|
||||||
|
@ -192,6 +194,7 @@ fn notebook_fix_all(snapshot: &DocumentSnapshot) -> crate::Result<CodeActionOrCo
|
||||||
Some(resolve_edit_for_fix_all(
|
Some(resolve_edit_for_fix_all(
|
||||||
document,
|
document,
|
||||||
snapshot.resolved_client_capabilities(),
|
snapshot.resolved_client_capabilities(),
|
||||||
|
snapshot.query().settings().file_resolver(),
|
||||||
snapshot.query().settings().linter(),
|
snapshot.query().settings().linter(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
)?),
|
)?),
|
||||||
|
@ -228,6 +231,7 @@ fn organize_imports(snapshot: &DocumentSnapshot) -> crate::Result<CodeActionOrCo
|
||||||
Some(resolve_edit_for_organize_imports(
|
Some(resolve_edit_for_organize_imports(
|
||||||
document,
|
document,
|
||||||
snapshot.resolved_client_capabilities(),
|
snapshot.resolved_client_capabilities(),
|
||||||
|
snapshot.query().settings().file_resolver(),
|
||||||
snapshot.query().settings().linter(),
|
snapshot.query().settings().linter(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
)?),
|
)?),
|
||||||
|
@ -264,6 +268,7 @@ fn notebook_organize_imports(snapshot: &DocumentSnapshot) -> crate::Result<CodeA
|
||||||
Some(resolve_edit_for_organize_imports(
|
Some(resolve_edit_for_organize_imports(
|
||||||
document,
|
document,
|
||||||
snapshot.resolved_client_capabilities(),
|
snapshot.resolved_client_capabilities(),
|
||||||
|
snapshot.query().settings().file_resolver(),
|
||||||
snapshot.query().settings().linter(),
|
snapshot.query().settings().linter(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
)?),
|
)?),
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use lsp_server::ErrorCode;
|
||||||
|
use lsp_types::{self as types, request as req};
|
||||||
|
|
||||||
|
use ruff_linter::codes::Rule;
|
||||||
|
use ruff_linter::settings::LinterSettings;
|
||||||
|
use ruff_workspace::FileResolverSettings;
|
||||||
|
|
||||||
use crate::edit::WorkspaceEditTracker;
|
use crate::edit::WorkspaceEditTracker;
|
||||||
use crate::fix::Fixes;
|
use crate::fix::Fixes;
|
||||||
use crate::server::api::LSPResult;
|
use crate::server::api::LSPResult;
|
||||||
|
@ -7,10 +14,6 @@ use crate::server::SupportedCodeAction;
|
||||||
use crate::server::{client::Notifier, Result};
|
use crate::server::{client::Notifier, Result};
|
||||||
use crate::session::{DocumentQuery, DocumentSnapshot, ResolvedClientCapabilities};
|
use crate::session::{DocumentQuery, DocumentSnapshot, ResolvedClientCapabilities};
|
||||||
use crate::PositionEncoding;
|
use crate::PositionEncoding;
|
||||||
use lsp_server::ErrorCode;
|
|
||||||
use lsp_types::{self as types, request as req};
|
|
||||||
use ruff_linter::codes::Rule;
|
|
||||||
use ruff_linter::settings::LinterSettings;
|
|
||||||
|
|
||||||
pub(crate) struct CodeActionResolve;
|
pub(crate) struct CodeActionResolve;
|
||||||
|
|
||||||
|
@ -22,7 +25,7 @@ impl super::BackgroundDocumentRequestHandler for CodeActionResolve {
|
||||||
fn document_url(params: &types::CodeAction) -> Cow<types::Url> {
|
fn document_url(params: &types::CodeAction) -> Cow<types::Url> {
|
||||||
let uri: lsp_types::Url = serde_json::from_value(params.data.clone().unwrap_or_default())
|
let uri: lsp_types::Url = serde_json::from_value(params.data.clone().unwrap_or_default())
|
||||||
.expect("code actions should have a URI in their data fields");
|
.expect("code actions should have a URI in their data fields");
|
||||||
std::borrow::Cow::Owned(uri)
|
Cow::Owned(uri)
|
||||||
}
|
}
|
||||||
fn run_with_snapshot(
|
fn run_with_snapshot(
|
||||||
snapshot: DocumentSnapshot,
|
snapshot: DocumentSnapshot,
|
||||||
|
@ -54,6 +57,7 @@ impl super::BackgroundDocumentRequestHandler for CodeActionResolve {
|
||||||
resolve_edit_for_fix_all(
|
resolve_edit_for_fix_all(
|
||||||
query,
|
query,
|
||||||
snapshot.resolved_client_capabilities(),
|
snapshot.resolved_client_capabilities(),
|
||||||
|
query.settings().file_resolver(),
|
||||||
query.settings().linter(),
|
query.settings().linter(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
)
|
)
|
||||||
|
@ -64,6 +68,7 @@ impl super::BackgroundDocumentRequestHandler for CodeActionResolve {
|
||||||
resolve_edit_for_organize_imports(
|
resolve_edit_for_organize_imports(
|
||||||
query,
|
query,
|
||||||
snapshot.resolved_client_capabilities(),
|
snapshot.resolved_client_capabilities(),
|
||||||
|
query.settings().file_resolver(),
|
||||||
query.settings().linter(),
|
query.settings().linter(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
)
|
)
|
||||||
|
@ -84,12 +89,13 @@ impl super::BackgroundDocumentRequestHandler for CodeActionResolve {
|
||||||
pub(super) fn resolve_edit_for_fix_all(
|
pub(super) fn resolve_edit_for_fix_all(
|
||||||
query: &DocumentQuery,
|
query: &DocumentQuery,
|
||||||
client_capabilities: &ResolvedClientCapabilities,
|
client_capabilities: &ResolvedClientCapabilities,
|
||||||
|
file_resolver_settings: &FileResolverSettings,
|
||||||
linter_settings: &LinterSettings,
|
linter_settings: &LinterSettings,
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
) -> crate::Result<types::WorkspaceEdit> {
|
) -> crate::Result<types::WorkspaceEdit> {
|
||||||
let mut tracker = WorkspaceEditTracker::new(client_capabilities);
|
let mut tracker = WorkspaceEditTracker::new(client_capabilities);
|
||||||
tracker.set_fixes_for_document(
|
tracker.set_fixes_for_document(
|
||||||
fix_all_edit(query, linter_settings, encoding)?,
|
fix_all_edit(query, file_resolver_settings, linter_settings, encoding)?,
|
||||||
query.version(),
|
query.version(),
|
||||||
)?;
|
)?;
|
||||||
Ok(tracker.into_workspace_edit())
|
Ok(tracker.into_workspace_edit())
|
||||||
|
@ -97,21 +103,23 @@ pub(super) fn resolve_edit_for_fix_all(
|
||||||
|
|
||||||
pub(super) fn fix_all_edit(
|
pub(super) fn fix_all_edit(
|
||||||
query: &DocumentQuery,
|
query: &DocumentQuery,
|
||||||
|
file_resolver_settings: &FileResolverSettings,
|
||||||
linter_settings: &LinterSettings,
|
linter_settings: &LinterSettings,
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
) -> crate::Result<Fixes> {
|
) -> crate::Result<Fixes> {
|
||||||
crate::fix::fix_all(query, linter_settings, encoding)
|
crate::fix::fix_all(query, file_resolver_settings, linter_settings, encoding)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn resolve_edit_for_organize_imports(
|
pub(super) fn resolve_edit_for_organize_imports(
|
||||||
query: &DocumentQuery,
|
query: &DocumentQuery,
|
||||||
client_capabilities: &ResolvedClientCapabilities,
|
client_capabilities: &ResolvedClientCapabilities,
|
||||||
linter_settings: &ruff_linter::settings::LinterSettings,
|
file_resolver_settings: &FileResolverSettings,
|
||||||
|
linter_settings: &LinterSettings,
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
) -> crate::Result<types::WorkspaceEdit> {
|
) -> crate::Result<types::WorkspaceEdit> {
|
||||||
let mut tracker = WorkspaceEditTracker::new(client_capabilities);
|
let mut tracker = WorkspaceEditTracker::new(client_capabilities);
|
||||||
tracker.set_fixes_for_document(
|
tracker.set_fixes_for_document(
|
||||||
organize_imports_edit(query, linter_settings, encoding)?,
|
organize_imports_edit(query, file_resolver_settings, linter_settings, encoding)?,
|
||||||
query.version(),
|
query.version(),
|
||||||
)?;
|
)?;
|
||||||
Ok(tracker.into_workspace_edit())
|
Ok(tracker.into_workspace_edit())
|
||||||
|
@ -119,6 +127,7 @@ pub(super) fn resolve_edit_for_organize_imports(
|
||||||
|
|
||||||
pub(super) fn organize_imports_edit(
|
pub(super) fn organize_imports_edit(
|
||||||
query: &DocumentQuery,
|
query: &DocumentQuery,
|
||||||
|
file_resolver_settings: &FileResolverSettings,
|
||||||
linter_settings: &LinterSettings,
|
linter_settings: &LinterSettings,
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
) -> crate::Result<Fixes> {
|
) -> crate::Result<Fixes> {
|
||||||
|
@ -130,5 +139,5 @@ pub(super) fn organize_imports_edit(
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
crate::fix::fix_all(query, &linter_settings, encoding)
|
crate::fix::fix_all(query, file_resolver_settings, &linter_settings, encoding)
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ impl super::SyncRequestHandler for ExecuteCommand {
|
||||||
Command::FixAll => {
|
Command::FixAll => {
|
||||||
let fixes = super::code_action_resolve::fix_all_edit(
|
let fixes = super::code_action_resolve::fix_all_edit(
|
||||||
snapshot.query(),
|
snapshot.query(),
|
||||||
|
snapshot.query().settings().file_resolver(),
|
||||||
snapshot.query().settings().linter(),
|
snapshot.query().settings().linter(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
)
|
)
|
||||||
|
@ -81,6 +82,7 @@ impl super::SyncRequestHandler for ExecuteCommand {
|
||||||
Command::OrganizeImports => {
|
Command::OrganizeImports => {
|
||||||
let fixes = super::code_action_resolve::organize_imports_edit(
|
let fixes = super::code_action_resolve::organize_imports_edit(
|
||||||
snapshot.query(),
|
snapshot.query(),
|
||||||
|
snapshot.query().settings().file_resolver(),
|
||||||
snapshot.query().settings().linter(),
|
snapshot.query().settings().linter(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use lsp_types::{self as types, request as req};
|
||||||
|
use types::TextEdit;
|
||||||
|
|
||||||
|
use ruff_python_ast::PySourceType;
|
||||||
|
use ruff_source_file::LineIndex;
|
||||||
|
use ruff_workspace::resolver::match_any_exclusion;
|
||||||
|
use ruff_workspace::{FileResolverSettings, FormatterSettings};
|
||||||
|
|
||||||
use crate::edit::{Replacement, ToRangeExt};
|
use crate::edit::{Replacement, ToRangeExt};
|
||||||
use crate::fix::Fixes;
|
use crate::fix::Fixes;
|
||||||
use crate::server::api::LSPResult;
|
use crate::server::api::LSPResult;
|
||||||
use crate::server::{client::Notifier, Result};
|
use crate::server::{client::Notifier, Result};
|
||||||
use crate::session::DocumentSnapshot;
|
use crate::session::DocumentSnapshot;
|
||||||
use crate::{PositionEncoding, TextDocument};
|
use crate::{PositionEncoding, TextDocument};
|
||||||
use lsp_types::{self as types, request as req};
|
|
||||||
use ruff_python_ast::PySourceType;
|
|
||||||
use ruff_source_file::LineIndex;
|
|
||||||
use ruff_workspace::FormatterSettings;
|
|
||||||
use types::TextEdit;
|
|
||||||
|
|
||||||
pub(crate) struct Format;
|
pub(crate) struct Format;
|
||||||
|
|
||||||
|
@ -39,6 +44,8 @@ pub(super) fn format_full_document(snapshot: &DocumentSnapshot) -> Result<Fixes>
|
||||||
if let Some(changes) = format_text_document(
|
if let Some(changes) = format_text_document(
|
||||||
text_document,
|
text_document,
|
||||||
snapshot.query().source_type(),
|
snapshot.query().source_type(),
|
||||||
|
snapshot.query().file_path(),
|
||||||
|
snapshot.query().settings().file_resolver(),
|
||||||
snapshot.query().settings().formatter(),
|
snapshot.query().settings().formatter(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
true,
|
true,
|
||||||
|
@ -50,6 +57,8 @@ pub(super) fn format_full_document(snapshot: &DocumentSnapshot) -> Result<Fixes>
|
||||||
if let Some(changes) = format_text_document(
|
if let Some(changes) = format_text_document(
|
||||||
snapshot.query().as_single_document().unwrap(),
|
snapshot.query().as_single_document().unwrap(),
|
||||||
snapshot.query().source_type(),
|
snapshot.query().source_type(),
|
||||||
|
snapshot.query().file_path(),
|
||||||
|
snapshot.query().settings().file_resolver(),
|
||||||
snapshot.query().settings().formatter(),
|
snapshot.query().settings().formatter(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
false,
|
false,
|
||||||
|
@ -71,6 +80,8 @@ pub(super) fn format_document(snapshot: &DocumentSnapshot) -> Result<super::Form
|
||||||
format_text_document(
|
format_text_document(
|
||||||
text_document,
|
text_document,
|
||||||
snapshot.query().source_type(),
|
snapshot.query().source_type(),
|
||||||
|
snapshot.query().file_path(),
|
||||||
|
snapshot.query().settings().file_resolver(),
|
||||||
snapshot.query().settings().formatter(),
|
snapshot.query().settings().formatter(),
|
||||||
snapshot.encoding(),
|
snapshot.encoding(),
|
||||||
snapshot.query().as_notebook().is_some(),
|
snapshot.query().as_notebook().is_some(),
|
||||||
|
@ -80,10 +91,24 @@ pub(super) fn format_document(snapshot: &DocumentSnapshot) -> Result<super::Form
|
||||||
fn format_text_document(
|
fn format_text_document(
|
||||||
text_document: &TextDocument,
|
text_document: &TextDocument,
|
||||||
source_type: PySourceType,
|
source_type: PySourceType,
|
||||||
|
file_path: &Path,
|
||||||
|
file_resolver_settings: &FileResolverSettings,
|
||||||
formatter_settings: &FormatterSettings,
|
formatter_settings: &FormatterSettings,
|
||||||
encoding: PositionEncoding,
|
encoding: PositionEncoding,
|
||||||
is_notebook: bool,
|
is_notebook: bool,
|
||||||
) -> Result<super::FormatResponse> {
|
) -> Result<super::FormatResponse> {
|
||||||
|
// If the document is excluded, return early.
|
||||||
|
if let Some(exclusion) = match_any_exclusion(
|
||||||
|
file_path,
|
||||||
|
&file_resolver_settings.exclude,
|
||||||
|
&file_resolver_settings.extend_exclude,
|
||||||
|
None,
|
||||||
|
Some(&formatter_settings.exclude),
|
||||||
|
) {
|
||||||
|
tracing::debug!("Ignored path via `{}`: {}", exclusion, file_path.display());
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
let source = text_document.contents();
|
let source = text_document.contents();
|
||||||
let mut formatted = crate::format::format(text_document, source_type, formatter_settings)
|
let mut formatted = crate::format::format(text_document, source_type, formatter_settings)
|
||||||
.with_failure_code(lsp_server::ErrorCode::InternalError)?;
|
.with_failure_code(lsp_server::ErrorCode::InternalError)?;
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use lsp_types::{self as types, request as req, Range};
|
||||||
|
|
||||||
|
use ruff_python_ast::PySourceType;
|
||||||
|
use ruff_workspace::resolver::match_any_exclusion;
|
||||||
|
use ruff_workspace::{FileResolverSettings, FormatterSettings};
|
||||||
|
|
||||||
use crate::edit::{RangeExt, ToRangeExt};
|
use crate::edit::{RangeExt, ToRangeExt};
|
||||||
use crate::server::api::LSPResult;
|
use crate::server::api::LSPResult;
|
||||||
use crate::server::{client::Notifier, Result};
|
use crate::server::{client::Notifier, Result};
|
||||||
use crate::session::DocumentSnapshot;
|
use crate::session::DocumentSnapshot;
|
||||||
use lsp_types::{self as types, request as req};
|
use crate::{PositionEncoding, TextDocument};
|
||||||
|
|
||||||
pub(crate) struct FormatRange;
|
pub(crate) struct FormatRange;
|
||||||
|
|
||||||
|
@ -17,25 +25,63 @@ impl super::BackgroundDocumentRequestHandler for FormatRange {
|
||||||
_notifier: Notifier,
|
_notifier: Notifier,
|
||||||
params: types::DocumentRangeFormattingParams,
|
params: types::DocumentRangeFormattingParams,
|
||||||
) -> Result<super::FormatResponse> {
|
) -> Result<super::FormatResponse> {
|
||||||
let document = snapshot
|
format_document_range(&snapshot, params.range)
|
||||||
.query()
|
|
||||||
.as_single_document()
|
|
||||||
.expect("hover should only be called on text documents or notebook cells");
|
|
||||||
let text = document.contents();
|
|
||||||
let index = document.index();
|
|
||||||
let range = params.range.to_text_range(text, index, snapshot.encoding());
|
|
||||||
let formatted_range = crate::format::format_range(
|
|
||||||
document,
|
|
||||||
snapshot.query().source_type(),
|
|
||||||
snapshot.query().settings().formatter(),
|
|
||||||
range,
|
|
||||||
)
|
|
||||||
.with_failure_code(lsp_server::ErrorCode::InternalError)?;
|
|
||||||
Ok(Some(vec![types::TextEdit {
|
|
||||||
range: formatted_range
|
|
||||||
.source_range()
|
|
||||||
.to_range(text, index, snapshot.encoding()),
|
|
||||||
new_text: formatted_range.into_code(),
|
|
||||||
}]))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Formats the specified [`Range`] in the [`DocumentSnapshot`].
|
||||||
|
fn format_document_range(
|
||||||
|
snapshot: &DocumentSnapshot,
|
||||||
|
range: Range,
|
||||||
|
) -> Result<super::FormatResponse> {
|
||||||
|
let text_document = snapshot
|
||||||
|
.query()
|
||||||
|
.as_single_document()
|
||||||
|
.expect("format should only be called on text documents or notebook cells");
|
||||||
|
format_text_document_range(
|
||||||
|
text_document,
|
||||||
|
range,
|
||||||
|
snapshot.query().source_type(),
|
||||||
|
snapshot.query().file_path(),
|
||||||
|
snapshot.query().settings().file_resolver(),
|
||||||
|
snapshot.query().settings().formatter(),
|
||||||
|
snapshot.encoding(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formats the specified [`Range`] in the [`TextDocument`].
|
||||||
|
fn format_text_document_range(
|
||||||
|
text_document: &TextDocument,
|
||||||
|
range: Range,
|
||||||
|
source_type: PySourceType,
|
||||||
|
file_path: &Path,
|
||||||
|
file_resolver_settings: &FileResolverSettings,
|
||||||
|
formatter_settings: &FormatterSettings,
|
||||||
|
encoding: PositionEncoding,
|
||||||
|
) -> Result<super::FormatResponse> {
|
||||||
|
// If the document is excluded, return early.
|
||||||
|
if let Some(exclusion) = match_any_exclusion(
|
||||||
|
file_path,
|
||||||
|
&file_resolver_settings.exclude,
|
||||||
|
&file_resolver_settings.extend_exclude,
|
||||||
|
None,
|
||||||
|
Some(&formatter_settings.exclude),
|
||||||
|
) {
|
||||||
|
tracing::debug!("Ignored path via `{}`: {}", exclusion, file_path.display());
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let text = text_document.contents();
|
||||||
|
let index = text_document.index();
|
||||||
|
let range = range.to_text_range(text, index, encoding);
|
||||||
|
let formatted_range =
|
||||||
|
crate::format::format_range(text_document, source_type, formatter_settings, range)
|
||||||
|
.with_failure_code(lsp_server::ErrorCode::InternalError)?;
|
||||||
|
|
||||||
|
Ok(Some(vec![types::TextEdit {
|
||||||
|
range: formatted_range
|
||||||
|
.source_range()
|
||||||
|
.to_range(text, index, encoding),
|
||||||
|
new_text: formatted_range.into_code(),
|
||||||
|
}]))
|
||||||
|
}
|
||||||
|
|
|
@ -479,7 +479,7 @@ impl DocumentQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the underlying file path for the document selected by this query.
|
/// Get the underlying file path for the document selected by this query.
|
||||||
pub(crate) fn file_path(&self) -> &PathBuf {
|
pub(crate) fn file_path(&self) -> &Path {
|
||||||
match self {
|
match self {
|
||||||
Self::Text { file_path, .. } | Self::Notebook { file_path, .. } => file_path,
|
Self::Text { file_path, .. } | Self::Notebook { file_path, .. } => file_path,
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,10 +73,17 @@ impl RuffSettings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the [`ruff_workspace::FileResolverSettings`] for this [`RuffSettings`].
|
||||||
|
pub(crate) fn file_resolver(&self) -> &ruff_workspace::FileResolverSettings {
|
||||||
|
&self.file_resolver
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the [`ruff_linter::settings::LinterSettings`] for this [`RuffSettings`].
|
||||||
pub(crate) fn linter(&self) -> &ruff_linter::settings::LinterSettings {
|
pub(crate) fn linter(&self) -> &ruff_linter::settings::LinterSettings {
|
||||||
&self.linter
|
&self.linter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the [`ruff_workspace::FormatterSettings`] for this [`RuffSettings`].
|
||||||
pub(crate) fn formatter(&self) -> &ruff_workspace::FormatterSettings {
|
pub(crate) fn formatter(&self) -> &ruff_workspace::FormatterSettings {
|
||||||
&self.formatter
|
&self.formatter
|
||||||
}
|
}
|
||||||
|
|
|
@ -626,6 +626,63 @@ pub fn match_candidate_exclusion(
|
||||||
exclusion.is_match_candidate(file_path) || exclusion.is_match_candidate(file_basename)
|
exclusion.is_match_candidate(file_path) || exclusion.is_match_candidate(file_basename)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub enum ExclusionKind {
|
||||||
|
/// The exclusion came from the `exclude` setting.
|
||||||
|
Exclude,
|
||||||
|
/// The exclusion came from the `extend-exclude` setting.
|
||||||
|
ExtendExclude,
|
||||||
|
/// The exclusion came from the `lint.exclude` setting.
|
||||||
|
LintExclude,
|
||||||
|
/// The exclusion came from the `lint.extend-exclude` setting.
|
||||||
|
FormatExclude,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ExclusionKind {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
ExclusionKind::Exclude => write!(f, "exclude"),
|
||||||
|
ExclusionKind::ExtendExclude => write!(f, "extend-exclude"),
|
||||||
|
ExclusionKind::LintExclude => write!(f, "lint.exclude"),
|
||||||
|
ExclusionKind::FormatExclude => write!(f, "lint.extend-exclude"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the [`ExclusionKind`] for a given [`Path`], if the path or any of its ancestors match
|
||||||
|
/// any of the exclusion criteria.
|
||||||
|
pub fn match_any_exclusion(
|
||||||
|
path: &Path,
|
||||||
|
exclude: &GlobSet,
|
||||||
|
extend_exclude: &GlobSet,
|
||||||
|
lint_exclude: Option<&GlobSet>,
|
||||||
|
format_exclude: Option<&GlobSet>,
|
||||||
|
) -> Option<ExclusionKind> {
|
||||||
|
for path in path.ancestors() {
|
||||||
|
if let Some(basename) = path.file_name() {
|
||||||
|
let path = Candidate::new(path);
|
||||||
|
let basename = Candidate::new(basename);
|
||||||
|
if match_candidate_exclusion(&path, &basename, exclude) {
|
||||||
|
return Some(ExclusionKind::Exclude);
|
||||||
|
}
|
||||||
|
if match_candidate_exclusion(&path, &basename, extend_exclude) {
|
||||||
|
return Some(ExclusionKind::ExtendExclude);
|
||||||
|
}
|
||||||
|
if let Some(lint_exclude) = lint_exclude {
|
||||||
|
if match_candidate_exclusion(&path, &basename, lint_exclude) {
|
||||||
|
return Some(ExclusionKind::LintExclude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(format_exclude) = format_exclude {
|
||||||
|
if match_candidate_exclusion(&path, &basename, format_exclude) {
|
||||||
|
return Some(ExclusionKind::FormatExclude);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::fs::{create_dir, File};
|
use std::fs::{create_dir, File};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue