1use std::{
2 fs::{self, File},
3 io::Write,
4 path::{Path, PathBuf},
5 process::Stdio,
6};
7
8use crate::{error::LimpError, parser::load_from_deps, storage::JsonDependency};
9
10const MAIN_SNIP: &str = r#"fn main() {
11 println!("Hello, limp!");
12}"#;
13
14pub fn username() -> String {
15 std::env::var("USER").unwrap_or(std::env::var("USERNAME").unwrap_or("unknown".to_string()))
16}
17
18pub fn storage_path() -> PathBuf {
19 let uname = username();
20
21 match std::env::consts::OS {
22 "windows" => PathBuf::from(format!("C:\\Users\\{}\\AppData\\Roaming\\limp", &uname)),
23 _ => PathBuf::from(format!("/home/{}/.config/limp/", &uname)),
24 }
25}
26
27pub fn config_path() -> PathBuf {
28 storage_path().join("dependencies.json")
29}
30
31pub fn snippets_dir() -> PathBuf {
32 storage_path().join("snippets")
33}
34
35pub fn find_toml() -> Option<PathBuf> {
36 if let Ok(mut path) = std::env::current_dir() {
37 let pre_toml = path.join("Cargo.toml");
38 if pre_toml.exists() {
39 return Some(pre_toml);
40 }
41 while path.pop() {
42 let pre_toml = path.join("Cargo.toml");
43 if pre_toml.exists() {
44 return Some(pre_toml);
45 }
46 }
47 return None;
48 }
49 None
50}
51
52pub fn open<P: AsRef<Path>>(path: P) -> Result<File, LimpError> {
53 let path = path.as_ref();
54 fs::create_dir_all(path.parent().unwrap_or(Path::new("./")))?;
55 let file = File::options()
56 .read(true)
57 .append(true)
58 .create(true)
59 .open(path)?;
60 Ok(file)
61}
62
63pub fn add_to_snippets_dir(name: &str, content: &str) -> Result<String, LimpError> {
64 let path = snippets_dir().join(format!("{name}.rs"));
65 if path.exists() {
66 return Err(LimpError::SnippetExists(name.to_string()));
67 }
68 let mut file = open(&path)?;
69 file.write_all(content.as_bytes())?;
70 Ok(path.display().to_string())
71}
72
73pub fn remove_from_snippets_dir(name: &str) -> Result<(), LimpError> {
74 let path = snippets_dir().join(format!("{name}.rs"));
75 if !path.exists() {
76 return Ok(());
78 }
79 fs::remove_file(path)?;
80 Ok(())
81}
82
83pub fn create_project(name: &str, deps: Option<&[JsonDependency]>) -> Result<(), LimpError> {
84 let project = PathBuf::from(format!("./{}", name));
85 if project.exists() && project.read_dir()?.count() > 0 {
86 return Err(LimpError::CrateExistsNotEmpty(name.to_string()));
87 }
88
89 let mut main_snippet = MAIN_SNIP.to_string();
90 let mut toml = open(project.join("Cargo.toml"))?;
91 writeln!(toml, "[package]")?;
92 writeln!(toml, "name = \"{}\"", name)?;
93 writeln!(toml, "version = \"0.1.0\"")?;
94 writeln!(toml, "edition = \"2021\"")?;
95 writeln!(toml)?;
96 writeln!(toml, "[dependencies]")?;
97 if let Some(deps) = deps {
98 for dep in deps.iter() {
99 writeln!(toml, "{}", dep)?
100 }
101 main_snippet = load_from_deps(deps).unwrap_or(MAIN_SNIP.to_string());
102 }
103
104 let mut main = open(project.join("src").join("main.rs"))?;
105 main.write_all(main_snippet.as_bytes())?;
106
107 if !std::process::Command::new("git")
108 .args(["init", name])
109 .stdout(Stdio::null())
110 .stderr(Stdio::null())
111 .spawn()?
112 .wait()?
113 .success()
114 {
115 return Err(LimpError::GitError(name.to_string()));
116 }
117 let mut gitignore = open(project.join(".gitignore"))?;
118 gitignore.write_all(b"/target")?;
119
120 Ok(())
121}