From 83f8df166bc8c6a786416ad64ea1b3ec56a0c259 Mon Sep 17 00:00:00 2001 From: LukeHalasy Date: Fri, 6 Oct 2023 20:56:17 -0400 Subject: [PATCH] adds the ability to view stash in status window and pop individual stash entry --- src/main.rs | 4 +- src/status.rs | 156 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 118 insertions(+), 42 deletions(-) diff --git a/src/main.rs b/src/main.rs index ec3a06d..54cd84e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -258,7 +258,9 @@ See https://github.com/Piturnah/gex/issues/13.", MessageType::Error); state.status.fetch(&state.repo, &config.options)?; } KeyCode::Char('u') => { - if state.status.cursor + if state.status.cursor >= state.status.file_diffs.len() { + state.status.stash_pop()?; + } else if state.status.cursor >= state.status.count_untracked + state.status.count_unstaged { state.status.unstage()?; diff --git a/src/status.rs b/src/status.rs index 9937424..a22547a 100644 --- a/src/status.rs +++ b/src/status.rs @@ -18,10 +18,11 @@ use nom::{bytes::complete::take_until, IResult}; use crate::{ config::{Config, Options, CONFIG}, - git_process, + debug, git_process, minibuffer::{MessageType, MiniBuffer}, parse::{self, parse_hunk_new, parse_hunk_old}, render::{self, Renderer, ResetAttributes, ResetColor}, + status, }; pub trait Expand { @@ -284,6 +285,7 @@ pub struct Status { pub count_unstaged: usize, pub count_staged: usize, pub cursor: usize, + pub stash_list: Vec, // pub stash_list: Vec, } impl render::Render for Status { @@ -367,6 +369,32 @@ impl render::Render for Status { writeln!(f, "{ResetAttributes}")?; } + if !self.stash_list.is_empty() { + writeln!( + f, + "\r\n{}Stash {}{}({}){}", + style::SetForegroundColor(config.colors.heading), + ResetColor, + style::Attribute::Dim, + self.stash_list.len(), + ResetAttributes + )?; + + for (i, stash) in self.stash_list.iter().enumerate() { + if let Some(stash_cursor) = self.cursor.checked_sub(self.file_diffs.len()) { + if i == stash_cursor { + let mut stash = stash.to_string(); + stash.insert_str(0, &format!("{}", Attribute::Reverse)); + write!(&mut stash, "{ResetAttributes}")?; + f.insert_cursor(); + writeln!(f, "\r{stash}")?; + continue; + } + } + writeln!(f, "\r{stash}")?; + } + } + Ok(()) } } @@ -556,6 +584,14 @@ impl Status { file_diff.selected = true; } + let stash_list_output = git_process(&["stash", "list"])?; + + self.stash_list = std::str::from_utf8(&stash_list_output.stdout) + .context("broken stdout from `git stash list`")? + .lines() + .map(|l| l.to_string()) + .collect::>(); + Ok(()) } @@ -781,31 +817,45 @@ impl Status { /// Move the cursor up one pub fn up(&mut self) -> Result<()> { - if self.file_diffs.is_empty() { - return Ok(()); - } - - let file = self - .file_diffs - .get_mut(self.cursor) - .context("cursor is at invalid position")?; + let count_file_diffs = self.file_diffs.len(); - if file.up().is_err() { - match self.cursor.checked_sub(1) { - Some(v) => { - self.cursor = v; - file.selected = false; - let new_file = self - .file_diffs - .get_mut(self.cursor) - .context("cursor at invalid position")?; - new_file.selected = true; - if new_file.expanded() { - new_file.cursor_last(); + if let Some(file) = self.file_diffs.get_mut(self.cursor) { + if file.up().is_err() { + match self.cursor.checked_sub(1) { + Some(v) => { + self.cursor = v; + file.selected = false; + let new_file = self + .file_diffs + .get_mut(self.cursor) + .context("cursor at invalid position")?; + new_file.selected = true; + if new_file.expanded() { + new_file.cursor_last(); + } } + None => self.cursor = 0, } - None => self.cursor = 0, } + } else if let Some(_) = self.stash_list.get(self.cursor - self.file_diffs.len()) { + if self.cursor - self.file_diffs.len() == 0 { + if count_file_diffs == 0 { + return Ok(()); + } + + self.cursor -= 1; + let new_file = self + .file_diffs + .get_mut(self.cursor) + .context("cursor at invalid position")?; + new_file.selected = true; + if new_file.expanded() { + new_file.cursor_last(); + } + return Ok(()); + } + + self.cursor -= 1; } Ok(()) @@ -813,31 +863,40 @@ impl Status { /// Move the cursor down one pub fn down(&mut self) -> Result<()> { - if self.file_diffs.is_empty() { - return Ok(()); - } - let count_file_diffs = self.file_diffs.len(); - let file = self - .file_diffs - .get_mut(self.cursor) - .context("cursor is at invalid position")?; + let count_stash_list = self.stash_list.len(); + + if let Some(file) = self.file_diffs.get_mut(self.cursor) { + if file.down().is_err() { + if self.cursor + 1 >= count_file_diffs { + if count_stash_list != 0 { + // advance to stash list + self.cursor += 1; + file.selected = false; + debug!("IN FILE SECTION: CURSOR COUNT: {:?}", self.cursor) + } + return Ok(()); + } - if file.down().is_err() { - if self.cursor + 1 >= count_file_diffs { + self.cursor += 1; + file.selected = false; + let new_file = self + .file_diffs + .get_mut(self.cursor) + .context("cursor at invalid position")?; + new_file.selected = true; + if new_file.expanded() { + new_file.cursor_first(); + } + } + } else if let Some(_) = self.stash_list.get(self.cursor - self.file_diffs.len()) { + if self.cursor + 1 >= count_file_diffs + count_stash_list { + debug!("returning ok"); return Ok(()); } self.cursor += 1; - file.selected = false; - let new_file = self - .file_diffs - .get_mut(self.cursor) - .context("cursor at invalid position")?; - new_file.selected = true; - if new_file.expanded() { - new_file.cursor_first(); - } + debug!("CURSOR COUNT: {:?}", self.cursor); } Ok(()) @@ -882,4 +941,19 @@ impl Status { new_file.selected = true; Ok(()) } + + pub(crate) fn stash_pop(&self) -> Result<()> { + let stash_entry = self + .stash_list + .get(self.cursor - self.file_diffs.len()) + .context("cursor at an invalid position")?; + + if let Some(start) = stash_entry.find("{") { + if let Some(end) = stash_entry.find("}") { + git_process(&["stash", "pop", &stash_entry[start + 1..end]])?; + } + } + + Ok(()) + } }