Repository: helix-editor/helix
File: helix-lsp/src/lib.rs (Rust)

Code before:
                let params: lsp::UnregistrationParams = params.parse()?;
                Self::UnregisterCapability(params)
            }
            lsp::request::ShowDocument::METHOD => {
                let params: lsp::ShowDocumentParams = params.parse()?;
                Self::ShowDocument(params)
            }
            _ => {
                return Err(Error::Unhandled);
            }
        };
        Ok(request)
    }
}

#[derive(Debug, PartialEq, Clone)]
pub enum Notification {
    // we inject this notification to signal the LSP is ready
    Initialized,
    // and this notification to signal that the LSP exited
    Exit,
    PublishDiagnostics(lsp::PublishDiagnosticsParams),
    ShowMessage(lsp::ShowMessageParams),
    LogMessage(lsp::LogMessageParams),
    ProgressMessage(lsp::ProgressParams),
    WorkspaceDiagnosticRefresh,
}

impl Notification {
    pub fn parse(method: &str, params: jsonrpc::Params) -> Result<Notification> {
        use lsp::notification::Notification as _;

        let notification = match method {
            lsp::notification::Initialized::METHOD => Self::Initialized,
            lsp::notification::Exit::METHOD => Self::Exit,
            lsp::notification::PublishDiagnostics::METHOD => {
                let params: lsp::PublishDiagnosticsParams = params.parse()?;
                Self::PublishDiagnostics(params)
            }

            lsp::notification::ShowMessage::METHOD => {
                let params: lsp::ShowMessageParams = params.parse()?;
                Self::ShowMessage(params)
            }
            lsp::notification::LogMessage::METHOD => {
                let params: lsp::LogMessageParams = params.parse()?;
                Self::LogMessage(params)
            }
            lsp::notification::Progress::METHOD => {
                let params: lsp::ProgressParams = params.parse()?;
                Self::ProgressMessage(params)

Review comment (suggestion):
It looks like this is actually a request rather than a notification in the spec, so this should live under `MethodCall`. In `application.rs` the handler for this branch should move down to where we handle `Call::MethodCall`s and return `Ok(serde_json::Value::Null)` I believe

Code after:
    fn start_client(
        &mut self,
        name: String,
        ls_config: &LanguageConfiguration,
        doc_path: Option<&std::path::PathBuf>,
        root_dirs: &[PathBuf],
        enable_snippets: bool,
    ) -> Result<Arc<Client>, StartupError> {
        let syn_loader = self.syn_loader.load();
        let config = syn_loader
            .language_server_configs()
            .get(&name)
            .ok_or_else(|| anyhow::anyhow!("Language server '{name}' not defined"))?;
        let id = self.inner.try_insert_with_key(|id| {
            start_client(
                id,
                name,
                ls_config,
                config,
                doc_path,
                root_dirs,
                enable_snippets,
            )
            .map(|client| {
                self.incoming.push(UnboundedReceiverStream::new(client.1));
                client.0
            })
        })?;
        Ok(self.inner[id].clone())
    }

    /// If this method is called, all documents that have a reference to the language server have to refresh their language servers,
    /// See helix_view::editor::Editor::refresh_language_servers
    pub fn restart_server(
        &mut self,
        name: &str,
        language_config: &LanguageConfiguration,
        doc_path: Option<&std::path::PathBuf>,
        root_dirs: &[PathBuf],
        enable_snippets: bool,
    ) -> Option<Result<Arc<Client>>> {
        if let Some(old_clients) = self.inner_by_name.remove(name) {
            if old_clients.is_empty() {
                log::info!("restarting client for '{name}' which was manually stopped");
            } else {
                log::info!("stopping existing clients for '{name}'");
            }
            for old_client in old_clients {
                self.file_event_handler.remove_client(old_client.id());
                self.inner.remove(old_client.id());
                tokio::spawn(async move {