Open icsaszar opened 4 years ago
I think this is a great idea! Normally, the solution for this would be to use a Mutex
or RwLock
to manage synchronization of the files
field. We could write an example which showcases this use.
If we follow through with https://github.com/ebkalderon/tower-lsp/issues/13#issuecomment-589995913 and turn the notification handlers into async fn
methods which can be spawned onto the runtime with tokio::spawn()
, we could then use a tokio::sync::Mutex
to avoid blocking the executor.
I can help with the implementation of the example once #13 is done.
While on this subject, a "Useful resources/Relevant projects" section in the readme could also be useful.
So far the following resources were very helpful for me:
I wholeheartedly recommend this! I especially recommend codespan
and codespan-lsp
for handling text spans and code diagnostics because it interoperates directly with lsp-types
, a foundational crate used by tower-lsp
. I try to be mindful of version incompatibilities between codespan-lsp
and lsp-types
and I generally avoid upgrading the lsp-types
dependency in tower-lsp
sometimes specifically to remain compatible with both.
However, I don't think I can reasonably recommend using both codespan
and ropey
in the same project, though, since codespan::Files
expects T: AsRef<str>
and ropey::{Ropey,RopeySlice}
do not implement this, sadly, so the two crates cannot easily integrate.
@ebkalderon I just found your nix-language-server project which could serve as the example we're looking for.
It's clean and understandable, it has state handling, error reporting and even incremental text updates.
Thanks for the kind words! While I think it's a pretty good example of tower-lsp
on its own, but I feel it's hardly clean enough to recommend to new users to reference. Error handling is poor and there is no revision checking of incremental text updates at the moment, which means that undoing certain edits and re-applying them can occasionally screw up the integrity of the cached text. Note the giant //! HACK: All of this
comment at the top of the backend.rs
module (link). 😅
It could serve as a good example if given a bit more attention and polish, though.
I ran into a case where the above blueprint didn't really work, because of a variable which was !Sync
and !Send
, which kept that variable from living across an await point (I.e. it could only live on the stack within an async block). If you guys think it would be worth having an example which shows dealing with this situation, I could try and extract a minimal example out of it.
@ratmice sure, if you have an example to share that could be interesting. Even just having some notes about some other scenario like that in this issue could be useful for people searching the repo.
I think it probably requires too much detail about the specific situation, but I threw together a very specific example in pr #340
I think an example with a recommended method to handle state would be very useful (since it's what a real use case would probably look like).
I think simply printing the open files in the workspace every time a file is opened (
did_open
) or closeddid_close
and counting the number of calls todid_change
would be enough to get started.The main reason for this is that only
&self
is available in the methods, so something straight forward like thiswon't compile because
Vec::push()
requires a mutable reference to&self
.It would be also nice to recommend something that can make use of the fact that the server has async support.