Radish alpha
r
Radicle terminal user interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
bin: Improve hunk list in `patch review`
Erik Kundt committed 1 year ago
commit 7fb484cc14a1758b0d68130dd3a2b02d365c5457
parent 7cd6b390236245d2f0b0d09df7e495ed87aaefd6
4 files changed +218 -55
modified bin/cob.rs
@@ -54,6 +54,43 @@ pub fn parse_assignees(input: String) -> Result<Vec<Did>> {
    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<Modification>> for HunkStats {
+
    fn from(hunk: &Hunk<Modification>) -> 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 }
+
    }
+
}
+

/// A single review item. Can be a hunk or eg. a file move.
/// Files are usually split into multiple review items.
#[derive(Clone, Debug)]
modified bin/commands/patch/review.rs
@@ -7,11 +7,11 @@ use std::sync::Mutex;

use anyhow::Result;

-
use ratatui::text::Line;
use termion::event::Key;

use ratatui::layout::{Constraint, Layout};
use ratatui::style::Stylize;
+
use ratatui::text::Line;
use ratatui::text::Text;
use ratatui::{Frame, Viewport};

@@ -171,7 +171,7 @@ impl<'a> App<'a> {
        let columns = [
            Column::new(" ", Constraint::Length(1)),
            Column::new(" ", Constraint::Fill(1)),
-
            Column::new(" ", Constraint::Fill(1)),
+
            Column::new(" ", Constraint::Length(15)),
        ]
        .to_vec();
        let mut selected = self.queue.1.selected();
@@ -317,14 +317,40 @@ impl<'a> App<'a> {
                            Column::new(path.clone(), Constraint::Length(path.width() as u16)),
                            Column::new(
                                span::default(" copied ")
-
                                    .light_red()
+
                                    .light_blue()
                                    .dim()
                                    .reversed()
                                    .into_right_aligned_line(),
                                Constraint::Fill(1),
                            ),
                        ];
-
                        ui.columns(frame, header.clone().to_vec(), Some(Borders::Top));
+

+
                        // let hunk = match &copied.diff {
+
                        //     DiffContent::Plain {
+
                        //         hunks,
+
                        //         stats: _,
+
                        //         eof: _,
+
                        //     } => {
+
                        //         log::info!("{:?}", hunks);
+
                        //         let text = hunks.iter().fold(Text::raw(""), |mut text, hunk| {
+
                        //             text.extend(Text::from(hunk.to_text(
+
                        //                 &mut hi,
+
                        //                 &item.highlighted,
+
                        //                 repo.raw(),
+
                        //             )));
+
                        //             text
+
                        //         });
+

+
                        //         Some(text)
+
                        //     }
+
                        //     DiffContent::Binary => {
+
                        //         Some(Text::raw("Binary files cannot be viewed."))
+
                        //     }
+
                        //     DiffContent::Empty => Some(Text::raw("")),
+
                        // };
+
                        // let hunk = hunk.unwrap_or_default();
+

+
                        ui.columns(frame, header.clone().to_vec(), Some(Borders::All));
                    }
                    (_, crate::cob::ReviewItem::FileMoved { moved }) => {
                        let path = Line::from(
modified bin/commands/patch/review/builder.rs
@@ -481,6 +481,14 @@ impl<'a, G: Signer> ReviewBuilder<'a, G> {
        let repo = self.repo.raw();
        let tree = {
            let commit = repo.find_commit(revision.head().into())?;
+

+
            log::info!(
+
                "Loading queue patch: Patch[commit({}), tree({})], Brain[tree({})]",
+
                commit.id(),
+
                commit.tree()?.id(),
+
                &brain.accepted().id()
+
            );
+

            commit.tree()?
        };

modified bin/ui/items.rs
@@ -42,7 +42,7 @@ use tui::ui::span;
use tui::ui::theme::style;
use tui::ui::{ToRow, ToTree};

-
use crate::cob::IndexedReviewItem;
+
use crate::cob::{DiffStats, HunkStats, IndexedReviewItem};
use crate::git::{Blob, Repo};

use super::super::git;
@@ -1063,86 +1063,178 @@ impl<'a> From<(&Repository, &IndexedReviewItem)> for ReviewItem<'a> {
impl<'a> ToRow<3> for ReviewItem<'a> {
    fn to_row(&self) -> [Cell; 3] {
        use crate::cob::ReviewItem as Item;
+

+
        let build_stats_spans = |stats: &DiffStats| -> Vec<Span<'_>> {
+
            let mut cell = vec![];
+

+
            let (added, deleted) = match stats {
+
                DiffStats::Hunk(stats) => (stats.added(), stats.deleted()),
+
                DiffStats::File(stats) => (stats.additions, stats.deletions),
+
            };
+

+
            if added > 0 {
+
                cell.push(span::default(&format!("+{}", added)).light_green().dim());
+
            }
+

+
            if added > 0 && deleted > 0 {
+
                cell.push(span::default(",").dim());
+
            }
+

+
            if deleted > 0 {
+
                cell.push(span::default(&format!("-{}", deleted)).light_red().dim());
+
            }
+

+
            cell
+
        };
+

        match &self.inner {
            (
-
                idx,
+
                _,
                Item::FileAdded {
-
                    path: _,
+
                    path,
                    header: _,
                    new: _,
-
                    hunk: _,
+
                    hunk,
                    stats: _,
                },
-
            ) => [
-
                span::secondary("?").into(),
-
                span::default(&format!("Hunk {}", idx)).into(),
-
                span::default("").into(),
-
            ],
-
            (idx, Item::FileCopied { copied: _ }) => [
-
                span::secondary("?").into(),
-
                span::default(&format!("Hunk {}", idx)).into(),
-
                span::default("").into(),
-
            ],
+
            ) => {
+
                let stats = hunk
+
                    .as_ref()
+
                    .map(|hunk| HunkStats::from(hunk))
+
                    .unwrap_or_default();
+
                let stats_cell = [
+
                    build_stats_spans(&DiffStats::Hunk(stats)),
+
                    [span::default(" A ").bold().light_green().dim()].to_vec(),
+
                ]
+
                .concat();
+

+
                [
+
                    span::secondary("?").into(),
+
                    ReviewItem::pretty_path(path, false).into(),
+
                    Line::from(stats_cell).right_aligned().into(),
+
                ]
+
            }
            (
-
                idx,
-
                Item::FileDeleted {
-
                    path: _,
+
                _,
+
                Item::FileModified {
+
                    path,
                    header: _,
                    old: _,
-
                    hunk: _,
+
                    new: _,
+
                    hunk,
                    stats: _,
                },
-
            ) => [
-
                span::secondary("?").into(),
-
                span::default(&format!("Hunk {}", idx)).into(),
-
                span::default("").into(),
-
            ],
+
            ) => {
+
                let stats = hunk
+
                    .as_ref()
+
                    .map(|hunk| HunkStats::from(hunk))
+
                    .unwrap_or_default();
+
                let stats_cell = [
+
                    build_stats_spans(&DiffStats::Hunk(stats)),
+
                    [span::default(" M ").bold().light_yellow().dim()].to_vec(),
+
                ]
+
                .concat();
+

+
                [
+
                    span::secondary("?").into(),
+
                    ReviewItem::pretty_path(path, false).into(),
+
                    Line::from(stats_cell).right_aligned().into(),
+
                ]
+
            }
            (
-
                idx,
-
                Item::FileEofChanged {
-
                    path: _,
+
                _,
+
                Item::FileDeleted {
+
                    path,
                    header: _,
                    old: _,
-
                    new: _,
-
                    eof: _,
+
                    hunk,
+
                    stats: _,
                },
-
            ) => [
-
                span::secondary("?").into(),
-
                span::default(&format!("Hunk {}", idx)).into(),
-
                span::default("").into(),
-
            ],
+
            ) => {
+
                let stats = hunk
+
                    .as_ref()
+
                    .map(|hunk| HunkStats::from(hunk))
+
                    .unwrap_or_default();
+
                let stats_cell = [
+
                    build_stats_spans(&DiffStats::Hunk(stats)),
+
                    [span::default(" D ").bold().light_red().dim()].to_vec(),
+
                ]
+
                .concat();
+

+
                [
+
                    span::secondary("?").into(),
+
                    ReviewItem::pretty_path(path, true).into(),
+
                    Line::from(stats_cell).right_aligned().into(),
+
                ]
+
            }
+
            (_, Item::FileCopied { copied }) => {
+
                let stats = copied
+
                    .diff
+
                    .stats()
+
                    .map(|stats| stats.clone())
+
                    .unwrap_or_default();
+
                let stats_cell = [
+
                    build_stats_spans(&DiffStats::File(stats)),
+
                    [span::default(" CP ").bold().light_blue().dim()].to_vec(),
+
                ]
+
                .concat();
+

+
                [
+
                    span::secondary("?").into(),
+
                    ReviewItem::pretty_path(&copied.new_path, false).into(),
+
                    Line::from(stats_cell).right_aligned().into(),
+
                ]
+
            }
+
            (_, Item::FileMoved { moved }) => {
+
                let stats = moved
+
                    .diff
+
                    .stats()
+
                    .map(|stats| stats.clone())
+
                    .unwrap_or_default();
+
                let stats_cell = [
+
                    build_stats_spans(&DiffStats::File(stats)),
+
                    [span::default(" MV ").bold().light_blue().dim()].to_vec(),
+
                ]
+
                .concat();
+

+
                [
+
                    span::secondary("?").into(),
+
                    ReviewItem::pretty_path(&moved.new_path, false).into(),
+
                    Line::from(stats_cell).right_aligned().into(),
+
                ]
+
            }
            (
-
                idx,
-
                Item::FileModeChanged {
-
                    path: _,
+
                _,
+
                Item::FileEofChanged {
+
                    path,
                    header: _,
                    old: _,
                    new: _,
+
                    eof: _,
                },
            ) => [
                span::secondary("?").into(),
-
                span::default(&format!("Hunk {}", idx)).into(),
-
                span::default("").into(),
+
                ReviewItem::pretty_path(path, false).into(),
+
                span::default("EOF ")
+
                    .light_blue()
+
                    .into_right_aligned_line()
+
                    .into(),
            ],
            (
-
                idx,
-
                Item::FileModified {
-
                    path: _,
+
                _,
+
                Item::FileModeChanged {
+
                    path,
                    header: _,
                    old: _,
                    new: _,
-
                    hunk: _,
-
                    stats: _,
                },
            ) => [
                span::secondary("?").into(),
-
                span::default(&format!("Hunk {}", idx)).into(),
-
                span::default("").into(),
-
            ],
-
            (idx, Item::FileMoved { moved: _ }) => [
-
                span::secondary("?").into(),
-
                span::default(&format!("Hunk {}", idx)).into(),
-
                span::default("").into(),
+
                ReviewItem::pretty_path(path, false).into(),
+
                span::default("FM ")
+
                    .light_blue()
+
                    .into_right_aligned_line()
+
                    .into(),
            ],
        }
    }
@@ -1153,7 +1245,7 @@ impl<'a> ReviewItem<'a> {
        let file = path.file_name().unwrap_or_default();
        let path = if path.iter().count() > 1 {
            path.into_iter()
-
                .take(path.into_iter().count() - 2)
+
                .take(path.into_iter().count() - 1)
                .map(|component| component.to_string_lossy().to_string())
                .collect::<Vec<_>>()
        } else {