diff --git a/bin/cob.rs b/bin/cob.rs index d9f817de..b20f2314 100644 --- a/bin/cob.rs +++ b/bin/cob.rs @@ -1,226 +1,3 @@ pub mod inbox; pub mod issue; pub mod patch; - -use std::path::{Path, PathBuf}; -use std::str::FromStr; - -use anyhow::Result; - -use radicle::cob::Label; -use radicle::git::Oid; -use radicle::prelude::Did; -use radicle_surf::diff::*; - -use radicle_cli::git::unified_diff::FileHeader; -use radicle_cli::git::unified_diff::HunkHeader; - -use crate::git::Blob; -use crate::git::Repo; -use crate::ui::items::Blobs; - -pub type FilePaths<'a> = (Option<(&'a Path, Oid)>, Option<(&'a Path, Oid)>); - -#[allow(dead_code)] -pub fn parse_labels(input: String) -> Result> { - let mut labels = vec![]; - if !input.is_empty() { - for name in input.split(',') { - match Label::new(name.trim()) { - Ok(label) => labels.push(label), - Err(err) => return Err(anyhow::anyhow!(err).context("Can't parse labels.")), - } - } - } - - Ok(labels) -} - -#[allow(dead_code)] -pub fn parse_assignees(input: String) -> Result> { - let mut assignees = vec![]; - if !input.is_empty() { - for did in input.split(',') { - match Did::from_str(&format!("did:key:{}", did)) { - Ok(did) => assignees.push(did), - Err(err) => return Err(anyhow::anyhow!(err).context("Can't parse assignees.")), - } - } - } - - Ok(assignees) -} - -pub enum DiffStats { - Hunk(HunkStats), - File(FileStats), -} - -#[derive(Default)] -pub struct HunkStats { - added: usize, - deleted: usize, -} - -impl HunkStats { - pub fn added(&self) -> usize { - self.added - } - pub fn deleted(&self) -> usize { - self.deleted - } -} - -impl From<&Hunk> for HunkStats { - fn from(hunk: &Hunk) -> Self { - let mut added = 0_usize; - let mut deleted = 0_usize; - - for modification in &hunk.lines { - match modification { - Modification::Addition(_) => added += 1, - Modification::Deletion(_) => deleted += 1, - _ => {} - } - } - - Self { added, deleted } - } -} - -#[derive(Clone, Default, Debug, PartialEq)] -pub enum HunkState { - #[default] - Rejected, - Accepted, -} - -/// A single review item. Can be a hunk or eg. a file move. -/// Files are usually split into multiple review items. -#[derive(Clone, Debug)] -pub enum HunkItem { - Added { - path: PathBuf, - header: FileHeader, - new: DiffFile, - hunk: Option>, - _stats: Option, - }, - Deleted { - path: PathBuf, - header: FileHeader, - old: DiffFile, - hunk: Option>, - _stats: Option, - }, - Modified { - path: PathBuf, - header: FileHeader, - old: DiffFile, - new: DiffFile, - hunk: Option>, - _stats: Option, - }, - Moved { - moved: Moved, - }, - Copied { - copied: Copied, - }, - EofChanged { - path: PathBuf, - header: FileHeader, - old: DiffFile, - new: DiffFile, - _eof: EofNewLine, - }, - ModeChanged { - path: PathBuf, - header: FileHeader, - old: DiffFile, - new: DiffFile, - }, -} - -impl HunkItem { - pub fn hunk(&self) -> Option<&Hunk> { - match self { - Self::Added { hunk, .. } => hunk.as_ref(), - Self::Deleted { hunk, .. } => hunk.as_ref(), - Self::Modified { hunk, .. } => hunk.as_ref(), - _ => None, - } - } - - pub fn file_header(&self) -> FileHeader { - match self { - Self::Added { header, .. } => header.clone(), - Self::Deleted { header, .. } => header.clone(), - Self::Moved { moved } => FileHeader::Moved { - old_path: moved.old_path.clone(), - new_path: moved.new_path.clone(), - }, - Self::Copied { copied } => FileHeader::Copied { - old_path: copied.old_path.clone(), - new_path: copied.new_path.clone(), - }, - Self::Modified { header, .. } => header.clone(), - Self::EofChanged { header, .. } => header.clone(), - Self::ModeChanged { header, .. } => header.clone(), - } - } - - pub fn hunk_header(&self) -> Option { - self.hunk().and_then(|h| HunkHeader::try_from(h).ok()) - } - - pub fn paths(&self) -> FilePaths { - match self { - Self::Added { path, new, .. } => (None, Some((path, new.oid))), - Self::Deleted { path, old, .. } => (Some((path, old.oid)), None), - Self::Moved { moved } => ( - Some((&moved.old_path, moved.old.oid)), - Some((&moved.new_path, moved.new.oid)), - ), - Self::Copied { copied } => ( - Some((&copied.old_path, copied.old.oid)), - Some((&copied.new_path, copied.new.oid)), - ), - Self::Modified { path, old, new, .. } => (Some((path, old.oid)), Some((path, new.oid))), - Self::EofChanged { path, old, new, .. } => { - (Some((path, old.oid)), Some((path, new.oid))) - } - Self::ModeChanged { path, old, new, .. } => { - (Some((path, old.oid)), Some((path, new.oid))) - } - } - } - - pub fn blobs(&self, repo: &R) -> Blobs<(PathBuf, Blob)> { - let (old, new) = self.paths(); - Blobs::from_paths(old, new, repo) - } -} - -#[derive(Clone, Debug)] -pub struct StatefulHunkItem(HunkItem, HunkState); - -impl StatefulHunkItem { - pub fn hunk(&self) -> &HunkItem { - &self.0 - } - - pub fn state(&self) -> &HunkState { - &self.1 - } - - pub fn state_mut(&mut self) -> &mut HunkState { - &mut self.1 - } -} - -impl From<(&HunkItem, &HunkState)> for StatefulHunkItem { - fn from(value: (&HunkItem, &HunkState)) -> Self { - Self(value.0.clone(), value.1.clone()) - } -} diff --git a/bin/commands/patch/review.rs b/bin/commands/patch/review.rs index 47f466f2..9202148a 100644 --- a/bin/commands/patch/review.rs +++ b/bin/commands/patch/review.rs @@ -36,8 +36,8 @@ use tui::ui::span; use tui::ui::Column; use tui::{Channel, Exit}; -use crate::cob::HunkState; -use crate::cob::StatefulHunkItem; +use crate::git::HunkState; +use crate::git::StatefulHunkDiff; use crate::tui_patch::review::builder::DiffUtil; use crate::ui::format; use crate::ui::items::HunkItem; @@ -202,7 +202,7 @@ impl<'a> App<'a> { .iter() .map(|(_, item, state)| { ( - HunkItem::from((&repo, &review, StatefulHunkItem::from((item, state)))), + HunkItem::from((&repo, &review, StatefulHunkDiff::from((item, state)))), HunkItemState { cursor: Position::new(0, 0), }, diff --git a/bin/commands/patch/review/builder.rs b/bin/commands/patch/review/builder.rs index 83455c1d..ad88884a 100644 --- a/bin/commands/patch/review/builder.rs +++ b/bin/commands/patch/review/builder.rs @@ -28,13 +28,13 @@ use radicle_cli::git::unified_diff::{self, FileHeader}; use radicle_cli::git::unified_diff::{Encode, HunkHeader}; use radicle_cli::terminal as term; -use crate::cob::{HunkItem, HunkState}; +use crate::git::{HunkDiff, HunkState}; /// Queue of items (usually hunks) left to review. #[derive(Clone, Default)] pub struct ReviewQueue { /// Hunks left to review. - queue: VecDeque<(usize, HunkItem, HunkState)>, + queue: VecDeque<(usize, HunkDiff, HunkState)>, } impl ReviewQueue { @@ -61,14 +61,14 @@ impl ReviewQueue { match file { FileDiff::Moved(moved) => { - self.add_item(HunkItem::Moved { moved }, state); + self.add_item(HunkDiff::Moved { moved }, state); } FileDiff::Copied(copied) => { - self.add_item(HunkItem::Copied { copied }, state); + self.add_item(HunkDiff::Copied { copied }, state); } FileDiff::Added(a) => { self.add_item( - HunkItem::Added { + HunkDiff::Added { path: a.path, header: header.clone(), new: a.new, @@ -88,7 +88,7 @@ impl ReviewQueue { } FileDiff::Deleted(d) => { self.add_item( - HunkItem::Deleted { + HunkDiff::Deleted { path: d.path, header: header.clone(), old: d.old, @@ -109,7 +109,7 @@ impl ReviewQueue { FileDiff::Modified(m) => { if m.old.mode != m.new.mode { self.add_item( - HunkItem::ModeChanged { + HunkDiff::ModeChanged { path: m.path.clone(), header: header.clone(), old: m.old.clone(), @@ -124,7 +124,7 @@ impl ReviewQueue { } DiffContent::Binary => { self.add_item( - HunkItem::Modified { + HunkDiff::Modified { path: m.path.clone(), header: header.clone(), old: m.old.clone(), @@ -142,7 +142,7 @@ impl ReviewQueue { } => { for hunk in hunks { self.add_item( - HunkItem::Modified { + HunkDiff::Modified { path: m.path.clone(), header: header.clone(), old: m.old.clone(), @@ -155,7 +155,7 @@ impl ReviewQueue { } if let EofNewLine::OldMissing | EofNewLine::NewMissing = eof { self.add_item( - HunkItem::EofChanged { + HunkDiff::EofChanged { path: m.path.clone(), header: header.clone(), old: m.old.clone(), @@ -171,13 +171,13 @@ impl ReviewQueue { } } - fn add_item(&mut self, item: HunkItem, state: HunkState) { + fn add_item(&mut self, item: HunkDiff, state: HunkState) { self.queue.push_back((self.queue.len(), item, state)); } } impl std::ops::Deref for ReviewQueue { - type Target = VecDeque<(usize, HunkItem, HunkState)>; + type Target = VecDeque<(usize, HunkDiff, HunkState)>; fn deref(&self) -> &Self::Target { &self.queue @@ -191,7 +191,7 @@ impl std::ops::DerefMut for ReviewQueue { } impl Iterator for ReviewQueue { - type Item = (usize, HunkItem, HunkState); + type Item = (usize, HunkDiff, HunkState); fn next(&mut self) -> Option { self.queue.pop_front() @@ -206,14 +206,14 @@ pub struct FileReviewBuilder { } impl FileReviewBuilder { - pub fn new(item: &HunkItem) -> Self { + pub fn new(item: &HunkDiff) -> Self { Self { delta: 0, header: item.file_header(), } } - pub fn set_item(&mut self, item: &HunkItem) -> &mut Self { + pub fn set_item(&mut self, item: &HunkDiff) -> &mut Self { let header = item.file_header(); if self.header != header { self.header = header; @@ -222,7 +222,7 @@ impl FileReviewBuilder { self } - pub fn item_diff(&mut self, item: &HunkItem) -> Result { + pub fn item_diff(&mut self, item: &HunkDiff) -> Result { let mut buf = Vec::new(); let mut writer = unified_diff::Writer::new(&mut buf); writer.encode(&self.header)?; diff --git a/bin/git.rs b/bin/git.rs index 33094dd4..c81be0d0 100644 --- a/bin/git.rs +++ b/bin/git.rs @@ -1,8 +1,15 @@ -use std::fs; use std::path::Path; +use std::{fs, path::PathBuf}; use radicle::git; use radicle::git::Oid; +use radicle_cli::git::unified_diff::{FileHeader, HunkHeader}; +use radicle_cli::terminal; +use radicle_cli::terminal::highlight::Highlighter; +use radicle_surf::diff::{Copied, DiffFile, EofNewLine, FileStats, Hunk, Modification, Moved}; +use ratatui::text::Line; + +pub type FilePaths<'a> = (Option<(&'a Path, Oid)>, Option<(&'a Path, Oid)>); /// Get the diff stats between two commits. /// Should match the default output of `git diff --stat` exactly. @@ -22,14 +29,6 @@ pub fn diff_stats( diff.stats() } -/// Blob returned by the [`Repo`] trait. -#[derive(PartialEq, Eq, Debug)] -pub enum Blob { - Binary, - Empty, - Plain(Vec), -} - /// A repository of Git blobs. pub trait Repo { /// Lookup a blob from the repo. @@ -70,3 +69,282 @@ impl Repo for git::raw::Repository { }) } } + +/// Blob returned by the [`Repo`] trait. +#[derive(PartialEq, Eq, Debug)] +pub enum Blob { + Binary, + Empty, + Plain(Vec), +} + +/// Blobs passed down to the hunk renderer. +#[derive(Clone, Debug)] +pub struct Blobs { + pub old: Option, + pub new: Option, +} + +impl Blobs { + pub fn new(old: Option, new: Option) -> Self { + Self { old, new } + } +} + +impl<'a> Blobs<(PathBuf, Blob)> { + pub fn highlight(self, mut hi: Highlighter) -> Blobs>> { + let mut blobs = Blobs::default(); + if let Some((path, Blob::Plain(content))) = &self.old { + blobs.old = hi + .highlight(path, content) + .map(|hi| { + hi.into_iter() + .map(|line| Line::raw(line.to_string())) + .collect::>() + }) + .ok(); + } + if let Some((path, Blob::Plain(content))) = &self.new { + blobs.new = hi + .highlight(path, content) + .map(|hi| { + hi.into_iter() + .map(|line| Line::raw(line.to_string())) + .collect::>() + }) + .ok(); + } + blobs + } + + pub fn _raw(self) -> Blobs>> { + let mut blobs = Blobs::default(); + if let Some((_, Blob::Plain(content))) = &self.old { + blobs.old = std::str::from_utf8(content) + .map(|lines| { + lines + .lines() + .map(terminal::Line::new) + .map(|line| Line::raw(line.to_string())) + .collect::>() + }) + .ok(); + } + if let Some((_, Blob::Plain(content))) = &self.new { + blobs.new = std::str::from_utf8(content) + .map(|lines| { + lines + .lines() + .map(terminal::Line::new) + .map(|line| Line::raw(line.to_string())) + .collect::>() + }) + .ok(); + } + blobs + } + + pub fn from_paths( + old: Option<(&Path, Oid)>, + new: Option<(&Path, Oid)>, + repo: &R, + ) -> Blobs<(PathBuf, Blob)> { + Blobs::new( + old.and_then(|(path, oid)| { + repo.blob(oid) + .ok() + .or_else(|| repo.file(path)) + .map(|blob| (path.to_path_buf(), blob)) + }), + new.and_then(|(path, oid)| { + repo.blob(oid) + .ok() + .or_else(|| repo.file(path)) + .map(|blob| (path.to_path_buf(), blob)) + }), + ) + } +} + +impl Default for Blobs { + fn default() -> Self { + Self { + old: None, + new: None, + } + } +} + +pub enum DiffStats { + Hunk(HunkStats), + File(FileStats), +} + +#[derive(Default)] +pub struct HunkStats { + added: usize, + deleted: usize, +} + +impl HunkStats { + pub fn added(&self) -> usize { + self.added + } + pub fn deleted(&self) -> usize { + self.deleted + } +} + +impl From<&Hunk> for HunkStats { + fn from(hunk: &Hunk) -> Self { + let mut added = 0_usize; + let mut deleted = 0_usize; + + for modification in &hunk.lines { + match modification { + Modification::Addition(_) => added += 1, + Modification::Deletion(_) => deleted += 1, + _ => {} + } + } + + Self { added, deleted } + } +} + +#[derive(Clone, Default, Debug, PartialEq)] +pub enum HunkState { + #[default] + Rejected, + Accepted, +} + +/// A single review item. Can be a hunk or eg. a file move. +/// Files are usually split into multiple review items. +#[derive(Clone, Debug)] +pub enum HunkDiff { + Added { + path: PathBuf, + header: FileHeader, + new: DiffFile, + hunk: Option>, + _stats: Option, + }, + Deleted { + path: PathBuf, + header: FileHeader, + old: DiffFile, + hunk: Option>, + _stats: Option, + }, + Modified { + path: PathBuf, + header: FileHeader, + old: DiffFile, + new: DiffFile, + hunk: Option>, + _stats: Option, + }, + Moved { + moved: Moved, + }, + Copied { + copied: Copied, + }, + EofChanged { + path: PathBuf, + header: FileHeader, + old: DiffFile, + new: DiffFile, + _eof: EofNewLine, + }, + ModeChanged { + path: PathBuf, + header: FileHeader, + old: DiffFile, + new: DiffFile, + }, +} + +impl HunkDiff { + pub fn hunk(&self) -> Option<&Hunk> { + match self { + Self::Added { hunk, .. } => hunk.as_ref(), + Self::Deleted { hunk, .. } => hunk.as_ref(), + Self::Modified { hunk, .. } => hunk.as_ref(), + _ => None, + } + } + + pub fn file_header(&self) -> FileHeader { + match self { + Self::Added { header, .. } => header.clone(), + Self::Deleted { header, .. } => header.clone(), + Self::Moved { moved } => FileHeader::Moved { + old_path: moved.old_path.clone(), + new_path: moved.new_path.clone(), + }, + Self::Copied { copied } => FileHeader::Copied { + old_path: copied.old_path.clone(), + new_path: copied.new_path.clone(), + }, + Self::Modified { header, .. } => header.clone(), + Self::EofChanged { header, .. } => header.clone(), + Self::ModeChanged { header, .. } => header.clone(), + } + } + + pub fn hunk_header(&self) -> Option { + self.hunk().and_then(|h| HunkHeader::try_from(h).ok()) + } + + pub fn paths(&self) -> FilePaths { + match self { + Self::Added { path, new, .. } => (None, Some((path, new.oid))), + Self::Deleted { path, old, .. } => (Some((path, old.oid)), None), + Self::Moved { moved } => ( + Some((&moved.old_path, moved.old.oid)), + Some((&moved.new_path, moved.new.oid)), + ), + Self::Copied { copied } => ( + Some((&copied.old_path, copied.old.oid)), + Some((&copied.new_path, copied.new.oid)), + ), + Self::Modified { path, old, new, .. } => (Some((path, old.oid)), Some((path, new.oid))), + Self::EofChanged { path, old, new, .. } => { + (Some((path, old.oid)), Some((path, new.oid))) + } + Self::ModeChanged { path, old, new, .. } => { + (Some((path, old.oid)), Some((path, new.oid))) + } + } + } + + pub fn blobs(&self, repo: &R) -> Blobs<(PathBuf, Blob)> { + let (old, new) = self.paths(); + Blobs::from_paths(old, new, repo) + } +} + +#[derive(Clone, Debug)] +pub struct StatefulHunkDiff(HunkDiff, HunkState); + +impl StatefulHunkDiff { + pub fn hunk(&self) -> &HunkDiff { + &self.0 + } + + pub fn state(&self) -> &HunkState { + &self.1 + } + + pub fn state_mut(&mut self) -> &mut HunkState { + &mut self.1 + } +} + +impl From<(&HunkDiff, &HunkState)> for StatefulHunkDiff { + fn from(value: (&HunkDiff, &HunkState)) -> Self { + Self(value.0.clone(), value.1.clone()) + } +} diff --git a/bin/ui/items.rs b/bin/ui/items.rs index e7832a6b..4f489c3f 100644 --- a/bin/ui/items.rs +++ b/bin/ui/items.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; -use std::path::{Path, PathBuf}; use std::str::FromStr; use nom::bytes::complete::{tag, take}; @@ -42,8 +41,7 @@ use tui::ui::utils::LineMerger; use tui::ui::{span, Column}; use tui::ui::{ToRow, ToTree}; -use crate::cob::{DiffStats, HunkStats, StatefulHunkItem}; -use crate::git::{Blob, Repo}; +use crate::git::{Blobs, DiffStats, HunkDiff, HunkStats, StatefulHunkDiff}; use crate::ui; use super::super::git; @@ -1095,7 +1093,7 @@ impl From)>> for HunkComments { #[derive(Clone, Debug)] pub struct HunkItem<'a> { /// The underlying hunk type and its current state (accepted / rejected). - pub inner: StatefulHunkItem, + pub inner: StatefulHunkDiff, /// Raw or highlighted hunk lines. Highlighting is expensive and needs to be asynchronously. /// Therefor, a hunks' lines need to stored separately. pub lines: Blobs>>, @@ -1103,20 +1101,20 @@ pub struct HunkItem<'a> { pub comments: HunkComments, } -impl<'a> From<(&Repository, &Review, StatefulHunkItem)> for HunkItem<'a> { - fn from(value: (&Repository, &Review, StatefulHunkItem)) -> Self { +impl<'a> From<(&Repository, &Review, StatefulHunkDiff)> for HunkItem<'a> { + fn from(value: (&Repository, &Review, StatefulHunkDiff)) -> Self { let (repo, review, item) = value; let hi = Highlighter::default(); let hunk = item.hunk(); let path = match &hunk { - crate::cob::HunkItem::Added { path, .. } => path, - crate::cob::HunkItem::Modified { path, .. } => path, - crate::cob::HunkItem::Deleted { path, .. } => path, - crate::cob::HunkItem::Copied { copied } => &copied.new_path, - crate::cob::HunkItem::Moved { moved } => &moved.new_path, - crate::cob::HunkItem::ModeChanged { path, .. } => path, - crate::cob::HunkItem::EofChanged { path, .. } => path, + HunkDiff::Added { path, .. } => path, + HunkDiff::Modified { path, .. } => path, + HunkDiff::Deleted { path, .. } => path, + HunkDiff::Copied { copied } => &copied.new_path, + HunkDiff::Moved { moved } => &moved.new_path, + HunkDiff::ModeChanged { path, .. } => path, + HunkDiff::EofChanged { path, .. } => path, }; // TODO(erikli): Start with raw, non-highlighted lines and @@ -1141,8 +1139,6 @@ impl<'a> From<(&Repository, &Review, StatefulHunkItem)> for HunkItem<'a> { impl<'a> ToRow<3> for HunkItem<'a> { fn to_row(&self) -> [Cell; 3] { - use crate::cob::HunkItem as Item; - let build_stats_spans = |stats: &DiffStats| -> Vec> { let mut cell = vec![]; @@ -1176,7 +1172,7 @@ impl<'a> ToRow<3> for HunkItem<'a> { }; match &self.inner.hunk() { - Item::Added { + HunkDiff::Added { path, header: _, new: _, @@ -1198,7 +1194,7 @@ impl<'a> ToRow<3> for HunkItem<'a> { Line::from(stats_cell).right_aligned().into(), ] } - Item::Modified { + HunkDiff::Modified { path, header: _, old: _, @@ -1221,7 +1217,7 @@ impl<'a> ToRow<3> for HunkItem<'a> { Line::from(stats_cell).right_aligned().into(), ] } - Item::Deleted { + HunkDiff::Deleted { path, header: _, old: _, @@ -1243,7 +1239,7 @@ impl<'a> ToRow<3> for HunkItem<'a> { Line::from(stats_cell).right_aligned().into(), ] } - Item::Copied { copied } => { + HunkDiff::Copied { copied } => { let stats = copied.diff.stats().copied().unwrap_or_default(); let stats_cell = [ build_stats_spans(&DiffStats::File(stats)), @@ -1259,7 +1255,7 @@ impl<'a> ToRow<3> for HunkItem<'a> { Line::from(stats_cell).right_aligned().into(), ] } - Item::Moved { moved } => { + HunkDiff::Moved { moved } => { let stats = moved.diff.stats().copied().unwrap_or_default(); let stats_cell = [ build_stats_spans(&DiffStats::File(stats)), @@ -1275,7 +1271,7 @@ impl<'a> ToRow<3> for HunkItem<'a> { Line::from(stats_cell).right_aligned().into(), ] } - Item::EofChanged { + HunkDiff::EofChanged { path, header: _, old: _, @@ -1290,7 +1286,7 @@ impl<'a> ToRow<3> for HunkItem<'a> { .right_aligned() .into(), ], - Item::ModeChanged { + HunkDiff::ModeChanged { path, header: _, old: _, @@ -1324,7 +1320,7 @@ impl<'a> HunkItem<'a> { }; match &self.inner.hunk() { - crate::cob::HunkItem::Added { + HunkDiff::Added { path, header: _, new: _, @@ -1352,7 +1348,7 @@ impl<'a> HunkItem<'a> { header.to_vec() } - crate::cob::HunkItem::Modified { + HunkDiff::Modified { path, header: _, old: _, @@ -1381,7 +1377,7 @@ impl<'a> HunkItem<'a> { header.to_vec() } - crate::cob::HunkItem::Deleted { + HunkDiff::Deleted { path, header: _, old: _, @@ -1408,7 +1404,7 @@ impl<'a> HunkItem<'a> { header.to_vec() } - crate::cob::HunkItem::Copied { copied } => { + HunkDiff::Copied { copied } => { let path = Line::from( [ ui::span::pretty_path(&copied.old_path, false, true), @@ -1433,7 +1429,7 @@ impl<'a> HunkItem<'a> { header.to_vec() } - crate::cob::HunkItem::Moved { moved } => { + HunkDiff::Moved { moved } => { let path = Line::from( [ ui::span::pretty_path(&moved.old_path, false, true), @@ -1459,7 +1455,7 @@ impl<'a> HunkItem<'a> { header.to_vec() } - crate::cob::HunkItem::EofChanged { + HunkDiff::EofChanged { path, header: _, old: _, @@ -1481,7 +1477,7 @@ impl<'a> HunkItem<'a> { header.to_vec() } - crate::cob::HunkItem::ModeChanged { + HunkDiff::ModeChanged { path, header: _, old: _, @@ -1506,12 +1502,10 @@ impl<'a> HunkItem<'a> { } pub fn hunk_text(&'a self) -> Option> { - use crate::cob::HunkItem; - match &self.inner.hunk() { - HunkItem::Added { hunk, .. } - | HunkItem::Modified { hunk, .. } - | HunkItem::Deleted { hunk, .. } => { + HunkDiff::Added { hunk, .. } + | HunkDiff::Modified { hunk, .. } + | HunkDiff::Deleted { hunk, .. } => { let mut lines = hunk .as_ref() .map(|hunk| Text::from(hunk.to_text(&self.lines))); @@ -1586,103 +1580,6 @@ impl<'a> HunkItem<'a> { } } -/// Blobs passed down to the hunk renderer. -#[derive(Clone, Debug)] -pub struct Blobs { - pub old: Option, - pub new: Option, -} - -impl Blobs { - pub fn new(old: Option, new: Option) -> Self { - Self { old, new } - } -} - -impl<'a> Blobs<(PathBuf, Blob)> { - pub fn highlight(self, mut hi: Highlighter) -> Blobs>> { - let mut blobs = Blobs::default(); - if let Some((path, Blob::Plain(content))) = &self.old { - blobs.old = hi - .highlight(path, content) - .map(|hi| { - hi.into_iter() - .map(|line| Line::raw(line.to_string())) - .collect::>() - }) - .ok(); - } - if let Some((path, Blob::Plain(content))) = &self.new { - blobs.new = hi - .highlight(path, content) - .map(|hi| { - hi.into_iter() - .map(|line| Line::raw(line.to_string())) - .collect::>() - }) - .ok(); - } - blobs - } - - pub fn _raw(self) -> Blobs>> { - let mut blobs = Blobs::default(); - if let Some((_, Blob::Plain(content))) = &self.old { - blobs.old = std::str::from_utf8(content) - .map(|lines| { - lines - .lines() - .map(terminal::Line::new) - .map(|line| Line::raw(line.to_string())) - .collect::>() - }) - .ok(); - } - if let Some((_, Blob::Plain(content))) = &self.new { - blobs.new = std::str::from_utf8(content) - .map(|lines| { - lines - .lines() - .map(terminal::Line::new) - .map(|line| Line::raw(line.to_string())) - .collect::>() - }) - .ok(); - } - blobs - } - - pub fn from_paths( - old: Option<(&Path, Oid)>, - new: Option<(&Path, Oid)>, - repo: &R, - ) -> Blobs<(PathBuf, Blob)> { - Blobs::new( - old.and_then(|(path, oid)| { - repo.blob(oid) - .ok() - .or_else(|| repo.file(path)) - .map(|blob| (path.to_path_buf(), blob)) - }), - new.and_then(|(path, oid)| { - repo.blob(oid) - .ok() - .or_else(|| repo.file(path)) - .map(|blob| (path.to_path_buf(), blob)) - }), - ) - } -} - -impl Default for Blobs { - fn default() -> Self { - Self { - old: None, - new: None, - } - } -} - pub struct HighlightedLine<'a>(Line<'a>); impl<'a> From> for HighlightedLine<'a> { diff --git a/bin/ui/span.rs b/bin/ui/span.rs index 519fa4ea..739b9a6b 100644 --- a/bin/ui/span.rs +++ b/bin/ui/span.rs @@ -3,7 +3,7 @@ use std::path::Path; use ratatui::prelude::Stylize; use ratatui::text::Span; -use crate::cob::HunkState; +use crate::git::HunkState; use radicle_tui as tui;