lib.rs

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