2022-08-21 00:59:09 +00:00
|
|
|
use std::fs;
|
|
|
|
use std::mem;
|
|
|
|
use std::path;
|
|
|
|
use std::process;
|
|
|
|
|
|
|
|
use crate::tasks;
|
|
|
|
use crate::error;
|
2022-08-25 06:40:56 +00:00
|
|
|
use crate::graph;
|
2022-08-21 06:43:42 +00:00
|
|
|
use crate::state;
|
2022-08-25 06:40:56 +00:00
|
|
|
use crate::colour;
|
2022-08-21 00:59:09 +00:00
|
|
|
use crate::tasks::Id;
|
|
|
|
|
2022-08-21 02:10:31 +00:00
|
|
|
pub fn open_editor(path : &path::Path, editor : &str) -> Result<process::ExitStatus, error::Error> {
|
|
|
|
let mut command = process::Command::new(editor);
|
2022-08-21 00:59:09 +00:00
|
|
|
|
2022-08-21 02:10:31 +00:00
|
|
|
command
|
|
|
|
.args(vec![&path]);
|
|
|
|
|
|
|
|
let mut child = command.spawn()?;
|
|
|
|
|
2022-08-21 06:43:42 +00:00
|
|
|
child.wait().map_err(error::Error::from)
|
2022-08-21 02:10:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn edit_info(id : Id, vault_folder : path::PathBuf, editor : &str) -> Result<(), error::Error> {
|
2022-08-21 06:43:42 +00:00
|
|
|
let mut task = tasks::Task::load(id, &vault_folder, false)?;
|
2022-08-21 00:59:09 +00:00
|
|
|
|
2022-08-21 02:10:31 +00:00
|
|
|
let temp_path = vault_folder.join("temp.md");
|
2022-08-21 00:59:09 +00:00
|
|
|
|
2022-08-21 06:43:42 +00:00
|
|
|
fs::write(&temp_path, &task.data.info.unwrap_or_default().as_bytes())?;
|
2022-08-21 00:59:09 +00:00
|
|
|
|
2022-08-21 02:10:31 +00:00
|
|
|
let status = open_editor(&temp_path, editor)?;
|
2022-08-21 00:59:09 +00:00
|
|
|
|
2022-08-21 02:10:31 +00:00
|
|
|
if !status.success() {
|
|
|
|
match status.code() {
|
|
|
|
Some(code) => Err(error::Error::Generic(format!("Process responded with a non-zero status code: {}", code))),
|
|
|
|
None => Err(error::Error::Generic(String::from("Process was interrupted by signal"))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
let file_contents = fs::read_to_string(&temp_path)?;
|
2022-08-21 00:59:09 +00:00
|
|
|
|
2022-08-21 02:10:31 +00:00
|
|
|
task.data.info = if file_contents.is_empty() {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Some(file_contents)
|
|
|
|
};
|
|
|
|
|
|
|
|
task.save()?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2022-08-21 00:59:09 +00:00
|
|
|
|
2022-08-21 06:43:42 +00:00
|
|
|
pub fn edit_raw(id : Id, vault_folder : path::PathBuf, editor : &str, state : &mut state::State) -> Result<(), error::Error> {
|
2022-08-21 02:10:31 +00:00
|
|
|
|
2022-08-21 06:43:42 +00:00
|
|
|
let mut task = tasks::Task::load(id, &vault_folder, false)?;
|
2022-08-21 02:10:31 +00:00
|
|
|
|
|
|
|
let temp_path = vault_folder.join("temp.toml");
|
|
|
|
|
2022-08-25 10:44:10 +00:00
|
|
|
fs::copy(&task.path, &temp_path)?;
|
2022-08-21 00:59:09 +00:00
|
|
|
|
2022-08-21 02:10:31 +00:00
|
|
|
let status = open_editor(&temp_path, editor)?;
|
|
|
|
|
2022-08-21 00:59:09 +00:00
|
|
|
if !status.success() {
|
|
|
|
match status.code() {
|
|
|
|
Some(code) => Err(error::Error::Generic(format!("Process responded with a non-zero status code: {}", code))),
|
|
|
|
None => Err(error::Error::Generic(String::from("Process was interrupted by signal"))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
let mut edited_task = tasks::Task::load_direct(temp_path.clone(), true)?;
|
|
|
|
|
|
|
|
if edited_task.data.id != task.data.id {
|
|
|
|
Err(error::Error::Generic(String::from("You cannot change the ID of a task in a direct edit")))
|
|
|
|
}
|
2022-08-21 06:43:42 +00:00
|
|
|
else if edited_task.data.name.chars().all(|c| c.is_numeric()) {
|
|
|
|
Err(error::Error::Generic(String::from("Name must not be purely numeric")))
|
|
|
|
}
|
2022-08-21 00:59:09 +00:00
|
|
|
else {
|
2022-08-25 06:40:56 +00:00
|
|
|
// Dependencies were edited so the graph needs to be updated.
|
2022-08-21 00:59:09 +00:00
|
|
|
if edited_task.data.dependencies != task.data.dependencies {
|
2022-08-25 06:40:56 +00:00
|
|
|
for dependency in &task.data.dependencies {
|
|
|
|
state.data.deps.remove_edge(id, *dependency);
|
|
|
|
}
|
|
|
|
|
|
|
|
for dependency in &edited_task.data.dependencies {
|
|
|
|
if state.data.deps.contains_node(*dependency) {
|
|
|
|
state.data.deps.insert_edge(id, *dependency)?;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return Err(error::Error::Generic(format!("No task with an ID of {} exists", colour::id(*dependency))));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(cycle) = state.data.deps.find_cycle() {
|
|
|
|
return Err(error::Error::Generic(format!("Note edit aborted due to circular dependency: {}", graph::format_cycle(&cycle))));
|
|
|
|
}
|
2022-08-21 00:59:09 +00:00
|
|
|
}
|
2022-08-21 06:43:42 +00:00
|
|
|
// Name change means index needs to be updated.
|
2022-08-21 00:59:09 +00:00
|
|
|
if edited_task.data.name != task.data.name {
|
2022-08-25 00:44:22 +00:00
|
|
|
state.data.index.remove(task.data.name.clone(), id);
|
|
|
|
state.data.index.insert(edited_task.data.name.clone(), id);
|
2022-08-21 00:59:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mem::swap(&mut edited_task.data, &mut task.data);
|
|
|
|
mem::drop(edited_task);
|
|
|
|
|
|
|
|
task.save()?;
|
|
|
|
|
2022-08-25 06:40:56 +00:00
|
|
|
trash::delete(&temp_path)?;
|
2022-08-21 00:59:09 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|