summaryrefslogtreecommitdiffstats
path: root/src/todo_file/mod.rs
diff options
context:
space:
mode:
authorTim Oram <dev@mitmaro.ca>2020-10-29 11:53:55 -0230
committerTim Oram <dev@mitmaro.ca>2020-10-29 21:23:19 -0230
commit337daa271780f95b4b19e4e9399cf59d236eb5df (patch)
tree918212621c5b9bc02f5978135490e622178b5410 /src/todo_file/mod.rs
parent4cd7109b36d200b252c36dd29b23eb5c26a03989 (diff)
Move git interactive to todo file module
The GitInteractive stuct is one of the oldest structs in the project and was initially used as a catch-all for any functionality that was shared across the application. Overtime the functionality of this file has been moved into the various modules of the project. At this point, the only thing the struct handles is the direct interactions with the rebase todo file and it's lines. This finally moves the global stuct into a module.
Diffstat (limited to 'src/todo_file/mod.rs')
-rw-r--r--src/todo_file/mod.rs164
1 files changed, 164 insertions, 0 deletions
diff --git a/src/todo_file/mod.rs b/src/todo_file/mod.rs
new file mode 100644
index 0000000..a7c143d
--- /dev/null
+++ b/src/todo_file/mod.rs
@@ -0,0 +1,164 @@
+use crate::list::action::Action;
+use crate::list::line::Line;
+use anyhow::{anyhow, Result};
+use std::fs::{read_to_string, File};
+use std::io::Write;
+use std::path::Path;
+
+pub struct EditContext {
+ action: Option<Action>,
+ content: Option<String>,
+}
+
+impl EditContext {
+ pub const fn new() -> Self {
+ Self {
+ action: None,
+ content: None,
+ }
+ }
+
+ pub const fn action(mut self, action: Action) -> Self {
+ self.action = Some(action);
+ self
+ }
+
+ pub fn content(mut self, content: &str) -> Self {
+ self.content = Some(content.to_string());
+ self
+ }
+
+ pub const fn get_action(&self) -> &Option<Action> {
+ &self.action
+ }
+
+ pub const fn get_content(&self) -> &Option<String> {
+ &self.content
+ }
+}
+
+pub struct TodoFile {
+ comment_char: String,
+ filepath: String,
+ is_noop: bool,
+ lines: Vec<Line>,
+ selected_line_index: usize,
+}
+
+impl TodoFile {
+ pub(crate) fn new(path: &str, comment_char: &str) -> Self {
+ Self {
+ comment_char: comment_char.to_string(),
+ filepath: path.to_string(),
+ lines: vec![],
+ is_noop: false,
+ selected_line_index: 1,
+ }
+ }
+
+ pub(crate) fn set_lines(&mut self, lines: Vec<Line>) {
+ self.is_noop = !lines.is_empty() && lines[0].get_action() == &Action::Noop;
+ self.lines = if self.is_noop {
+ vec![]
+ }
+ else {
+ lines.into_iter().filter(|l| l.get_action() != &Action::Noop).collect()
+ };
+ }
+
+ pub(crate) fn load_file(&mut self) -> Result<()> {
+ let lines = read_to_string(Path::new(&self.filepath))
+ .map_err(|err| anyhow!("Error reading file: {}", self.filepath).context(err))?
+ .lines()
+ .filter_map(|l| {
+ if l.starts_with(self.comment_char.as_str()) || l.is_empty() {
+ None
+ }
+ else {
+ Some(Line::new(l).map_err(|err| anyhow!("Error reading file: {}", self.filepath).context(err)))
+ }
+ })
+ .collect::<Result<Vec<Line>>>()?;
+ self.set_lines(lines);
+ Ok(())
+ }
+
+ pub(crate) fn write_file(&self) -> Result<()> {
+ let mut file = File::create(&self.filepath)
+ .map_err(|err| anyhow!(err).context(anyhow!("Error opening file: {}", self.filepath)))?;
+ let file_contents = if self.is_noop {
+ String::from("noop")
+ }
+ else {
+ self.lines.iter().map(Line::to_text).collect::<Vec<String>>().join("\n")
+ };
+ writeln!(file, "{}", file_contents)
+ .map_err(|err| anyhow!(err).context(anyhow!("Error writing file: {}", self.filepath)))?;
+ Ok(())
+ }
+
+ pub(crate) fn set_noop(&mut self) {
+ self.is_noop = true;
+ self.lines.clear();
+ }
+
+ pub(crate) fn set_selected_line_index(&mut self, selected_line_index: usize) {
+ self.selected_line_index = selected_line_index;
+ }
+
+ pub(crate) fn swap_lines(&mut self, a: usize, b: usize) {
+ self.lines.swap(a, b);
+ }
+
+ pub(crate) fn add_line(&mut self, line_number: usize, line: Line) {
+ self.lines.insert(line_number - 1, line);
+ }
+
+ pub(crate) fn remove_line(&mut self, line_number: usize) {
+ self.lines.remove(line_number - 1);
+ }
+
+ pub(crate) fn update_selected(&mut self, edit_context: &EditContext) {
+ self.update_range(self.selected_line_index, self.selected_line_index, edit_context);
+ }
+
+ pub(crate) fn update_range(&mut self, start_index: usize, end_index: usize, edit_context: &EditContext) {
+ let range = if end_index <= start_index {
+ end_index..=start_index
+ }
+ else {
+ start_index..=end_index
+ };
+
+ for index in range {
+ let line = &mut self.lines[index - 1];
+ if let Some(action) = edit_context.get_action().as_ref() {
+ line.set_action(*action);
+ }
+
+ if let Some(content) = edit_context.get_content().as_ref() {
+ line.edit_content(content);
+ }
+ }
+ }
+
+ pub(crate) fn get_selected_line(&self) -> &Line {
+ &self.lines[self.selected_line_index - 1]
+ }
+
+ pub(crate) const fn get_selected_line_index(&self) -> usize {
+ self.selected_line_index
+ }
+
+ pub(crate) fn get_filepath(&self) -> &str {
+ self.filepath.as_str()
+ }
+
+ pub(crate) const fn get_lines(&self) -> &Vec<Line> {
+ &self.lines
+ }
+
+ pub(crate) const fn is_noop(&self) -> bool {
+ self.is_noop
+ }
+}