use std::path::PathBuf;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RebaseEntry {
pub hash: String,
pub short_hash: String,
pub message: String,
pub action: RebaseAction,
}
impl RebaseEntry {
pub fn new(hash: String, message: String, action: RebaseAction) -> Self {
let short_hash = hash.chars().take(7).collect();
Self {
hash,
short_hash,
message,
action,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RebaseAction {
Pick,
Reword,
Edit,
Squash,
Fixup,
Drop,
}
impl RebaseAction {
pub fn as_str(&self) -> &'static str {
match self {
RebaseAction::Pick => "pick",
RebaseAction::Reword => "reword",
RebaseAction::Edit => "edit",
RebaseAction::Squash => "squash",
RebaseAction::Fixup => "fixup",
RebaseAction::Drop => "drop",
}
}
pub fn from_str(s: &str) -> Option<Self> {
match s {
"pick" => Some(RebaseAction::Pick),
"reword" => Some(RebaseAction::Reword),
"edit" => Some(RebaseAction::Edit),
"squash" => Some(RebaseAction::Squash),
"fixup" => Some(RebaseAction::Fixup),
"drop" => Some(RebaseAction::Drop),
_ => None,
}
}
pub fn cycle_next(&self) -> Self {
match self {
RebaseAction::Pick => RebaseAction::Reword,
RebaseAction::Reword => RebaseAction::Edit,
RebaseAction::Edit => RebaseAction::Squash,
RebaseAction::Squash => RebaseAction::Fixup,
RebaseAction::Fixup => RebaseAction::Drop,
RebaseAction::Drop => RebaseAction::Pick,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RebasePhase {
Planning,
Active,
Conflict,
Recovery,
}
#[derive(Debug, Clone)]
pub struct RebaseSession {
pub phase: RebasePhase,
pub entries: Vec<RebaseEntry>,
pub cursor: usize,
pub todo_path: Option<PathBuf>,
pub base_commit: Option<String>,
pub use_root: bool,
pub dirty: bool,
}
impl Default for RebaseSession {
fn default() -> Self {
Self {
phase: RebasePhase::Planning,
entries: Vec::new(),
cursor: 0,
todo_path: None,
base_commit: None,
use_root: false,
dirty: false,
}
}
}
impl RebaseSession {
pub fn new() -> Self {
Self::default()
}
pub fn is_valid(&self) -> bool {
match self.phase {
RebasePhase::Planning => {
self.entries.iter().all(|entry| {
!entry.hash.is_empty() && !entry.short_hash.is_empty()
})
}
RebasePhase::Active | RebasePhase::Conflict => {
self.todo_path.is_some() && !self.entries.is_empty()
}
RebasePhase::Recovery => {
true }
}
}
pub fn current_entry(&self) -> Option<&RebaseEntry> {
self.entries.get(self.cursor)
}
pub fn move_cursor_up(&mut self) {
if self.cursor > 0 {
self.cursor -= 1;
}
}
pub fn move_cursor_down(&mut self) {
if self.cursor + 1 < self.entries.len() {
self.cursor += 1;
}
}
pub fn move_entry_up(&mut self) {
if self.cursor > 0 {
self.entries.swap(self.cursor, self.cursor - 1);
self.cursor -= 1;
self.dirty = true;
}
}
pub fn move_entry_down(&mut self) {
if self.cursor + 1 < self.entries.len() {
self.entries.swap(self.cursor, self.cursor + 1);
self.cursor += 1;
self.dirty = true;
}
}
}