From 1513a9f4b0b9284981cda72a5f68c94c0cb5d54e Mon Sep 17 00:00:00 2001
From: Sysix <3897725+Sysix@users.noreply.github.com>
Date: Sun, 5 Apr 2026 13:32:23 +0000
Subject: [PATCH] feat(oxlint/lsp): show note field for lsp diagnostic (#20983)
closes https://github.com/oxc-project/oxc-intellij-plugin/issues/423
Screenshot:
---
apps/oxlint/src/lsp/error_with_position.rs | 29 +++++++++++--------
.../fixtures_lsp_cross_module@dep-a.ts.snap | 2 +-
...cross_module_extended_config@dep-a.ts.snap | 2 +-
...nfig@dep-a.ts_folder__folder-dep-a.ts.snap | 2 +-
...lsp_ts_path_alias@deep__src__dep-a.ts.snap | 2 +-
5 files changed, 21 insertions(+), 16 deletions(-)
diff --git a/apps/oxlint/src/lsp/error_with_position.rs b/apps/oxlint/src/lsp/error_with_position.rs
index 6ebbc5160dc5c..650f07b96a1d2 100644
--- a/apps/oxlint/src/lsp/error_with_position.rs
+++ b/apps/oxlint/src/lsp/error_with_position.rs
@@ -93,23 +93,28 @@ pub fn message_to_lsp_diagnostic(
.and_then(|url| url.parse().ok())
.map(|href| CodeDescription { href });
- let diagnostic_message = match &message.error.help {
- Some(help) => {
- let main_msg = &message.error.message;
- let mut msg = String::with_capacity(main_msg.len() + help.len() + 7);
- msg.push_str(main_msg);
- msg.push_str("\nhelp: ");
- msg.push_str(help);
- msg
- }
- None => message.error.message.to_string(),
- };
+ let mut diagnostic_message = String::with_capacity(
+ message.error.message.len()
+ + message.error.help.as_ref().map_or(0, |h| h.len() + 7) // "help: " prefix
+ + message.error.note.as_ref().map_or(0, |n| n.len() + 7), // "note: " prefix
+ );
+
+ diagnostic_message.push_str(&message.error.message);
+ if let Some(help) = &message.error.help {
+ diagnostic_message.push_str("\nhelp: ");
+ diagnostic_message.push_str(help);
+ }
+
+ if let Some(note) = &message.error.note {
+ diagnostic_message.push_str("\nnote: ");
+ diagnostic_message.push_str(note);
+ }
// 1) Use `fixed_content.message` if it exists
// 2) Try to parse the report diagnostic message
// 3) Fallback to "Fix this problem"
let alternative_fix_title: Cow<'static, str> =
- if let Some(code) = diagnostic_message.split(':').next() {
+ if let Some(code) = message.error.message.split(':').next() {
format!("Fix this {code} problem").into()
} else {
std::borrow::Cow::Borrowed("Fix this problem")
diff --git a/apps/oxlint/src/lsp/snapshots/fixtures_lsp_cross_module@dep-a.ts.snap b/apps/oxlint/src/lsp/snapshots/fixtures_lsp_cross_module@dep-a.ts.snap
index 8edad88f859d3..e87b85fc07b68 100644
--- a/apps/oxlint/src/lsp/snapshots/fixtures_lsp_cross_module@dep-a.ts.snap
+++ b/apps/oxlint/src/lsp/snapshots/fixtures_lsp_cross_module@dep-a.ts.snap
@@ -9,7 +9,7 @@ File URI: file:///fixtures/lsp/cross_module/dep-a.ts
code: "eslint-plugin-import(no-cycle)"
code_description.href: "https://oxc.rs/docs/guide/usage/linter/rules/import/no-cycle.html"
-message: "Dependency cycle detected\nhelp: Refactor to remove the cycle. Consider extracting shared code into a separate module that both files can import."
+message: "Dependency cycle detected\nhelp: Refactor to remove the cycle. Consider extracting shared code into a separate module that both files can import.\nnote: These paths form a cycle:\n╭──▶ ./dep-b.ts (fixtures/lsp/cross_module/dep-b.ts)\n│ ⬇ imports\n│ ./dep-a.ts (fixtures/lsp/cross_module/dep-a.ts)\n╰─────────╯ imports the current file"
range: Range { start: Position { line: 1, character: 18 }, end: Position { line: 1, character: 30 } }
related_information[0].message: ""
related_information[0].location.uri: "file:///fixtures/lsp/cross_module/dep-a.ts"
diff --git a/apps/oxlint/src/lsp/snapshots/fixtures_lsp_cross_module_extended_config@dep-a.ts.snap b/apps/oxlint/src/lsp/snapshots/fixtures_lsp_cross_module_extended_config@dep-a.ts.snap
index dd83909e929ad..bdde16d1c06da 100644
--- a/apps/oxlint/src/lsp/snapshots/fixtures_lsp_cross_module_extended_config@dep-a.ts.snap
+++ b/apps/oxlint/src/lsp/snapshots/fixtures_lsp_cross_module_extended_config@dep-a.ts.snap
@@ -9,7 +9,7 @@ File URI: file:///fixtures/lsp/cross_module_extended_config/dep-a.ts
code: "eslint-plugin-import(no-cycle)"
code_description.href: "https://oxc.rs/docs/guide/usage/linter/rules/import/no-cycle.html"
-message: "Dependency cycle detected\nhelp: Refactor to remove the cycle. Consider extracting shared code into a separate module that both files can import."
+message: "Dependency cycle detected\nhelp: Refactor to remove the cycle. Consider extracting shared code into a separate module that both files can import.\nnote: These paths form a cycle:\n╭──▶ ./dep-b.ts (fixtures/lsp/cross_module_extended_config/dep-b.ts)\n│ ⬇ imports\n│ ./dep-a.ts (fixtures/lsp/cross_module_extended_config/dep-a.ts)\n╰─────────╯ imports the current file"
range: Range { start: Position { line: 1, character: 18 }, end: Position { line: 1, character: 30 } }
related_information[0].message: ""
related_information[0].location.uri: "file:///fixtures/lsp/cross_module_extended_config/dep-a.ts"
diff --git a/apps/oxlint/src/lsp/snapshots/fixtures_lsp_cross_module_nested_config@dep-a.ts_folder__folder-dep-a.ts.snap b/apps/oxlint/src/lsp/snapshots/fixtures_lsp_cross_module_nested_config@dep-a.ts_folder__folder-dep-a.ts.snap
index edee751b77d7b..fd2623a9d8f28 100644
--- a/apps/oxlint/src/lsp/snapshots/fixtures_lsp_cross_module_nested_config@dep-a.ts_folder__folder-dep-a.ts.snap
+++ b/apps/oxlint/src/lsp/snapshots/fixtures_lsp_cross_module_nested_config@dep-a.ts_folder__folder-dep-a.ts.snap
@@ -19,7 +19,7 @@ File URI: file:///fixtures/lsp/cross_module_nested_config/folder/folde
code: "eslint-plugin-import(no-cycle)"
code_description.href: "https://oxc.rs/docs/guide/usage/linter/rules/import/no-cycle.html"
-message: "Dependency cycle detected\nhelp: Refactor to remove the cycle. Consider extracting shared code into a separate module that both files can import."
+message: "Dependency cycle detected\nhelp: Refactor to remove the cycle. Consider extracting shared code into a separate module that both files can import.\nnote: These paths form a cycle:\n╭──▶ ./folder-dep-b.ts (fixtures/lsp/cross_module_nested_config/folder/folder-dep-b.ts)\n│ ⬇ imports\n│ ./folder-dep-a.ts (fixtures/lsp/cross_module_nested_config/folder/folder-dep-a.ts)\n╰─────────╯ imports the current file"
range: Range { start: Position { line: 1, character: 18 }, end: Position { line: 1, character: 37 } }
related_information[0].message: ""
related_information[0].location.uri: "file:///fixtures/lsp/cross_module_nested_config/folder/folder-dep-a.ts"
diff --git a/apps/oxlint/src/lsp/snapshots/fixtures_lsp_ts_path_alias@deep__src__dep-a.ts.snap b/apps/oxlint/src/lsp/snapshots/fixtures_lsp_ts_path_alias@deep__src__dep-a.ts.snap
index 790f8d33c5669..2a9758979fa9e 100644
--- a/apps/oxlint/src/lsp/snapshots/fixtures_lsp_ts_path_alias@deep__src__dep-a.ts.snap
+++ b/apps/oxlint/src/lsp/snapshots/fixtures_lsp_ts_path_alias@deep__src__dep-a.ts.snap
@@ -9,7 +9,7 @@ File URI: file:///fixtures/lsp/ts_path_alias/deep/src/dep-a.ts
code: "eslint-plugin-import(no-cycle)"
code_description.href: "https://oxc.rs/docs/guide/usage/linter/rules/import/no-cycle.html"
-message: "Dependency cycle detected\nhelp: Refactor to remove the cycle. Consider extracting shared code into a separate module that both files can import."
+message: "Dependency cycle detected\nhelp: Refactor to remove the cycle. Consider extracting shared code into a separate module that both files can import.\nnote: These paths form a cycle:\n╭──▶ @/dep-b (fixtures/lsp/ts_path_alias/deep/src/dep-b.ts)\n│ ⬇ imports\n│ ./dep-a.ts (fixtures/lsp/ts_path_alias/deep/src/dep-a.ts)\n╰─────────╯ imports the current file"
range: Range { start: Position { line: 1, character: 18 }, end: Position { line: 1, character: 27 } }
related_information[0].message: ""
related_information[0].location.uri: "file:///fixtures/lsp/ts_path_alias/deep/src/dep-a.ts"