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

[WIP] WASM demo #1746

Closed
wants to merge 1 commit into from
Closed

Conversation

JasperDeSutter
Copy link
Contributor

@JasperDeSutter JasperDeSutter commented Sep 1, 2019

This is a stab at #1007, having a monaco editor with rust-analyzer running in WASM.

features:

  • document syntax highlighting with rust analyzer, through extensive hacks on JS side
  • hover, which works pretty well (using language ID hack for highlighting)
  • real-time update
  • rename, but breaks undo :)
  • code lens
  • code completions - currently panics on wasm-bindgen side
  • diagnostics, still have to implement quick fixes
  • actions / quick fixes
  • inlay hints (is this even possible in monaco?)
  • goto definition / implementation / type definition

Issues when running ra_ide_api in wasm:

  • std::time::Instant does not work -> replaced by shim for feature "wasm"
  • rayon does not work -> replaced by standard iterators for feature "wasm"

as for the implementation:

Started from a standard wasm-bindgen template, as explained here: https://rustwasm.github.io/docs/book/game-of-life/hello-world.html

Currently the code is executed on the main thread (not a webworker), this might be added later when things become too slow. Also, when trying this before, there was a webpack issue which generated a wrong bundle for webworkers.

value passing JS -> WASM happens through arguments for ease of use, and WASM -> JS uses serde_wasm_bindgen. This was the most ergonomic way to work with structured data, but might leave some performance on the table.

logs are filtered to Level::Warn, because the abundance of Info logging really slows down everything a lot though the console_log logger.

It's a pain to try to figure out monaco's API's and how they differ from the vscode/LSP ones. The bad documentation makes me resort to plowing through the npm package code...

Still very much work-in-progress here, but I'm looking for feedback already to be sure.

@@ -134,7 +133,7 @@ impl LibraryData {
root_id: SourceRootId,
files: Vec<(FileId, RelativePathBuf, Arc<String>)>,
) -> LibraryData {
let symbol_index = SymbolIndex::for_files(files.par_iter().map(|(file_id, _, text)| {
let symbol_index = SymbolIndex::for_files(files.iter().map(|(file_id, _, text)| {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like we should just #[cfg(feature = "wasm")] this: rayon is pretty important for perf

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you mean target_arch="wasm32"?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, good question....

I feel like it's better to use Cargo feature, but that's just a gut feeling, so I am fine either way!

}

pub fn update(&mut self, code: String) -> JsValue {
// TODO: how to update analyisis source?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need AnalysisHost and AnalysisChange for this, but re-creating on every change is surely fine for the first stab!


cd www
npm i
npx webpack-dev-server --host 0.0.0.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally, we should build a static page and host it on GH pages, like here: https://github.com/matklad/tom/tree/gh-pages

@matklad
Copy link
Member

matklad commented Sep 2, 2019

I've looked at it, and this looks awesome!

Let's do two things before merging though:

@matklad
Copy link
Member

matklad commented Sep 2, 2019

#1747 makes the scaffold for gh-pages

println!("linked list has length: {}", list.len());
println!("{}", list.stringify());
}
`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing ; and trailing newline.

@JasperDeSutter
Copy link
Contributor Author

wasm-pack will be needed to build the wasm-demo (https://rustwasm.github.io/wasm-pack/installer/), where should this be added? As is node/npm, but I guess this is already there for vscode tests.

@matklad
Copy link
Member

matklad commented Sep 2, 2019

Yeah, we already require node, so we can assume it exists. Wasm pack should be installed by website gen using cargo install

let allTokens = []

function update() {
console.warn("update")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please end statements with ;? While javascript allows it, only npm doesnt use them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the JS code is still formatted/structured badly, heck it even has warn's for logging and commented-out code.
The whole file needs some serious cleaning, but I was planning to do this after implementing most of the demo-able functionality.

// install wasm-pack if not available
let res = Command::new("wasm-pack").arg("--version").status();
if res.is_err() {
let status = cargo().args(&["install", "wasm-pack"]).status()?;
Copy link
Member

@killercup killercup Sep 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest downloading https://github.com/rustwasm/wasm-pack/releases/download/v0.8.1/wasm-pack-v0.8.1-x86_64-unknown-linux-musl.tar.gz instead and saving a lot of time when it is not cached. You can even easily check the version and there are binaries for other platforms too. This way you can also install it to a specific location and execute it from there so you know the version matches what you expect.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The flip side is that we'd have to implement our own caching logic, to avoid download on every local build. I think it makes sense to defer these concerns to cargo install and travis own caching.

@matklad
Copy link
Member

matklad commented Sep 5, 2019

Ok, I think this looks good enough to lend now, but the branch needs rebasing

@@ -0,0 +1,202 @@
// @ts-check
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we're running this through webpack anyway, why not use TS? (that shouldn't block this PR though 🙂 )

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that’s actually a really great idea! I’d love to get rid of webpack if possible though, but I guess Monaco needs it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, TypeScript makes more sense indeed. I just didn't want to add the extra dependencies to ts-loader + extra config required to make TS work for now.
As for webpack, monaco does require webpack-like semantics, such as importing CSS files into JavaScript. This can probably be done with another bundler instead, but probably won't work without any tool (or just tsc).

@matklad
Copy link
Member

matklad commented Sep 6, 2019

@JasperDeSutter looks like this still has some conflicts. Perhaps it would be easier to squash down the history here to a single commit and rebase that?

@JasperDeSutter
Copy link
Contributor Author

@matklad done, everything should be up-to-date now

@matklad
Copy link
Member

matklad commented Sep 9, 2019

Tested it locally, and it works! However, given the number of deps here and the size of the .wasm file, I feel it makes sense to move the whole website do the separate repository. I'll try to look into this today

@@ -4,6 +4,9 @@ name = "ra_ide_api"
version = "0.1.0"
authors = ["rust-analyzer developers"]

[features]
wasm = []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason this is a feature? You should be able to just check for wasm via a normal cfg based on the target?!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#1746 (comment)

Not sure which is better, but, with a feature, we can check that wasm build actually builds without needing to compile to wasm

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, looks like you already had a discussion about this further up.

@matklad
Copy link
Member

matklad commented Sep 9, 2019

I'll try to look into this today

Nope, I won't get to this today sadly :(

bors bot added a commit that referenced this pull request Sep 20, 2019
1888: allow compiling ra_ide_api on wasm r=matklad a=matklad

bors r+

this is from #1746 

Co-authored-by: Aleksey Kladov <[email protected]>
matklad added a commit to rust-analyzer/rust-analyzer.github.io that referenced this pull request Sep 20, 2019
matklad added a commit to rust-analyzer/rust-analyzer.github.io that referenced this pull request Sep 20, 2019
matklad added a commit to rust-analyzer/rust-analyzer.github.io that referenced this pull request Sep 20, 2019
matklad added a commit to rust-analyzer/rust-analyzer.github.io that referenced this pull request Sep 20, 2019
matklad added a commit to rust-analyzer/rust-analyzer.github.io that referenced this pull request Sep 20, 2019
@matklad
Copy link
Member

matklad commented Sep 20, 2019

finally got to this!

https://rust-analyzer.github.io/wasm-demo.html

I've moved it to the separate repo, to avoid adding mulimegabyte blobs to the git history:

https://github.com/rust-analyzer/rust-analyzer.github.io

The setup is pretty horrible and could be improved

@matklad
Copy link
Member

matklad commented Sep 20, 2019

Thank you so much for bringing this all together @JasperDeSutter !

@matklad matklad closed this Sep 20, 2019
@lnicola
Copy link
Member

lnicola commented Sep 20, 2019

That's pretty cool, but does it work? I can't get completion to yield anything useful, not even for the List type in the demo:

image

image

image

Also, wheel scroll doesn't work in Firefox, but that's probably an editor issue.

@matklad
Copy link
Member

matklad commented Sep 20, 2019 via email

matklad added a commit to rust-analyzer/rust-analyzer-wasm that referenced this pull request Dec 23, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants