Open jeromegn opened 3 years ago
Going to be challenging, but leaving this open for ideas and discussion!
I think the issue with rust-analyser would need to be done within rust-analyser maybe by handling .ers files specially (since I think that's an extension rust-script can use for scripts by association)
I had a quick look at how debugging might work (such as breakpoints)
The debugger extension would need to run something like the below but automatically switch out the program field with the output from rust-script and also maybe add in a sourceMap entry to map the original source script to the one in the build directory
{
"name": "Launch2",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/target/debug/example.exe",
"args": [],
"cwd": "${workspaceFolder}",
"stopOnEntry": false,
"sourceLanguages": ["rust"],
},
I was looking into this literally this evening, and it looks to me like the easiest way to start is by forking rust-analyzer and implementing some changes without significant regard for existing features. I believe this could reach proof of concept quite rapidly. Then, once the fork works, one can think about how and whether integration into rust-analyzer itself might be done. (Given how the suggestion to support individual rs files was received in rust-analyzer/rust-analyzer#4477, I'm unsure as to whether they would be receptive to the idea. On the other hand, rust-script
is well enough known that they might be.)
I've added the proof of concept project near the top of my large pile of project ideas. If I get around to trying it, I'll report back.
I am making progress on this. I will share when I have something to show.
@SafariMonkey Anything to show yet?
I think there are a few things to talk about, detection and IDE support
the way I see it there are two possible methods
.rs
files for a header in the first (10?) lines looking for ``cargo
and then assumes it is rust-script than preforms the needed actions or.ers
or other? alternative file extensionObviously supporting the majority of these platforms is silly for our small project, so I crossed out most things that we probably should not focus any effort on. that leaves
As plausible candidates. I feel drawn to VScode as a user of it, so thats my vote for the first focus
I have spent a decent amount of time on this, with various branches, ending in byte-accurate tracking of the location of the span of the cargo manifest, which I have succeeded in feeding into rust-analyzer
. (branch) rust-analyzer
is happy to treat an ers
file as a Rust source file if you add it to the package.json and some other places, but I'm pretty stuck on how rust-script
stuff should be integrated into rust-analyzer
. I've considered trying to get some input on the zulip, but I don't exactly even know how to formulate the question.
The best I've come up with is to represent the script as a pseudo-macro that is invoked from the generated path, which generates the code, or possibly representing the source file as a custom source code path ([path]
) for the binary in the Cargo.toml
. Both of these run into a design decision in rust-analyzer
, which is:
To solve (or explicitly refuse to solve) these problems rust-analyzer uses the concept of a "source root". Roughly speaking, source roots are the contents of a directory on a file systems, like
/home/matklad/projects/rustraytracer/**.rs
.More precisely, all files (
FileId
s) are partitioned into disjointSourceRoot
s. Each file has a relative UTF-8 path within theSourceRoot
.SourceRoot
has an identity (integer ID). Crucially, the root path of the source root itself is unknown to the analyzer: A client is supposed to maintain a mapping betweenSourceRoot
IDs (which are assigned by the client) and actualPathBuf
s.SourceRoot
s give a sane tree model of the file system to the analyzer.Note that
mod
,#[path]
andinclude!()
can only reference files from the same source root. It is of course possible to explicitly add extra files to the source root, even/dev/random
.
(source)
Overall, this project has been on my mind I haven't touched the code since late March now because I've been unable to find the best approach, nor to formulate my thoughts in a constructive way to ask e.g. the rust-analyzer
folks. I've been meaning to write this up for weeks, so thanks for giving me the push to finally do so!
I welcome any thoughts and feedback on how to proceed.
Helpwanted
Hello there ,
here this library gives some insights about how and why rust-analyzer not working and workaround ways https://lib.rs/crates/rv
and here this library fixes auto-completion, but not code check on the fly , reminder the library expects rust files under "exercises" folder https://crates.io/crates/rustlings-fix
in the end for me as a rust learner the most practical way is building a cargo package and then creating a folder named "examples" which cargo does not complain having multiple separated rust files, and everything works perfectly , You can run individual executable examples with the cargo run command with the --example
It seems to me that forking rust-analyzer
or similar solutions is a very significant task, and would mean that you could not get things easily working out of the box with rustup
.
Let me suggest a perhaps more pragmatic workaround: rust-analyzer
supports non-Cargo based projects. The gist of it is that you need a rust-project.json
file that explains to rust-analyzer
the structure of the project. This file will be picked up by rust-analyzer
in a few different ways, the most obvious being that it will look for it in the root directory of the project. However, for scripts this is impractical, as you might want to have multiple unrelated scripts in the same directory. There's this alternative:
Specify
"rust-analyzer.linkedProjects": [ "path/to/rust-project.json" ]
in the settings (and make sure that your LSP client sends settings as a part of initialize request).
Based on this, here's what I envision:
--generate-rust-analyzer-config
parameter to rust-script
that when run generates precisely the needed rust-project.json
file for rust-analyzer
to be able to understand the file, and output the requisite rust-analyzer
settings.rust-analyzer
settings.This way at least rust-analyzer
itself requires no upstream changes. Of course, I hope in the future we can have canonical support for rust-script
(or a similar solution) in rust-analyzer
, but this appears like something that would take a lot of time to accomplish. In the intermediate time, perhaps a solution like this might be a decent workaround?
To add to that, once such support is available in rust-script
, one could imagine building small plugins for specific IDEs like VS Code that would, when confronted with an .ers
file, run rust-script
to obtain the necessary config and automatically add it to rust-analyzer
configuration. I don't have enough experience with rust-analyzer
and VS Code to say if this is actually feasible to do, but it doesn't sound so farfetched.
Yet another approach would be to create a language server that proxies almost all requests/response to/from rust-analyzer
. It would launch rust-analyzer
on the cached package, maybe remove some capabilities, translate some file path and file position (for templated scripts), invoke rust-script --gen-pkg-only
for some type of requests, etc..
I wouldn't say it's an easy thing to do, but probably easier and more maintainable than forking rust-analyzer, and possible to support templated scripts.
Disclaimer: I've never written language-server-related things, so maybe I'm missing something obvious.
Any updates on this?
Here's a proof-of-concept of what I said in the last comment. It kinda works at some extent, but haven't tested extensively. It'd have been nicer if rust-script didn't remove shebang, as things are off by one line due to it if the script had a shebang, I believe.
It'd have been nicer if rust-script didn't remove shebang, as things are off by one line due to it if the script had a shebang, I believe.
@MiSawa Great suggestion! Should be fixed by the just released 0.25.0 version of rust-script.
Ah nice, thank you for the quick fix!
I'm willing to investigate into the other approach (use rust-project.json
) later this month, which perhaps is easier, if others hasn't.
So... here's a script that generates rust-project.json
file for a given rust-script. I also tried integrating it with the language server.
rust-project.json
Although many things work well without too much code, rust-project.json
isn't a silver bullet. Especially, rust-analyzer
relies on cargo
for fly check (done through something like cargo check --workspace --message-format=json --all-targets
, and diagnostics are emitted based on the result), but since we use non-cargo thing to declare the project, we need to either
cargo check
which translates the path, and let rust-analyzer
invoke it instead, orrust-analyzer
track the source file in the generated package, and translate the path in the language server proxy.[[bin]] path=..
of Cargo.toml
. This means that as long as it's not a templated (including those doesn't have main), we can just configure rust-analyzer
to use that Cargo.toml
, and we don't need any path translation.rust-analyzer
's support seems to be extremely limited so probably not worth to do now, but we may be able to utilize include!
. Unfortunately it can't have //!
-type of doc comment though it seems to ignore shebang as same as usual rust file.Would it cause any issue if we used the absolute path of the original .ers
source as the [[bin]] path=...
of Cargo.toml
when it has the main
function? With that change, I think this (unpublished) revision of rscls works well on that situation.
@MiSawa Nice work - https://github.com/fornwall/rust-script/pull/103 has just been released in version 0.28.0.
Perhaps we should move towards this setup where the source input file is unmodified always, and deprecate (or at least avoid encouraging it in the the documentation) functionality such as automatically wrapping the script with a main
function?
Thank you, released rscls 0.2.0 that works well with rust-script 0.28.0
(except templated and non-main
) in my environment.
Hmmm, I personally always use scripts including main
, and that writing of main
doesn't really bother me, so I'd +1 for not encouraging in favor of lsp support.
There's a RFC for official support of single file scripts, and I guess they won't support such features initially (at least MVP doesn't). So explicit main
may be better for compatibility with that thing.
+1 @MiSawa to rscls
! Works seamlessly with Neovim!
Is there a known way for something like rust-analyzer to work on these scripts? I think if I add a Cargo.toml with all the crates I use in my scripts, I might be able to get some support.
However, that won't work with the special template syntax.
Any tips regarding using IDEs with rust-script? I believe cargo-eval and cargo-script suffer from the same issues.