lib.rs

  1use plugin::prelude::*;
  2use serde_json::json;
  3use std::fs;
  4use std::path::PathBuf;
  5
  6// #[import]
  7// fn command(string: String) -> Option<String>;
  8
  9// TODO: some sort of macro to generate ABI bindings
 10extern "C" {
 11    pub fn hello(item: u32) -> u32;
 12    pub fn bye(item: u32) -> u32;
 13}
 14
 15// #[bind]
 16// pub async fn name(u32) -> u32 {
 17
 18// }
 19
 20// #[no_mangle]
 21// pub extern "C" fn very_unique_name_of_course() -> impl std::future::Future<Output = u32> {
 22//     async move {
 23//         std::fs::read_to_string("heck.txt").unwrap().len() as u32
 24//     }
 25// }
 26
 27const BIN_PATH: &'static str =
 28    "node_modules/vscode-json-languageserver/bin/vscode-json-languageserver";
 29
 30#[bind]
 31pub fn name() -> &'static str {
 32    // let number = unsafe { hello(27) };
 33    // println!("got: {}", number);
 34    // let number = unsafe { bye(28) };
 35    // println!("got: {}", number);
 36    "vscode-json-languageserver"
 37}
 38
 39#[bind]
 40pub fn server_args() -> Vec<String> {
 41    vec!["--stdio".into()]
 42}
 43
 44#[bind]
 45pub fn fetch_latest_server_version() -> Option<String> {
 46    #[derive(Deserialize)]
 47    struct NpmInfo {
 48        versions: Vec<String>,
 49    }
 50
 51    let output = command("npm info vscode-json-languageserver --json")?;
 52    if !output.status.success() {
 53        return None;
 54    }
 55
 56    let mut info: NpmInfo = serde_json::from_slice(&output.stdout)?;
 57    info.versions.pop()
 58}
 59
 60// #[bind]
 61// pub fn fetch_server_binary(container_dir: PathBuf, version: String) -> Option<PathBuf> {
 62//     let version_dir = container_dir.join(version.as_str());
 63//     fs::create_dir_all(&version_dir)
 64//         .or_or_else(|| "failed to create version directory".to_string())?;
 65//     let binary_path = version_dir.join(Self::BIN_PATH);
 66
 67//     if fs::metadata(&binary_path).await.is_err() {
 68//         let output = command(format!(
 69//             "npm install vscode-json-languageserver@{}",
 70//             version
 71//         ));
 72//         if !output.status.success() {
 73//             Err(anyhow!("failed to install vscode-json-languageserver"))?;
 74//         }
 75
 76//         if let Some(mut entries) = fs::read_dir(&container_dir).await.log_err() {
 77//             while let Some(entry) = entries.next().await {
 78//                 if let Some(entry) = entry.log_err() {
 79//                     let entry_path = entry.path();
 80//                     if entry_path.as_path() != version_dir {
 81//                         fs::remove_dir_all(&entry_path).await.log_err();
 82//                     }
 83//                 }
 84//             }
 85//         }
 86//     }
 87
 88//     Ok(binary_path)
 89// }
 90
 91#[bind]
 92pub fn cached_server_binary(container_dir: PathBuf) -> Option<PathBuf> {
 93    let mut last_version_dir = None;
 94    let mut entries = fs::read_dir(&container_dir).ok()?;
 95
 96    while let Some(entry) = entries.next() {
 97        let entry = entry.ok()?;
 98        if entry.file_type().ok()?.is_dir() {
 99            last_version_dir = Some(entry.path());
100        }
101    }
102
103    let last_version_dir = last_version_dir?;
104    let bin_path = last_version_dir.join(BIN_PATH);
105    if bin_path.exists() {
106        Some(bin_path)
107    } else {
108        None
109    }
110}
111
112#[bind]
113pub fn initialization_options() -> Option<String> {
114    Some("{ \"provideFormatter\": true }".to_string())
115}
116
117#[bind]
118pub fn id_for_language(name: String) -> Option<String> {
119    if name == "JSON" {
120        Some("jsonc".into())
121    } else {
122        None
123    }
124}