Skip to content

Commit 7a0eb57

Browse files
committed
refactor(language_server): refactor ignore code action logic as a linter fix (#14183)
part of #11707 `disable rule for this file` are only valid for the current `SubContextHost` and will produce syntax error for vue files. A comment like this will be added. ``` // oxlint-disable no-debugger <script> debugger; </script> ``` This is the first part to refactor the logic, by moving it nearer to the linter, where the source text / sections are available. Probably needs some LSP feature flag for the message to pass the information of the current `ContextSubHost` source text offset.
1 parent 3b1fe6f commit 7a0eb57

25 files changed

+1792
-159
lines changed
Lines changed: 27 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
use tower_lsp_server::lsp_types::{
2-
CodeAction, CodeActionKind, Position, Range, TextEdit, Uri, WorkspaceEdit,
3-
};
1+
use tower_lsp_server::lsp_types::{CodeAction, CodeActionKind, TextEdit, Uri, WorkspaceEdit};
42

53
use crate::linter::error_with_position::{DiagnosticReport, FixedContent, PossibleFixContent};
64

@@ -11,6 +9,7 @@ fn fix_content_to_code_action(
119
fixed_content: &FixedContent,
1210
uri: &Uri,
1311
alternative_message: &str,
12+
is_preferred: bool,
1413
) -> CodeAction {
1514
// 1) Use `fixed_content.message` if it exists
1615
// 2) Try to parse the report diagnostic message
@@ -29,7 +28,7 @@ fn fix_content_to_code_action(
2928
CodeAction {
3029
title,
3130
kind: Some(CodeActionKind::QUICKFIX),
32-
is_preferred: Some(true),
31+
is_preferred: Some(is_preferred),
3332
edit: Some(WorkspaceEdit {
3433
#[expect(clippy::disallowed_types)]
3534
changes: Some(std::collections::HashMap::from([(
@@ -48,17 +47,31 @@ fn fix_content_to_code_action(
4847
pub fn apply_fix_code_actions(report: &DiagnosticReport, uri: &Uri) -> Option<Vec<CodeAction>> {
4948
match &report.fixed_content {
5049
PossibleFixContent::None => None,
51-
PossibleFixContent::Single(fixed_content) => {
52-
Some(vec![fix_content_to_code_action(fixed_content, uri, &report.diagnostic.message)])
50+
PossibleFixContent::Single(fixed_content) => Some(vec![fix_content_to_code_action(
51+
fixed_content,
52+
uri,
53+
&report.diagnostic.message,
54+
true,
55+
)]),
56+
PossibleFixContent::Multiple(fixed_contents) => {
57+
// only the first code action is preferred
58+
let mut preferred = true;
59+
Some(
60+
fixed_contents
61+
.iter()
62+
.map(|fixed_content| {
63+
let action = fix_content_to_code_action(
64+
fixed_content,
65+
uri,
66+
&report.diagnostic.message,
67+
preferred,
68+
);
69+
preferred = false;
70+
action
71+
})
72+
.collect(),
73+
)
5374
}
54-
PossibleFixContent::Multiple(fixed_contents) => Some(
55-
fixed_contents
56-
.iter()
57-
.map(|fixed_content| {
58-
fix_content_to_code_action(fixed_content, uri, &report.diagnostic.message)
59-
})
60-
.collect(),
61-
),
6275
}
6376
}
6477

@@ -108,82 +121,3 @@ pub fn apply_all_fix_code_action<'a>(
108121
command: None,
109122
})
110123
}
111-
112-
pub fn ignore_this_line_code_action(report: &DiagnosticReport, uri: &Uri) -> CodeAction {
113-
let rule_name = report.rule_name.as_ref();
114-
115-
// TODO: This CodeAction doesn't support disabling multiple rules by name for a given line.
116-
// To do that, we need to read `report.diagnostic.range.start.line` and check if a disable comment already exists.
117-
// If it does, it needs to be appended to instead of a completely new line inserted.
118-
CodeAction {
119-
title: rule_name.as_ref().map_or_else(
120-
|| "Disable oxlint for this line".into(),
121-
|s| format!("Disable {s} for this line"),
122-
),
123-
kind: Some(CodeActionKind::QUICKFIX),
124-
is_preferred: Some(false),
125-
edit: Some(WorkspaceEdit {
126-
#[expect(clippy::disallowed_types)]
127-
changes: Some(std::collections::HashMap::from([(
128-
uri.clone(),
129-
vec![TextEdit {
130-
range: Range {
131-
start: Position {
132-
line: report.diagnostic.range.start.line,
133-
// TODO: character should be set to match the first non-whitespace character in the source text to match the existing indentation.
134-
character: 0,
135-
},
136-
end: Position {
137-
line: report.diagnostic.range.start.line,
138-
// TODO: character should be set to match the first non-whitespace character in the source text to match the existing indentation.
139-
character: 0,
140-
},
141-
},
142-
new_text: rule_name.as_ref().map_or_else(
143-
|| "// oxlint-disable-next-line\n".into(),
144-
|s| format!("// oxlint-disable-next-line {s}\n"),
145-
),
146-
}],
147-
)])),
148-
..WorkspaceEdit::default()
149-
}),
150-
disabled: None,
151-
data: None,
152-
diagnostics: None,
153-
command: None,
154-
}
155-
}
156-
157-
pub fn ignore_this_rule_code_action(report: &DiagnosticReport, uri: &Uri) -> CodeAction {
158-
let rule_name = report.rule_name.as_ref();
159-
160-
CodeAction {
161-
title: rule_name.as_ref().map_or_else(
162-
|| "Disable oxlint for this file".into(),
163-
|s| format!("Disable {s} for this file"),
164-
),
165-
kind: Some(CodeActionKind::QUICKFIX),
166-
is_preferred: Some(false),
167-
edit: Some(WorkspaceEdit {
168-
#[expect(clippy::disallowed_types)]
169-
changes: Some(std::collections::HashMap::from([(
170-
uri.clone(),
171-
vec![TextEdit {
172-
range: Range {
173-
start: Position { line: 0, character: 0 },
174-
end: Position { line: 0, character: 0 },
175-
},
176-
new_text: rule_name.as_ref().map_or_else(
177-
|| "// oxlint-disable\n".into(),
178-
|s| format!("// oxlint-disable {s}\n"),
179-
),
180-
}],
181-
)])),
182-
..WorkspaceEdit::default()
183-
}),
184-
disabled: None,
185-
data: None,
186-
diagnostics: None,
187-
command: None,
188-
}
189-
}

crates/oxc_language_server/src/linter/error_with_position.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use crate::LSP_MAX_INT;
1313
pub struct DiagnosticReport {
1414
pub diagnostic: lsp_types::Diagnostic,
1515
pub fixed_content: PossibleFixContent,
16-
pub rule_name: Option<String>,
1716
}
1817

1918
#[derive(Debug, Clone)]
@@ -145,6 +144,5 @@ pub fn message_with_position_to_lsp_diagnostic_report(
145144
fixes.iter().map(fix_with_position_to_fix_content).collect(),
146145
),
147146
},
148-
rule_name: message.code.number.as_ref().map(std::string::ToString::to_string),
149147
}
150148
}

crates/oxc_language_server/src/linter/isolated_lint_handler.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ impl IsolatedLintHandler {
134134
data: None,
135135
},
136136
fixed_content: PossibleFixContent::None,
137-
rule_name: None,
138137
});
139138
}
140139
}

0 commit comments

Comments
 (0)