Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add VSCode command to show the rustc --explain EXXXX output #14280

Open
ivangabriele opened this issue Mar 8, 2023 · 16 comments
Open

Add VSCode command to show the rustc --explain EXXXX output #14280

ivangabriele opened this issue Mar 8, 2023 · 16 comments
Labels
A-diagnostics diagnostics / error reporting C-feature Category: feature request

Comments

@ivangabriele
Copy link

Here is a user story example:

  1. I use VSCode.
  2. I have a compilation (analysis) error.
  3. This error has an explanation code (For more information about this error, try `rustc --explain EXXXX`.).
  4. I open the command palette and run the command rust-analyzer: Explain.
  5. It opens a new tab containing the rustc --explain EXXXX output.

There are other considerations to take into account:

  • multiple errors
  • (rather?) add it in code actions
  • how would that reflect in other IDEs/text editors?

If this feature is acceptable (and once the specs would be agreed upon), I could try to contribute by working on it but I must warn that I'm a beginner in Rust, so that would take some time.

@ivangabriele ivangabriele added the C-feature Category: feature request label Mar 8, 2023
@ivangabriele ivangabriele changed the title Add command to show the rustc --explain EXXXX output Add editor command to show the rustc --explain EXXXX output Mar 8, 2023
@lnicola lnicola added the A-diagnostics diagnostics / error reporting label Mar 8, 2023
@Veykril
Copy link
Member

Veykril commented Mar 8, 2023

So we kind of have this already in a sense. In editors other than VSCode if the editor exposes the error link they can already get redirected to the explanation webpage of the error code. In VSCode we overwrite it for the diagnostics view, but I think it would make sense to make the error code in that view clickable and either have that be a link to the explanation page on the rust lang website or maybe show a hover with it.
image

@bjorn3
Copy link
Member

bjorn3 commented Mar 8, 2023

but I think it would make sense to make the error code in that view clickable

Since rust-lang/rust#107838 rustc itself actually does this in terminals supporting it when using -Zterminal-urls.

@ivangabriele
Copy link
Author

ivangabriele commented Mar 8, 2023

@Veykril Oh that seem easier to integrate it like that then. From what I understand it would "only" require to touch editors/code TS code to achieve that?

For the code action and/or tooltip link, I wonder if this error code is available as a specific prop in TS reflecting rustc code or if it must be "regexed" out? (I'm looking at the codebase right now to check that).

As for the command palette command, it has the advantage to allow custom keybindings for the end-user. But I have no idea if most other users would find that useful or not.

@ivangabriele ivangabriele changed the title Add editor command to show the rustc --explain EXXXX output Add VSCode command to show the rustc --explain EXXXX output Mar 8, 2023
@Veykril
Copy link
Member

Veykril commented Mar 8, 2023

We can also have both, that is a command as you described as well as the link in the diagnostics view.

Both of these things can be fully done in the client only, so no need to touch the server for this. For the command you'd need to fetch the current diagnostics and filter for the ones that apply to the cursor position, then you can probably extract the error code (link) from there.

@ivangabriele
Copy link
Author

@Veykril That's what I guessed looking at the code, I'll try to make a first poke locally to see if I'm able to make that work.

@ivangabriele
Copy link
Author

ivangabriele commented Mar 11, 2023

@Veykril I have an issue:

When I debug this code :

fn main() {
    let a = "a";

    a = "b";
}

the cli debugger output this error with an explain link:

error[E0384]: cannot assign twice to immutable variable `a`
 --> src/main.rs:4:5
  |
2 |     let a = "a";
  |         -
  |         |
  |         first assignment to `a`
  |         help: consider making this binding mutable: `mut a`
3 |
4 |     a = "b";
  |     ^^^^^^^ cannot assign twice to immutable variable

For more information about this error, try `rustc --explain E0384`.

but when I log the diagnostic in handleDiagnostics() (client.ts file), I receive this object:

ProtocolDiagnostic {
  range: n { c: p { c: 3, e: 4 }, e: p { c: 3, e: 11 } },
  message: 'cannot mutate immutable variable `a`',
  severity: 0,
  data: undefined,
  hasDiagnosticCode: false,
  code: {
    value: 'need-mut',
    target: f {
      scheme: 'https',
      authority: 'rust-analyzer.github.io',
      path: '/manual.html',
      query: '',
      fragment: 'need-mut',
      _formatted: null,
      _fsPath: null
    }
  },
  source: 'rust-analyzer'
}

I don't have any error link there. I thought errorCode was something but it's false (I may suggest to rename that to hasErrorCore in my PR).

I also wonder if the server uses the user rustc version or an custom version since even the message is different. Or maybe original errors are transformed somewhere?

@bjorn3
Copy link
Member

bjorn3 commented Mar 11, 2023

That diagnostic looks like it comes from rust-analyzer itself (source is rust-analyzer, not rustc). There should be a second diagnostic coming from rustc if you saved.

@lnicola
Copy link
Member

lnicola commented Mar 11, 2023

You can see it here:

        {
            "range": {
                "start": {
                    "line": 2,
                    "character": 4
                },
                "end": {
                    "line": 2,
                    "character": 11
                }
            },
            "severity": 1,
            "code": "E0384",
            "codeDescription": {
                "href": "https://doc.rust-lang.org/error-index.html#E0384"
            },
            "source": "rustc",
            "message": "cannot assign twice to immutable variable `a`\ncannot assign twice to immutable variable",
            "relatedInformation": [
                {
                    "location": {
                        "uri": "file:///home/grayshade/Projects/hello/src/main.rs",
                        "range": {
                            "start": {
                                "line": 1,
                                "character": 8
                            },
                            "end": {
                                "line": 1,
                                "character": 9
                            }
                        }
                    },
                    "message": "first assignment to `a`"
                },
                {
                    "location": {
                        "uri": "file:///home/grayshade/Projects/hello/src/main.rs",
                        "range": {
                            "start": {
                                "line": 1,
                                "character": 8
                            },
                            "end": {
                                "line": 1,
                                "character": 9
                            }
                        }
                    },
                    "message": "consider making this binding mutable: `mut a`"
                }
            ],
            "data": {
                "rendered": "\u001b[0m\u001b[1m\u001b[38;5;9merror[E0384]\u001b[0m\u001b[0m\u001b[1m: cannot assign twice to immutable variable `a`\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m--> \u001b[0m\u001b[0msrc/main.rs:3:5\u001b[0m\n\u001b[0m  \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;12m2\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m    let a = \"a\";\u001b[0m\n\u001b[0m  \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m        \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m-\u001b[0m\n\u001b[0m  \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m        \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\n\u001b[0m  \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m        \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12mfirst assignment to `a`\u001b[0m\n\u001b[0m  \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m        \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12mhelp: consider making this binding mutable: `mut a`\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;12m3\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m    a = \"b\";\u001b[0m\n\u001b[0m  \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m| \u001b[0m\u001b[0m    \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9m^^^^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;9mcannot assign twice to immutable variable\u001b[0m\n\n"
            }
        },

The compiler even gives us the explanation message, but there's no place for us to put it (data isn't really designed for this).

@ivangabriele
Copy link
Author

ivangabriele commented Mar 11, 2023

@lnicola How did you log this (I saw the data.rendered is used when it exists in handleDiagnostics() iterator).

@lnicola
Copy link
Member

lnicola commented Mar 11, 2023

"rust-analyzer.trace.server": "verbose" in the Code settings.

@ivangabriele
Copy link
Author

I think I will need some help to know how to pass/access this data in the client.

@Veykril
Copy link
Member

Veykril commented Mar 16, 2023

What exactly are you tackling now, what data you you want to acess

@ivangabriele
Copy link
Author

ivangabriele commented Mar 17, 2023

@Veykril I just need to access the code & codeDescription props in the output above. I may not even need the codeDescription since I think the URL is always `https://doc.rust-lang.org/error-index.html#${code}`.

My goal is to use this code in order to provide a VSCode command (for keybinding) as well as a code action to open this URL for each error that provides one. If I can access this prop, I should be able to handle the integration all by myself ^^.

@Veykril
Copy link
Member

Veykril commented Mar 17, 2023

I don;t quite see the problem I think, you have that information on hand in the handleDiagnostics middleware that you already found no?

@ivangabriele
Copy link
Author

ivangabriele commented Mar 17, 2023

@Veykril No actually, these are the 3 values I get from handleDiagnostics():

image

Enabling "rust-analyzer.trace.server": "verbose" doesn't change that (and I don't think this option is intended to change that part anyway, but rather the Rust Analyzer Language Server Trace output).

I even tried enabling rust-analyzer.diagnostics.useRustcErrorCode and rust-analyzer.diagnostics.previewRustcOutput to see, but it didn't change that part either. It just changes the preview and errorCode values to true.

@Veykril
Copy link
Member

Veykril commented Mar 17, 2023

That's a r-a native diagnostic, those are not the same as the one's the compiler emits. You need save a file for r-a to invoke cargo check, those diagnostics produced then will have the things you are looking for (this won't work if checkOnSave is disabled though)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics diagnostics / error reporting C-feature Category: feature request
Projects
None yet
Development

No branches or pull requests

4 participants