diff --git a/Cargo.lock b/Cargo.lock index 1b2281def1c20..e20ef34ed0571 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -642,7 +642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -651,7 +651,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1016,7 +1016,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.60.2", + "windows-sys 0.61.0", ] [[package]] @@ -1108,7 +1108,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.0", ] [[package]] @@ -1699,7 +1699,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1763,7 +1763,7 @@ dependencies = [ "portable-atomic", "portable-atomic-util", "serde_core", - "windows-sys 0.52.0", + "windows-sys 0.61.0", ] [[package]] @@ -3005,6 +3005,7 @@ dependencies = [ "serde", "serde_json", "similar", + "supports-hyperlinks", "tempfile", "thiserror 2.0.17", "tracing", @@ -3569,7 +3570,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.61.0", ] [[package]] @@ -3926,6 +3927,12 @@ dependencies = [ "syn", ] +[[package]] +name = "supports-hyperlinks" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804f44ed3c63152de6a9f90acbea1a110441de43006ea51bcce8f436196a288b" + [[package]] name = "syn" version = "2.0.110" @@ -3964,7 +3971,7 @@ dependencies = [ "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.61.0", ] [[package]] @@ -5013,7 +5020,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fe1c6d48cce77..ae0432817fbf0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -173,6 +173,7 @@ snapbox = { version = "0.6.0", features = [ static_assertions = "1.1.0" strum = { version = "0.27.0", features = ["strum_macros"] } strum_macros = { version = "0.27.0" } +supports-hyperlinks = { version = "3.1.0" } syn = { version = "2.0.55" } tempfile = { version = "3.9.0" } test-case = { version = "3.3.1" } diff --git a/crates/ruff_annotate_snippets/src/renderer/mod.rs b/crates/ruff_annotate_snippets/src/renderer/mod.rs index 7d3050bf0bd04..3d85e2542e99b 100644 --- a/crates/ruff_annotate_snippets/src/renderer/mod.rs +++ b/crates/ruff_annotate_snippets/src/renderer/mod.rs @@ -155,6 +155,11 @@ impl Renderer { self } + pub const fn hyperlink(mut self, hyperlink: bool) -> Self { + self.stylesheet.hyperlink = hyperlink; + self + } + /// Set the string used for when a long line is cut. /// /// The default is `...` (three `U+002E` characters). diff --git a/crates/ruff_db/Cargo.toml b/crates/ruff_db/Cargo.toml index 25f0024b80fdb..e8af17971d537 100644 --- a/crates/ruff_db/Cargo.toml +++ b/crates/ruff_db/Cargo.toml @@ -42,6 +42,7 @@ schemars = { workspace = true, optional = true } serde = { workspace = true, optional = true } serde_json = { workspace = true, optional = true } similar = { workspace = true } +supports-hyperlinks = { workspace = true } thiserror = { workspace = true } tracing = { workspace = true } tracing-subscriber = { workspace = true, optional = true } diff --git a/crates/ruff_db/src/diagnostic/render/full.rs b/crates/ruff_db/src/diagnostic/render/full.rs index 0784297755481..bbc71f93d04b2 100644 --- a/crates/ruff_db/src/diagnostic/render/full.rs +++ b/crates/ruff_db/src/diagnostic/render/full.rs @@ -49,7 +49,8 @@ impl<'a> FullRenderer<'a> { .help(stylesheet.help) .line_no(stylesheet.line_no) .emphasis(stylesheet.emphasis) - .none(stylesheet.none); + .none(stylesheet.none) + .hyperlink(stylesheet.hyperlink); for diag in diagnostics { let resolved = Resolved::new(self.resolver, diag, self.config); @@ -703,52 +704,7 @@ print() env.show_fix_status(true); env.fix_applicability(Applicability::DisplayOnly); - insta::assert_snapshot!(env.render_diagnostics(&diagnostics), @r" - error[unused-import][*]: `os` imported but unused - --> notebook.ipynb:cell 1:2:8 - | - 1 | # cell 1 - 2 | import os - | ^^ - | - help: Remove unused import: `os` - ::: cell 1 - 1 | # cell 1 - - import os - - error[unused-import][*]: `math` imported but unused - --> notebook.ipynb:cell 2:2:8 - | - 1 | # cell 2 - 2 | import math - | ^^^^ - 3 | - 4 | print('hello world') - | - help: Remove unused import: `math` - ::: cell 2 - 1 | # cell 2 - - import math - 2 | - 3 | print('hello world') - - error[unused-variable][*]: Local variable `x` is assigned to but never used - --> notebook.ipynb:cell 3:4:5 - | - 2 | def foo(): - 3 | print() - 4 | x = 1 - | ^ - | - help: Remove assignment to unused variable `x` - ::: cell 3 - 1 | # cell 3 - 2 | def foo(): - 3 | print() - - x = 1 - 4 | - note: This is an unsafe fix and may change runtime behavior - "); + insta::assert_snapshot!(env.render_diagnostics(&diagnostics)); } #[test] @@ -768,31 +724,7 @@ print() } *fix = Fix::unsafe_edits(edits.remove(0), edits); - insta::assert_snapshot!(env.render(&diagnostic), @r" - error[unused-import][*]: `os` imported but unused - --> notebook.ipynb:cell 1:2:8 - | - 1 | # cell 1 - 2 | import os - | ^^ - | - help: Remove unused import: `os` - ::: cell 1 - 1 | # cell 1 - - import os - ::: cell 2 - 1 | # cell 2 - - import math - 2 | - 3 | print('hello world') - ::: cell 3 - 1 | # cell 3 - 2 | def foo(): - 3 | print() - - x = 1 - 4 | - note: This is an unsafe fix and may change runtime behavior - "); + insta::assert_snapshot!(env.render(&diagnostic)); } /// Carriage return (`\r`) is a valid line-ending in Python, so we should normalize this to a diff --git a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__full__tests__notebook_output_with_diff.snap b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__full__tests__notebook_output_with_diff.snap new file mode 100644 index 0000000000000..f35f559a544e6 --- /dev/null +++ b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__full__tests__notebook_output_with_diff.snap @@ -0,0 +1,48 @@ +--- +source: crates/ruff_db/src/diagnostic/render/full.rs +expression: env.render_diagnostics(&diagnostics) +--- +error[unused-import][*]: `os` imported but unused + --> notebook.ipynb:cell 1:2:8 + | +1 | # cell 1 +2 | import os + | ^^ + | +help: Remove unused import: `os` + ::: cell 1 +1 | # cell 1 + - import os + +error[unused-import][*]: `math` imported but unused + --> notebook.ipynb:cell 2:2:8 + | +1 | # cell 2 +2 | import math + | ^^^^ +3 | +4 | print('hello world') + | +help: Remove unused import: `math` + ::: cell 2 +1 | # cell 2 + - import math +2 | +3 | print('hello world') + +error[unused-variable][*]: Local variable `x` is assigned to but never used + --> notebook.ipynb:cell 3:4:5 + | +2 | def foo(): +3 | print() +4 | x = 1 + | ^ + | +help: Remove assignment to unused variable `x` + ::: cell 3 +1 | # cell 3 +2 | def foo(): +3 | print() + - x = 1 +4 | +note: This is an unsafe fix and may change runtime behavior diff --git a/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__full__tests__notebook_output_with_diff_spanning_cells.snap b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__full__tests__notebook_output_with_diff_spanning_cells.snap new file mode 100644 index 0000000000000..63a920eff65ce --- /dev/null +++ b/crates/ruff_db/src/diagnostic/render/snapshots/ruff_db__diagnostic__render__full__tests__notebook_output_with_diff_spanning_cells.snap @@ -0,0 +1,27 @@ +--- +source: crates/ruff_db/src/diagnostic/render/full.rs +expression: env.render(&diagnostic) +--- +error[unused-import][*]: `os` imported but unused + --> notebook.ipynb:cell 1:2:8 + | +1 | # cell 1 +2 | import os + | ^^ + | +help: Remove unused import: `os` + ::: cell 1 +1 | # cell 1 + - import os + ::: cell 2 +1 | # cell 2 + - import math +2 | +3 | print('hello world') + ::: cell 3 +1 | # cell 3 +2 | def foo(): +3 | print() + - x = 1 +4 | +note: This is an unsafe fix and may change runtime behavior diff --git a/crates/ruff_db/src/diagnostic/stylesheet.rs b/crates/ruff_db/src/diagnostic/stylesheet.rs index ba7391549e843..c86ad430b6244 100644 --- a/crates/ruff_db/src/diagnostic/stylesheet.rs +++ b/crates/ruff_db/src/diagnostic/stylesheet.rs @@ -97,6 +97,8 @@ impl DiagnosticStylesheet { /// Default terminal styling pub fn styled() -> Self { let bright_blue = AnsiColor::BrightBlue.on_default(); + + let hyperlink = supports_hyperlinks::supports_hyperlinks(); Self { error: AnsiColor::BrightRed.on_default().effects(Effects::BOLD), warning: AnsiColor::Yellow.on_default().effects(Effects::BOLD), @@ -112,7 +114,7 @@ impl DiagnosticStylesheet { deletion: AnsiColor::Red.on_default(), insertion_line_no: AnsiColor::Green.on_default().effects(Effects::BOLD), deletion_line_no: AnsiColor::Red.on_default().effects(Effects::BOLD), - hyperlink: true, + hyperlink, } }