Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3747,6 +3747,10 @@ mod tests {
"Setting `windows-shell` expects an array value",
lsp::Range::at(0, 0, 1, 0),
)
.warning(
"`windows-shell` is deprecated, use `[windows]` attribute on `set shell` instead",
lsp::Range::at(0, 4, 0, 17),
)
.run();
}

Expand All @@ -3760,6 +3764,28 @@ mod tests {
echo \"foo\"
"
})
.warning(
"`windows-shell` is deprecated, use `[windows]` attribute on `set shell` instead",
lsp::Range::at(0, 4, 0, 17),
)
.run();
}

#[test]
fn settings_windows_shell_replacement() {
Test::new(indoc! {
"
set lists

[windows]
set shell := [\"powershell.exe\", \"-NoLogo\", \"-Command\"]
set windows-shell := [\"powershell.exe\", \"-NoLogo\", \"-Command\"]
"
})
.warning(
"`windows-shell` is deprecated, use `[windows]` attribute on `set shell` instead",
lsp::Range::at(4, 4, 4, 17),
)
.run();
}

Expand Down
6 changes: 3 additions & 3 deletions src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ pub enum Builtin<'a> {
aliases: &'a [&'a str],
kind: FunctionKind,
description: &'a str,
deprecated: Option<&'a str>,
deprecated: Option<Deprecation<'a>>,
},
Setting {
name: &'a str,
kind: SettingKind,
description: &'a str,
deprecated: Option<&'a str>,
deprecated: Option<Deprecation<'a>>,
},
}

Expand Down Expand Up @@ -250,7 +250,7 @@ mod tests {
aliases: &[],
kind: FunctionKind::Nullary,
description: "",
deprecated: Some("bar"),
deprecated: Some(Deprecation::Replacement("bar")),
}
.completion_items()
.into_iter()
Expand Down
19 changes: 13 additions & 6 deletions src/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -631,11 +631,12 @@ pub const BUILTINS: &[Builtin<'_>] = &[
kind: AttributeKind::Nullary,
description: indoc! {
"
Enable the recipe on Windows.
Enable a recipe or setting on Windows.

Part of the platform-gating family of attributes. When any
platform attribute is present, the recipe is only enabled when
one of the active platforms matches.
one of the active platforms matches. It can also specialize
`set shell` for Windows.

```just
[windows]
Expand Down Expand Up @@ -1307,7 +1308,7 @@ pub const BUILTINS: &[Builtin<'_>] = &[
variable is unset.
"
},
deprecated: Some("env"),
deprecated: Some(Deprecation::Replacement("env")),
},
Builtin::Function {
name: "env_var_or_default",
Expand All @@ -1321,7 +1322,7 @@ pub const BUILTINS: &[Builtin<'_>] = &[
`default` when the variable is unset.
"
},
deprecated: Some("env"),
deprecated: Some(Deprecation::Replacement("env")),
},
Builtin::Function {
name: "error",
Expand Down Expand Up @@ -2762,13 +2763,16 @@ pub const BUILTINS: &[Builtin<'_>] = &[
for a more flexible, version-agnostic alternative.
"
},
deprecated: Some("windows-shell"),
deprecated: Some(Deprecation::Replacement("windows-shell")),
},
Builtin::Setting {
name: "windows-shell",
kind: SettingKind::Array,
description: indoc! {
"
**Deprecated**: use the `[windows]` attribute on `set shell`
instead.

Set the command used to invoke recipes and evaluate backticks
on Windows.

Expand All @@ -2783,7 +2787,10 @@ pub const BUILTINS: &[Builtin<'_>] = &[
```
"
},
deprecated: None,
deprecated: Some(Deprecation::SettingAttribute {
attribute: "windows",
setting: "shell",
}),
},
Builtin::Setting {
name: "working-directory",
Expand Down
21 changes: 21 additions & 0 deletions src/deprecation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use super::*;

#[derive(Clone, Copy, Debug)]
pub enum Deprecation<'a> {
Replacement(&'a str),
SettingAttribute {
attribute: &'a str,
setting: &'a str,
},
}

impl Display for Deprecation<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Replacement(replacement) => write!(f, "`{replacement}`"),
Self::SettingAttribute { attribute, setting } => {
write!(f, "`[{attribute}]` attribute on `set {setting}`")
}
}
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub use {
dependency::Dependency,
dependency_argument::DependencyArgument,
dependency_phase::DependencyPhase,
deprecation::Deprecation,
diagnostic::Diagnostic,
document::Document,
error::Error,
Expand Down Expand Up @@ -70,6 +71,7 @@ mod count;
mod dependency;
mod dependency_argument;
mod dependency_phase;
mod deprecation;
mod diagnostic;
mod document;
mod error;
Expand Down
27 changes: 27 additions & 0 deletions src/quickfix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,31 @@ impl Quickfix {
title: format!("Replace `{}` with `{replacement}`", name.value),
}
}

#[must_use]
pub fn setting_attribute(
setting: &Setting,
document: &Document,
attribute: &str,
replacement: &str,
) -> Self {
let line = document
.content
.line(setting.range.start.line as usize)
.to_string();

let line = line.replacen(&setting.name.value, replacement, 1);

Self {
edits: vec![lsp::TextEdit {
range: setting.range,
new_text: format!("[{attribute}]\n{line}"),
}],
range: setting.name.range,
title: format!(
"Replace `{}` with `[{attribute}] set {replacement}`",
setting.name.value
),
}
}
}
28 changes: 28 additions & 0 deletions src/quickfixer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,34 @@ mod tests {
.run();
}

#[test]
fn replaces_windows_shell_setting() {
Test::new(
"set windows-shell := [\"powershell.exe\", \"-NoLogo\", \"-Command\"]\n",
)
.range(lsp::Range::at(0, 4, 0, 4))
.quickfix(Quickfix {
edits: vec![lsp::TextEdit {
range: lsp::Range::at(0, 0, 1, 0),
new_text:
"[windows]\nset shell := [\"powershell.exe\", \"-NoLogo\", \"-Command\"]\n"
.to_string(),
}],
range: lsp::Range::at(0, 4, 0, 17),
title: "Replace `windows-shell` with `[windows] set shell`".to_string(),
})
.run();
}

#[test]
fn skips_windows_shell_setting_when_replacement_exists() {
Test::new(
"[windows]\nset shell := [\"foo\"]\nset windows-shell := [\"bar\"]\n",
)
.range(lsp::Range::at(2, 4, 2, 4))
.run();
}

#[test]
fn skips_disabled_rules() {
let config = serde_json::from_value::<Config>(serde_json::json!({
Expand Down
8 changes: 4 additions & 4 deletions src/rule/deprecated_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ define_rule! {
let function_name = &function_call.name.value;

if let Some(Builtin::Function {
deprecated: Some(replacement),
deprecated: Some(deprecation),
..
}) = context.builtin_function(function_name.as_str())
{
diagnostics.push(Diagnostic::warning(
format!(
"`{function_name}` is deprecated, use `{replacement}` instead"
"`{function_name}` is deprecated, use {deprecation} instead"
),
function_call.name.range,
));
Expand All @@ -34,13 +34,13 @@ define_rule! {
let function_name = &function_call.name.value;

if let Some(Builtin::Function {
deprecated: Some(replacement),
deprecated: Some(Deprecation::Replacement(replacement)),
..
}) = context.builtin_function(function_name.as_str())
{
quickfixes.push(Quickfix::replacement(
&function_call.name,
replacement.to_string(),
*replacement,
));
}
}
Expand Down
38 changes: 30 additions & 8 deletions src/rule/deprecated_setting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ define_rule! {

for setting in context.settings() {
if let Some(Builtin::Setting {
deprecated: Some(replacement),
deprecated: Some(deprecation),
..
}) = context.builtin_setting(&setting.name.value)
{
diagnostics.push(Diagnostic::warning(
format!(
"`{}` is deprecated, use `{replacement}` instead",
"`{}` is deprecated, use {deprecation} instead",
setting.name.value
),
setting.name.range,
Expand All @@ -28,17 +28,39 @@ define_rule! {
},
quickfixes(context) {
let mut quickfixes = Vec::new();

for setting in context.settings() {
if let Some(Builtin::Setting {
deprecated: Some(replacement),
deprecated: Some(deprecation),
..
}) = context.builtin_setting(&setting.name.value)
{
quickfixes.push(Quickfix::replacement(
&setting.name,
replacement.to_string(),
));
let deprecation = *deprecation;

let quickfix = match deprecation {
Deprecation::Replacement(replacement) => {
Quickfix::replacement(&setting.name, replacement)
}
Deprecation::SettingAttribute {
attribute,
setting: replacement,
} => {
if context.settings().iter().any(|replacement_setting| {
replacement_setting.name.value == replacement
&& replacement_setting.has_attribute(attribute)
}) {
continue;
}

Quickfix::setting_attribute(
setting,
context.document(),
attribute,
replacement,
)
}
};

quickfixes.push(quickfix);
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/setting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ impl Setting {
range,
})
}

#[must_use]
pub fn has_attribute(&self, name: &str) -> bool {
self
.attributes
.iter()
.any(|attribute| attribute.name.value == name)
}
}

#[cfg(test)]
Expand Down
Loading