ebkalderon / tower-lsp

Language Server Protocol implementation written in Rust
Apache License 2.0
1k stars 55 forks source link

How to proactively send commands #290

Closed Timmmm closed 2 years ago

Timmmm commented 2 years ago

Hi, I'm a bit of a Tokio newbie (I know nothing about it whatsoever), and I was wondering how to send custom requests to the client proactively, in other words not in response to a request from the client. In my case I want to send an ExecuteCommand when some file changes.

I'm not really sure where to start though - can you give me any hints? I've added a method to my Backend like this:

  pub async fn start_python_debugging(&self, port: u16) -> Result<<ExecuteCommand as Request>::Result> {
    // https://code.visualstudio.com/api/references/vscode-api#debug
    self.client.send_custom_request::<ExecuteCommand>(ExecuteCommandParams{
      command: "vscode.debug.startDebugging".to_string(),
      arguments: todo!(),
      work_done_progress_params: WorkDoneProgressParams { work_done_token: None },
    }).await
  }

And I'm going to use the Notify crate which has an async example, but how do I connect them?

Timmmm commented 2 years ago

Never mind I think I figured it out. Something like this (not tested yet but it compiles which is like 90% as good in Rust!)

impl Backend {
  pub fn new(client: Client) -> Self {
    // async_watcher() from the notify async example.
    let (mut watcher, mut rx) = async_watcher().unwrap();

    watcher.watch(Path::new("/path/to/file"), RecursiveMode::NonRecursive).unwrap();

    let client_copy = client.clone();
    tokio::spawn(async move {
      while let Some(res) = rx.next().await {
        match res {
          Ok(event) => {
            println!("changed: {:?}", event);
            client_copy.send_custom_request::<ExecuteCommand>(ExecuteCommandParams{
              command: "startDebugging".to_string(),
              arguments: todo!(),
              work_done_progress_params: WorkDoneProgressParams { work_done_token: None },
            }).await;
          }
          Err(e) => println!("watch error: {:?}", e),
        }
      }
    });

    Self {
      client,
      ...
    }
  }