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}