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

IDE support #11

Open
jeromegn opened this issue Nov 23, 2020 · 19 comments
Open

IDE support #11

jeromegn opened this issue Nov 23, 2020 · 19 comments
Labels
help wanted Extra attention is needed

Comments

@jeromegn
Copy link

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.

@fornwall fornwall added the help wanted Extra attention is needed label Nov 26, 2020
@fornwall
Copy link
Owner

Going to be challenging, but leaving this open for ideas and discussion!

@Hecatron
Copy link

Hecatron commented Feb 9, 2021

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)

  • rust-script would need to have a option that builds but doesn't run the script, then returns the build directory / location of the built exe maybe as a json output or something
  • A custom debugger extension for vscode would then need to be written that would run rust-script with the above option, then use codelldb and the output from rust-script to launch the exe.

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"],
        },

@SafariMonkey
Copy link

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-lang/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.

@SafariMonkey
Copy link

I am making progress on this. I will share when I have something to show.

@boehs
Copy link

boehs commented May 5, 2021

@SafariMonkey Anything to show yet?

I think there are a few things to talk about, detection and IDE support


Detection

the way I see it there are two possible methods

  1. IDE scans all .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
  2. match for .ers or other? alternative file extension

IDE

Via: https://areweideyet.com/

Obviously 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

  • Atom
  • Emacs
  • Sublime
  • Vim/Neovim
  • VScode
  • Eclipse
  • IntelliJ-based IDEs
  • Visual Studio

As plausible candidates. I feel drawn to VScode as a user of it, so thats my vote for the first focus

@SafariMonkey
Copy link

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 (FileIds) are partitioned into disjoint
SourceRoots. Each file has a relative UTF-8 path within the SourceRoot.
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 between SourceRoot IDs (which are assigned by the client) and actual
PathBufs. SourceRoots give a sane tree model of the file system to the
analyzer.

Note that mod, #[path] and include!() 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.

@canofworm
Copy link

Helpwanted

@mu-us61
Copy link

mu-us61 commented Sep 22, 2022

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 option , but more easy way is in vs-code installing code runner then defining "rust-script" as run command , then you don't have to worry about the ".exe" output everything is clean and fast, works perfect

image

@Andlon
Copy link

Andlon commented Mar 7, 2023

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:

  1. Add a --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.
  2. The user then takes the output of this command and pastes it into their 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?

@Andlon
Copy link

Andlon commented Mar 7, 2023

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.

@MiSawa
Copy link
Contributor

MiSawa commented Mar 7, 2023

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.

@xbladesub
Copy link

Any updates on this?

@MiSawa
Copy link
Contributor

MiSawa commented Apr 9, 2023

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.

@fornwall
Copy link
Owner

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.

@MiSawa
Copy link
Contributor

MiSawa commented Apr 11, 2023

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.

@MiSawa
Copy link
Contributor

MiSawa commented Apr 20, 2023

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.

What I learned about 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

  • create a wrapper of cargo check which translates the path, and let rust-analyzer invoke it instead, or
  • somehow let rust-analyzer track the source file in the generated package, and translate the path in the language server proxy.

What I found

  • We can refer to an arbitrary absolute path in [[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.
  • For templated ones, the 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.

Suggestion

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.

@fornwall
Copy link
Owner

@MiSawa Nice work - #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?

@MiSawa
Copy link
Contributor

MiSawa commented Jun 12, 2023

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.

@kurtlawrence
Copy link

+1 @MiSawa to rscls! Works seamlessly with Neovim!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests