Add Cargo-style project discovery for Buck and Bazel Users
This feature requires the user to add a command that generates a `rust-project.json` from a set of files. Project discovery can be invoked in two ways:
1. At extension activation time, which includes the generated `rust-project.json` as part of the linkedProjects argument in `InitializeParams`.
2. Through a new command titled "rust-analyzer: Add current file to workspace", which makes use of a new, rust-analyzer-specific LSP request that adds the workspace without erasing any existing workspaces. Note that there is no mechanism to _remove_ workspaces other than "quit the rust-analyzer server".
Few notes:
- I think that the command-running functionality _could_ merit being placed into its own extension (and expose it via extension contribution points) to provide build-system idiomatic progress reporting and status handling, but I haven't (yet) made an extension that does this nor does Buck expose this sort of functionality.
- This approach would _just work_ for Bazel. I'll try and get the tool that's responsible for Buck integration open-sourced soon.
- On the testing side of things, I've used this in around my employer's Buck-powered monorepo and it's a nice experience. That being said, I can't think of an open-source repository where this can be tested in public, so you might need to trust me on this one.
I'd love to get feedback on:
- Naming of LSP extensions/new commands. I'm not too pleased with how "rust-analyzer: Add current file to workspace" is named, in that it's creating a _new_ workspace. I think that this command being added should be gated on `rust-analyzer.discoverProjectCommand` on being set, so I can add this in sequent commits.
- My Typescript. It's not particularly good.
- Suggestions on handling folders with _both_ Cargo and non-Cargo build systems and if I make activation a bit better.
(I previously tried to add this functionality entirely within rust-analyzer-the-LSP server itself, but matklad was right—an extension side approach is much, much easier.)
This feature requires the user to add a command that generates a
`rust-project.json` from a set of files. Project discovery can be invoked
in two ways:
1. At extension activation time, which includes the generated
`rust-project.json` as part of the linkedProjects argument in
InitializeParams
2. Through a new command titled "Add current file to workspace", which
makes use of a new, rust-analyzer specific LSP request that adds
the workspace without erasing any existing workspaces.
I think that the command-running functionality _could_ merit being
placed into its own extension (and expose it via extension contribution
points), if only provide build-system idiomatic progress reporting and
status handling, but I haven't (yet) made an extension that does this.
Beginning of MIR
This pull request introduces the initial implementation of MIR lowering and interpreting in Rust Analyzer.
The implementation of MIR has potential to bring several benefits:
- Executing a unit test without compiling it: This is my main goal. It can be useful for quickly testing code changes and print-debugging unit tests without the need for a full compilation (ideally in almost zero time, similar to languages like python and js). There is a probability that it goes nowhere, it might become slower than rustc, or it might need some unreasonable amount of memory, or we may fail to support a common pattern/function that make it unusable for most of the codes.
- Constant evaluation: MIR allows for easier and more correct constant evaluation, on par with rustc. If r-a wants to fully support the type system, it needs full const eval, which means arbitrary code execution, which needs MIR or something similar.
- Supporting more diagnostics: MIR can be used to detect errors, most famously borrow checker and lifetime errors, but also mutability errors and uninitialized variables, which can be difficult/impossible to detect in HIR.
- Lowering closures: With MIR we can find out closure capture modes, which is useful in detecting if a closure implements the `FnMut` or `Fn` traits, and calculating its size and data layout.
But the current PR implements no diagnostics and doesn't support closures. About const eval, I removed the old const eval code and it now uses the mir interpreter. Everything that is supported in stable rustc is either implemented or is super easy to implement. About interpreting unit tests, I added an experimental config, disabled by default, that shows a `pass` or `fail` on hover of unit tests (ideally it should be a button similar to `Run test` button, but I didn't figured out how to add them). Currently, no real world test works, due to missing features including closures, heap allocation, `dyn Trait` and ... so at this point it is only useful for me selecting what to implement next.
The implementation of MIR is based on the design of rustc, the data structures are almost copy paste (so it should be easy to migrate it to a possible future stable-mir), but the lowering and interpreting code is from me.
add openDocs command to context menu in VS Code extension
This adds the `openDocs` command to the VS Code context menu. I believe there are probably many user who are unaware of this command existing in the rust analyzer extension, and that this should enhance the discoverability of the command. Additionally, even if people are aware of this capability, it's helpful to have this in the context menu anyway; for example, one might forget the name of the command, or the keybinding they have assigned to it. I think that opening docs is a common enough action to warrant the extra line added to the context menu.
This makes a few other small changes as well. There are two minor style changes to increase style consistency. First, it changes the titles of the two commands that the rust analyzer extension will contribute to the context menu to title case. All standard VS Code commands that appear in the context menu are in title case. Second, it shortens the title of the `openDocs` command from `Open docs under cursor` to `Open Docs`. The implicit assumption in the standard VS Code context menu command titles is that the action applies to the symbol under the cursor: `Go to Definition`, `Find All References`, etc. Note that since these are changes to the command titles, rather than the command names themselves, these changes will not break any users' existing keybindings for these commands.
Second, this adds further restrictions to the `where` clauses of the two commands that the rust analyzer extension will contribute to the context menu, so that the two commands will appear in the context menu only when in a Rust project **and** within a Rust file. Say you have a Python or bash script inside your Rust project. Having these commands appear in the context menu when you right click a symbol in such a non-Rust file is extraneous and potentially confusing.
![demonstration](https://user-images.githubusercontent.com/6609145/219976062-b46ab21b-5753-48f5-a1da-562566cae71c.gif)
fix: Suppress extra indent after the end of field and function chains
(spurred on by <https://github.com/rust-lang/rust-analyzer/issues/4182#issuecomment-671275652>)
Caveat that this doesn't work for after tail expressions, although there shouldn't be anything after those anyways.
This also complicates when to reload the language configuration by nature of now always having a language configuration applicable.
Examples of indentation fixes:
```rs
fn main() {
println!("Hello!"); // < enter here!
// ... indents down here
fs::read_to_string("soup") // < enter here!
// ... still indents down here :(
.map(|_| ())
.map(|_| ()) // < enter here!
// ... still indents down here :D
.map_err(|_| ())
.unwrap(); // < enter here!
// ... indents down here :D
// ... and subsequent enters stay at the same indent
0.0f64
.to_radians()
.to_radians()
.to_radians() // force semi on a new line
; // < enter here!
// ... indents down here :D
}
fn tail_end() -> i32 {
0i32.wrapping_abs()
.wrapping_abs()
.wrapping_abs()
.wrapping_abs() // < enter here!
// ... still indents here 🤷
}
```
minor: Explicitly disable the rust-analyzer extension in untrusted workspaces
This is the default, but its always better to be explicit here + we can add a small note as to why.
Use ANSI control characters to display text decorations matching the
VScode terminal theme, and strip them out when providing text content
for rustc diagnostics.
This adds the small `anser` library to parse the control codes, and it
also supports HTML output so it should be fairly easy to switch to a
rendered HTML/webview implementation if desired.
Rename `checkOnSave` settings to `check`
Now that flychecks can be triggered without saving the setting name doesn't make that much sense anymore. This PR renames it to just `check`, but keeps `checkOnSave` as the enabling setting.
feat: add the ability to limit the number of threads launched by `main_loop`
## Motivation
`main_loop` defaults to launch as many threads as cpus in one machine. When developing on multi-core remote servers on multiple projects, this will lead to thousands of idle threads being created. This is very annoying when one wants check whether his program under developing is running correctly via `htop`.
<img width="756" alt="image" src="https://user-images.githubusercontent.com/41831480/206656419-fa3f0dd2-e554-4f36-be1b-29d54739930c.png">
## Contribution
This patch introduce the configuration option `rust-analyzer.numThreads` to set the desired thread number used by the main thread pool.
This should have no effects on the performance as not all threads are actually used.
<img width="1325" alt="image" src="https://user-images.githubusercontent.com/41831480/206656834-fe625c4c-b993-4771-8a82-7427c297fd41.png">
## Demonstration
The following is a snippet of `lunarvim` configuration using my own build.
```lua
vim.list_extend(lvim.lsp.automatic_configuration.skipped_servers, { "rust_analyzer" })
require("lvim.lsp.manager").setup("rust_analyzer", {
cmd = { "env", "RA_LOG=debug", "RA_LOG_FILE=/tmp/ra-test.log",
"/home/jlhu/Projects/rust-analyzer/target/debug/rust-analyzer",
},
init_options = {
numThreads = 4,
},
settings = {
cachePriming = {
numThreads = 8,
},
},
})
```
## Limitations
The `numThreads` can only be modified via `initializationOptions` in early initialisation because everything has to wait until the thread pool starts including the dynamic settings modification support.
The `numThreads` also does not reflect the end results of how many threads is actually created, because I have not yet tracked down everything that spawns threads.
Use diagnostic code as link to full message
fixes#13823 by adding a vscode setting that will keeping the existing diagnostic code and use it as a link to the full compiler error message.
While I was there I also fixed `index` to fallback to `rendered.length` to make the previewRustcOutput feature work.
feat: Add an option to hide adjustment hints outside of `unsafe` blocks and functions
As the title suggests: this PR adds an option (namely `rust-analyzer.inlayHints.expressionAdjustmentHints.hideOutsideUnsafe`) that allows to hide adjustment hints outside of `unsafe` blocks and functions:
![2022-12-21_23-11](https://user-images.githubusercontent.com/38225716/208986376-d607de62-8290-4e16-b7fe-15b762dc5f60.png)
Requested by `@BoxyUwU` <3
Support multiple targets for checkOnSave (in conjunction with cargo 1.64.0+)
This PR adds support for the ability to pass multiple `--target` flags when using
`cargo` 1.64.0+.
## Questions
I needed to change the type of two configurations options, but I did not plurialize the names to
avoid too much churn, should I ?
## Zulip thread
https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer/topic/Issue.2013282.20.28supporting.20multiple.20targets.20with.201.2E64.2B.29
## Example
To see it working, on a macOS machine:
```sh
$ cd /tmp
$ cargo new cargo-multiple-targets-support-ra-test
$ cd !$
$ mkdir .cargo
$ echo '
[build]
target = [
"aarch64-apple-darwin",
"x86_64-apple-darwin",
]
' > .cargo/config.toml
$ echo '
fn main() {
#[cfg(all(target_arch = "aarch64", target_os = "macos"))]
{
let a = std::fs::read_to_string("/tmp/test-read");
}
#[cfg(all(target_arch = "x86_64", target_os = "macos"))]
{
let a = std::fs::read_to_string("/tmp/test-read");
}
#[cfg(all(target_arch = "x86_64", target_os = "windows"))]
{
let a = std::fs::read_to_string("/tmp/test-read");
}
}
' > src/main.rs
# launch your favorite editor with the version of RA from this PR
#
# You should see warnings under the first two `let a = ...` but not the third
```
## Screen
![Two panes of a terminal emulator, on the left pane is the main.rs file described above, with warnings for the first two let a = declaration, on the right pane is a display of the .cargo/config.toml, an ls of the current files in the directory and a call to cargo build to show the same warnings as in the editor on the left pane](https://user-images.githubusercontent.com/7951708/192122707-7a00606a-e581-4534-b9d5-b81c92694e8e.png)
Helps with #13282
feat: add config for inserting must_use in `generate_enum_as_method`
Should fix#13312
Didn't add a test because I was not sure on how to add test for a specific configuration option, tried to look for the usages for other `AssistConfig` variants but couldn't find any in `tests`. If there is a way to test this, do point me towards it.
I tried to extract the formatting string as a common `template_string` and only have if-else for that, but it didn't compile :(
Also it seems these tests are failing:
```
test config::tests::generate_config_documentation ... FAILED
test config::tests::generate_package_json_config ... FAILED
```
Can you also point me to how to correct these 😅 ( I guess there is some command to automatically generate these? )