Repository: lapce/lapce
File: lapce-proxy/src/plugin/mod.rs (Rust)

Code before:
            .core_rpc
            .volt_installing(volt, "Could not download Plugin".to_string());
    }
    let meta = download_volt_result?;
    let local_catalog_rpc = catalog_rpc.clone();
    let local_meta = meta.clone();

    let _ = start_volt(workspace, configurations, local_catalog_rpc, local_meta);
    let icon = volt_icon(&meta);
    catalog_rpc.core_rpc.volt_installed(meta, icon);
    Ok(())
}

pub fn remove_volt(
    catalog_rpc: PluginCatalogRpcHandler,
    volt: VoltMetadata,
) -> Result<()> {
    thread::spawn(move || -> Result<()> {
        let path = volt.dir.as_ref().ok_or_else(|| {
            catalog_rpc
                .core_rpc
                .volt_removing(volt.clone(), "Plugin Directory not set".to_string());
            anyhow::anyhow!("don't have dir")
        })?;
        // Waiting for the instance of WASI to be dropped.
        std::thread::sleep(std::time::Duration::from_secs(1));
        if let Err(e) = std::fs::remove_dir_all(path) {
            eprintln!("Could not delete plugin folder: {e}");
            catalog_rpc.core_rpc.volt_removing(
                volt.clone(),
                "Could not remove Plugin Directory".to_string(),
            );
        } else {
            catalog_rpc.core_rpc.volt_removed(volt.info(), false);
        }
        Ok(())
    });
    Ok(())
}

fn client_capabilities() -> ClientCapabilities {
    ClientCapabilities {
        text_document: Some(TextDocumentClientCapabilities {
            synchronization: Some(TextDocumentSyncClientCapabilities {
                did_save: Some(true),
                dynamic_registration: Some(true),
                ..Default::default()
            }),
            completion: Some(CompletionClientCapabilities {
                completion_item: Some(CompletionItemCapability {
                    snippet_support: Some(true),

Review comment (suggestion):
It would be much better to wait for the wasi instance to be dropped in `stop_volt()` I think.

My idea is in `PluginServerRpcHandler::shutdown()`, you'd wait for a new event like `PluginServerRpc::Exited` which was sent from the wasi msg sending loop break. (wasi.rs line 464)

Code after:
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        == Some("application/zstd");

    let id = volt.id();
    let plugin_dir = Directory::plugins_directory()
        .ok_or_else(|| anyhow!("can't get plugin directory"))?
        .join(id.to_string());
    let _ = fs::remove_dir_all(&plugin_dir);
    fs::create_dir_all(&plugin_dir)?;

    if is_zstd {
        let tar = zstd::Decoder::new(&mut resp).unwrap();
        let mut archive = Archive::new(tar);
        archive.unpack(&plugin_dir)?;
    } else {
        let tar = GzDecoder::new(&mut resp);
        let mut archive = Archive::new(tar);
        archive.unpack(&plugin_dir)?;
    }

    let meta = load_volt(&plugin_dir)?;
    Ok(meta)
}

pub fn install_volt(
    catalog_rpc: PluginCatalogRpcHandler,
    workspace: Option<PathBuf>,
    configurations: Option<HashMap<String, serde_json::Value>>,
    volt: VoltInfo,
) -> Result<()> {
    let download_volt_result = download_volt(&volt);
    if download_volt_result.is_err() {
        catalog_rpc
            .core_rpc
            .volt_installing(volt, "Could not download Plugin".to_string());
    }
    let meta = download_volt_result?;
    let local_catalog_rpc = catalog_rpc.clone();
    let local_meta = meta.clone();

    let _ = start_volt(workspace, configurations, local_catalog_rpc, local_meta);
    let icon = volt_icon(&meta);
    catalog_rpc.core_rpc.volt_installed(meta, icon);
    Ok(())
}

pub fn remove_volt(
    catalog_rpc: PluginCatalogRpcHandler,
    volt: VoltMetadata,
) -> Result<()> {