1use error::Error;
2use error::Error::InternalError;
3use git;
4use project;
5use snippet;
6
7use std::process::Command;
8
9use std::env;
10use std::fs;
11use std::fs::File;
12use std::io;
13use std::io::Write;
14use std::path;
15
16#[derive(Debug)]
17pub enum OpCode<'a> {
18 NewSnippet(&'a project::SnippetLocation),
20 AddSnippet(String, &'a project::SnippetLocation),
22 ListSnippets(bool),
24 PullSnippets,
26 SaveSnippets,
28}
29
30pub fn find_snippets(project: &project::Project) -> Result<Vec<fs::DirEntry>, Error> {
32 let mut res: Vec<fs::DirEntry> = Vec::new();
34
35 for snippet_location in project.locations.iter() {
37 println!("Finding snippets in {},", &snippet_location.local.as_str());
38 let mut entries: Vec<fs::DirEntry> = fs::read_dir(&snippet_location.local)?
39 .filter_map(|x| x.ok())
40 .collect();
41
42 let mut entries: Vec<_> = entries
44 .into_iter()
45 .filter_map(|e| {
46 let dir_ent = e;
47
48 let path = dir_ent.path();
50 let ext_opt = path.extension();
52 if let Some(ext) = ext_opt {
53 if let Some(s) = ext.to_str() {
54 if s == snippet_location.ext {
56 return Some(dir_ent);
57 }
58 }
59 }
60 return None;
61 })
62 .collect();
63 res.append(&mut entries);
64 }
65 Ok(res)
66}
67
68pub fn load_snippets(
70 dir_entries: &Vec<fs::DirEntry>,
71 keywords: &Vec<String>,
72) -> Result<Vec<snippet::Snippet>, Error> {
73 let keyword_slice = keywords.as_slice();
74
75 let mut tag_with_entries: Vec<(u32, &fs::DirEntry, Vec<String>)> = Vec::new();
77 for entry in dir_entries {
78 let tags = snippet::read_tags(entry.path().to_str().unwrap())?;
80
81 let tag_count : u32 = tags.iter()
84 .fold(0, |x, tag| x + if keyword_slice.contains(tag) { 1 } else { 0 });
85 if keyword_slice.is_empty() || tag_count > 0 {
86 tag_with_entries.push((tag_count, entry, snippet::read_tags(entry.path().to_str().unwrap())?));
87 }
88 }
89
90 tag_with_entries.sort_by(|a, b| b.0.cmp(&a.0) );
92
93 let result = tag_with_entries
95 .iter()
96 .map(|(count, entry, tags)| {
97 snippet::Snippet::new(entry.path().to_str().unwrap().to_string(), &tags)
98 })
99 .collect();
100
101 Ok(result)
102}
103
104pub fn edit_snippet(program: &str, full_path: &path::Path) -> Result<(), Error> {
106 let final_editor = default_editor(program);
107 let _output = Command::new(final_editor)
108 .arg(&full_path)
109 .spawn()?
110 .wait_with_output()?;
111
112 Ok(())
113}
114
115pub fn new_snippet(program: &str, working_dir: &path::Path) -> Result<(), Error> {
117 let final_editor = default_editor(program);
118
119 let _output = Command::new(final_editor)
120 .current_dir(&working_dir)
121 .spawn()?
122 .wait_with_output()?;
123
124 Ok(())
125}
126
127fn default_editor(program: &str) -> String {
128 let final_editor: String;
129 if let Ok(editor) = env::var("EDITOR") {
130 final_editor = editor.into();
131 } else {
132 final_editor = program.into()
133 };
134 final_editor
135}
136
137pub fn start_operation(
139 code: &OpCode,
140 project: &project::Project,
141 keywords: Vec<String>,
142) -> Result<Vec<snippet::Snippet>, Error> {
143 let result = match code {
145 OpCode::AddSnippet(new_file, location) => {
146 let full_path = path::Path::new(&location.local).join(new_file);
148 if full_path.exists() {
150 return Err(InternalError("Snippet already exists".to_string()));
151 }
152 let mut file = File::create(&full_path)?;
153
154 for keyword in &keywords {
156 file.write(keyword.as_bytes())?;
157 file.write(b",")?;
158 }
159
160 edit_snippet("vim", &full_path)?;
162
163 let snippet =
164 snippet::Snippet::new(full_path.into_os_string().into_string().unwrap(), &keywords);
165 Ok(vec![snippet])
166 }
167
168 OpCode::NewSnippet(location) => {
170 let path = path::Path::new(&location.local);
171
172 new_snippet("vim", path)?;
173 Ok(vec![])
174 }
175
176 OpCode::ListSnippets(_) => {
178 let files = find_snippets(&project)?;
179 let snippets = load_snippets(&files, &keywords)?;
180
181 Ok(snippets)
182 }
183
184 OpCode::PullSnippets => {
186 println!("Pulling snippet locations...");
187 for location in &project.locations {
188 if location.git == Some(true) {
190 git::git_pull(location)?;
191 }
192 }
193 Ok(vec![])
194 }
195
196 OpCode::SaveSnippets => {
198 println!("Saving snippets...");
199 for location in &project.locations {
200 if location.git == Some(true) {
202 git::determine_git_modified_status(location).and_then(|s| {
203 if let git::GitStatus::Modified = s {
204 println!("Enter your commit message: ");
205 let mut msg = String::new();
206 io::stdin().read_line(&mut msg)?;
207 git::git_add(location)?;
209 git::git_commit(location, msg)?;
211 git::git_push(location)?;
213 Ok(())
214 } else {
215 git::git_push(location)?;
217
218 Ok(())
219 }
220 })?;
221 };
222 }
223 Ok(vec![])
224 }
225 };
226 result
227}