Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: init lsp workspace when start language server #1584

Merged
merged 5 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions kclvm/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod modfile;
pub mod path;
pub mod settings;
pub mod vfs;
pub mod workfile;

#[cfg(test)]
pub(crate) mod tests;
1 change: 1 addition & 0 deletions kclvm/config/src/modfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::path::ModRelativePath;

pub const KCL_MOD_FILE: &str = "kcl.mod";
pub const KCL_MOD_LOCK_FILE: &str = "kcl.mod.lock";
pub const KCL_WORK_FILE: &str = "kcl.work";
pub const KCL_FILE_SUFFIX: &str = ".k";
pub const KCL_FILE_EXTENSION: &str = "k";
pub const KCL_MOD_PATH_ENV: &str = "${KCL_MOD}";
Expand Down
Empty file added kclvm/config/src/testdata/a/a.k
Empty file.
Empty file added kclvm/config/src/testdata/b/b.k
Empty file.
3 changes: 3 additions & 0 deletions kclvm/config/src/testdata/kcl.work
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
workspace ./a
workspace ./b
workspace ./c/d
190 changes: 190 additions & 0 deletions kclvm/config/src/workfile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
//! The config for IDE/LSP workspace config file `kcl.work'

use kclvm_utils::path::PathPrefix;
use serde::{Deserialize, Serialize};
use std::{
collections::HashMap,
io::{BufRead, BufReader},
path::{Path, PathBuf},
};

use crate::modfile::KCL_WORK_FILE;
use anyhow::Result;

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct WorkFile {
pub workspaces: Vec<WorkSpace>,
pub failed: HashMap<String, String>,
}

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct WorkSpace {
pub content: String,
pub path: String,
pub abs_path: String,
}

/// Load kcl work file from path
pub fn load_work_file<P: AsRef<Path> + std::fmt::Debug>(path: P) -> Result<WorkFile> {
let file = if path.as_ref().is_dir() {
let file_path = path.as_ref().join(KCL_WORK_FILE);
std::fs::File::open(file_path)?
} else if path.as_ref().is_file() {
std::fs::File::open(&path)?
} else {
return Err(anyhow::anyhow!("kcl.work not found for {:?}", path));
};

let reader = BufReader::new(file);
let mut workfile = WorkFile::default();
for line in reader.lines() {
if let Ok(line) = line {
let mut directive = line.split_whitespace();
if let Some(key) = directive.next() {
match key {
"workspace" => {
if let Some(path) = directive.next() {
workfile.workspaces.push(WorkSpace {
content: line.clone(),
path: path.to_string(),
abs_path: "".to_string(),
});
}
}
_ => {
workfile.failed.insert(line, "Unknown keyword".to_string());
}
}
}
}
}
Ok(workfile)
}

impl WorkFile {
pub fn canonicalize(&mut self, root: PathBuf) {
let mut new_workspaces = vec![];
for workspace in self.workspaces.iter_mut() {
let path = Path::new(&workspace.path);
if !path.is_absolute() {
let filepath = root.join(Path::new(&workspace.path));
match filepath.canonicalize() {
Ok(path) => new_workspaces.push(WorkSpace {
content: workspace.content.clone(),
path: workspace.path.clone(),
abs_path: path.adjust_canonicalization(),
}),
Err(e) => {
self.failed.insert(
workspace.content.clone(),
format!("path canonicalize failed: {:?}", e),
);
}
}
} else {
new_workspaces.push(WorkSpace {
content: workspace.content.clone(),
path: workspace.path.clone(),
abs_path: workspace.path.clone(),
})
};
}
self.workspaces = new_workspaces;
}
}

#[cfg(test)]
mod workfile_test {
use std::path::PathBuf;

use crate::workfile::WorkSpace;

use super::load_work_file;
#[test]
fn parse_workfile() {
let path = "./src/testdata/";
let workfile = load_work_file(path).unwrap();
assert_eq!(
workfile.workspaces,
vec![
WorkSpace {
content: "workspace ./a".to_string(),
path: "./a".to_string(),
abs_path: "".to_string()
},
WorkSpace {
content: "workspace ./b".to_string(),
path: "./b".to_string(),
abs_path: "".to_string()
},
WorkSpace {
content: "workspace ./c/d".to_string(),
path: "./c/d".to_string(),
abs_path: "".to_string()
},
]
);
}

#[test]
fn parse_workfile1() {
let path = "./src/testdata/kcl.work";
let workfile = load_work_file(path).unwrap();
assert_eq!(
workfile.workspaces,
vec![
WorkSpace {
content: "workspace ./a".to_string(),
path: "./a".to_string(),
abs_path: "".to_string()
},
WorkSpace {
content: "workspace ./b".to_string(),
path: "./b".to_string(),
abs_path: "".to_string()
},
WorkSpace {
content: "workspace ./c/d".to_string(),
path: "./c/d".to_string(),
abs_path: "".to_string()
},
]
);
}

#[test]
fn canonicalize_workfile() {
let path = "./src/testdata/kcl.work";
let mut workfile = load_work_file(path).unwrap();
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("src")
.join("testdata");
let mut a = path.clone();
a.push("a");

let mut b = path.clone();
b.push("b");

let mut cd = path.clone();
cd.push("c");
cd.push("d");

workfile.canonicalize(path);
assert_eq!(
workfile.workspaces,
vec![
WorkSpace {
content: "workspace ./a".to_string(),
path: "./a".to_string(),
abs_path: a.to_str().unwrap().to_string(),
},
WorkSpace {
content: "workspace ./b".to_string(),
path: "./b".to_string(),
abs_path: b.to_str().unwrap().to_string(),
},
]
);
assert!(!workfile.failed.is_empty());
}
}
Loading
Loading