From 94a8b030ea65f1924c544bb8c8c3268420e8466d Mon Sep 17 00:00:00 2001 From: altsem Date: Sun, 9 Nov 2025 14:09:24 +0100 Subject: [PATCH 01/11] feat: remove Ratatui dep. Rendering is now simpler, no double-buffering and diffing. --- src/app.rs | 7 +- src/term.rs | 123 +++++++++++++++--- .../gitu__tests__branch__checkout_picker.snap | 2 +- .../gitu__tests__branch__delete_picker.snap | 2 +- .../gitu__tests__branch__rename_picker.snap | 2 +- ...ests__cherry_pick__cherry_pick_prompt.snap | 2 +- ...ts__editor__re_enter_picker_from_menu.snap | 2 +- .../gitu__tests__merge__merge_picker.snap | 2 +- ...sts__merge__merge_picker_custom_input.snap | 2 +- ...ests__rebase__rebase_elsewhere_prompt.snap | 2 +- src/ui.rs | 102 +++++++++++++-- 11 files changed, 204 insertions(+), 44 deletions(-) diff --git a/src/app.rs b/src/app.rs index a9d42b39ed..9b08c7ee6e 100644 --- a/src/app.rs +++ b/src/app.rs @@ -250,9 +250,7 @@ impl App { pub fn redraw_now(&mut self, term: &mut Term) -> Res<()> { if self.state.screens.last_mut().is_some() { - term.draw(|frame| ui::ui(frame, &mut self.state)) - .map_err(Error::Term)?; - + ui::ui(term.backend_mut(), &mut self.state)?; self.state.needs_redraw = false; }; @@ -431,8 +429,7 @@ impl App { let log_entry = self.state.current_cmd_log.push_cmd(&cmd); - term.draw(|frame| ui::ui(frame, &mut self.state)) - .map_err(Error::Term)?; + ui::ui(term.backend_mut(), &mut self.state)?; let mut child = cmd.spawn().map_err(Error::SpawnCmd)?; diff --git a/src/term.rs b/src/term.rs index 4361bf45b1..467d155049 100644 --- a/src/term.rs +++ b/src/term.rs @@ -1,17 +1,23 @@ use crate::{Res, config::Config, error::Error}; use crossterm::{ - ExecutableCommand, cursor, + QueueableCommand, + cursor::{self, MoveTo}, event::{DisableMouseCapture, EnableMouseCapture, Event}, + style::{Attribute, Colors, Print, SetAttribute, SetColors}, terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode}, }; use ratatui::{ Terminal, backend::{Backend, CrosstermBackend, TestBackend}, + buffer::Cell, layout::Size, - prelude::{Position, backend::WindowSize, buffer::Cell}, + prelude::{Position, backend::WindowSize}, + style::{Color, Style}, }; use std::io::{self, Stdout, stdout}; use std::time::Duration; +use unicode_segmentation::UnicodeSegmentation; +use unicode_width::UnicodeWidthStr; pub type Term = Terminal; @@ -28,6 +34,93 @@ pub enum TermBackend { }, } +impl TermBackend { + pub(crate) fn queue_move_cursor(&mut self, x: u16, y: u16) -> Res<()> { + match self { + TermBackend::Crossterm(t) => crossterm::queue!(t, MoveTo(x, y)).map_err(Error::Term), + TermBackend::Test { backend, .. } => backend + .set_cursor_position(Position::new(x, y)) + .map_err(Error::Term), + } + } + + pub fn queue_print(&mut self, text: &str, style: &Style) -> Res<()> { + match self { + TermBackend::Crossterm(t) => { + print_crossterm_span(text, style, t).map_err(Error::Term)?; + + Ok(()) + } + TermBackend::Test { backend, .. } => { + print_test_span(text, style, backend).map_err(Error::Term) + } + } + } +} + +const ATTRS: &[(ratatui::style::Modifier, Attribute)] = &[ + (ratatui::style::Modifier::BOLD, Attribute::Bold), + (ratatui::style::Modifier::DIM, Attribute::Dim), + (ratatui::style::Modifier::ITALIC, Attribute::Italic), + (ratatui::style::Modifier::UNDERLINED, Attribute::Underlined), + (ratatui::style::Modifier::SLOW_BLINK, Attribute::SlowBlink), + (ratatui::style::Modifier::RAPID_BLINK, Attribute::RapidBlink), + (ratatui::style::Modifier::REVERSED, Attribute::Reverse), + (ratatui::style::Modifier::HIDDEN, Attribute::Hidden), + (ratatui::style::Modifier::CROSSED_OUT, Attribute::CrossedOut), +]; + +fn print_crossterm_span( + text: &str, + style: &Style, + t: &mut CrosstermBackend, +) -> Result<(), io::Error> { + let fg = style.fg.unwrap_or(Color::Reset); + let bg = style.bg.unwrap_or(Color::Reset); + + crossterm::queue!(t, SetAttribute(Attribute::Reset))?; + + for (modifier, attribute) in ATTRS { + if style.add_modifier.contains(*modifier) { + crossterm::queue!(t, SetAttribute(*attribute))?; + } + } + + crossterm::queue!(t, SetColors(Colors::new(fg.into(), bg.into())))?; + crossterm::queue!(t, Print(text))?; + Ok(()) +} + +fn print_test_span(text: &str, style: &Style, backend: &mut TestBackend) -> io::Result<()> { + let Position { x, y } = backend.get_cursor_position()?; + let width = backend.size()?.width; + + let mut cells = Vec::new(); + let mut cx = x; + for grapheme in text.graphemes(true) { + let grapheme_width = grapheme.width() as u16; + if grapheme_width == 0 || cx >= width { + continue; + } + + let mut cell = Cell::default(); + cell.set_symbol(grapheme).set_style(*style); + cells.push((cx, y, cell)); + cx += 1; + + for _ in 1..grapheme_width { + if cx >= width { + break; + } + cells.push((cx, y, Cell::default())); + cx += 1; + } + } + + backend.draw(cells.iter().map(|(x, y, cell)| (*x, *y, cell)))?; + backend.set_cursor_position(Position::new(cx, y)) +} + impl Backend for TermBackend { fn draw<'a, I>(&mut self, content: I) -> io::Result<()> where @@ -97,24 +190,14 @@ impl Backend for TermBackend { } impl TermBackend { - pub fn enter_alternate_screen(&mut self) -> Res<()> { - match self { - TermBackend::Crossterm(c) => c - .execute(EnterAlternateScreen) - .map_err(Error::Term) - .map(|_| ()), - TermBackend::Test { .. } => Ok(()), - } - } - pub fn setup_term(&mut self, config: &Config) -> io::Result<()> { match self { TermBackend::Crossterm(crossterm_backend) => { enable_raw_mode()?; - crossterm_backend.execute(EnterAlternateScreen)?; - crossterm_backend.execute(cursor::Hide)?; + crossterm_backend.queue(EnterAlternateScreen)?; + crossterm_backend.queue(cursor::Hide)?; if config.general.mouse_support { - crossterm_backend.execute(EnableMouseCapture)?; + crossterm_backend.queue(EnableMouseCapture)?; } } TermBackend::Test { .. } => {} @@ -127,10 +210,10 @@ impl TermBackend { match self { TermBackend::Crossterm(crossterm_backend) => { if config.general.mouse_support { - crossterm_backend.execute(DisableMouseCapture)?; + crossterm_backend.queue(DisableMouseCapture)?; } - crossterm_backend.execute(cursor::Show)?; - crossterm_backend.execute(LeaveAlternateScreen)?; + crossterm_backend.queue(cursor::Show)?; + crossterm_backend.queue(LeaveAlternateScreen)?; disable_raw_mode()?; } TermBackend::Test { .. } => {} @@ -146,9 +229,9 @@ impl TermBackend { match self { TermBackend::Crossterm(crossterm_backend) => { if config.general.mouse_support { - crossterm_backend.execute(DisableMouseCapture)?; + crossterm_backend.queue(DisableMouseCapture)?; } - crossterm_backend.execute(cursor::Show)?; + crossterm_backend.queue(cursor::Show)?; disable_raw_mode()?; } TermBackend::Test { .. } => {} diff --git a/src/tests/snapshots/gitu__tests__branch__checkout_picker.snap b/src/tests/snapshots/gitu__tests__branch__checkout_picker.snap index 1918f6c19c..62c87e1e2a 100644 --- a/src/tests/snapshots/gitu__tests__branch__checkout_picker.snap +++ b/src/tests/snapshots/gitu__tests__branch__checkout_picker.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 58f7548685b20bd5 +styles_hash: d0729ae36786267b diff --git a/src/tests/snapshots/gitu__tests__branch__delete_picker.snap b/src/tests/snapshots/gitu__tests__branch__delete_picker.snap index 280a39699e..c86d5923bb 100644 --- a/src/tests/snapshots/gitu__tests__branch__delete_picker.snap +++ b/src/tests/snapshots/gitu__tests__branch__delete_picker.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 45fbe6e2f998d7e4 +styles_hash: 6a255f9ee8d30c59 diff --git a/src/tests/snapshots/gitu__tests__branch__rename_picker.snap b/src/tests/snapshots/gitu__tests__branch__rename_picker.snap index 8d1582fec8..14a18c0e0f 100644 --- a/src/tests/snapshots/gitu__tests__branch__rename_picker.snap +++ b/src/tests/snapshots/gitu__tests__branch__rename_picker.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 67c9ab69126a0c9c +styles_hash: 8f7a659399e0489e diff --git a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_prompt.snap b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_prompt.snap index 9e2369e79e..bd64720487 100644 --- a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_prompt.snap +++ b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 23f47fa15ae9f751 +styles_hash: f868f120e27e8b1b diff --git a/src/tests/snapshots/gitu__tests__editor__re_enter_picker_from_menu.snap b/src/tests/snapshots/gitu__tests__editor__re_enter_picker_from_menu.snap index eef5ce06b2..eea969d927 100644 --- a/src/tests/snapshots/gitu__tests__editor__re_enter_picker_from_menu.snap +++ b/src/tests/snapshots/gitu__tests__editor__re_enter_picker_from_menu.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: f7e9b36bbf7e3d91 +styles_hash: 49e995be810c0237 diff --git a/src/tests/snapshots/gitu__tests__merge__merge_picker.snap b/src/tests/snapshots/gitu__tests__merge__merge_picker.snap index 2fb83c7041..aef0a95396 100644 --- a/src/tests/snapshots/gitu__tests__merge__merge_picker.snap +++ b/src/tests/snapshots/gitu__tests__merge__merge_picker.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 6960e24f02662545 +styles_hash: 16f8dd2fc9f8bc2f diff --git a/src/tests/snapshots/gitu__tests__merge__merge_picker_custom_input.snap b/src/tests/snapshots/gitu__tests__merge__merge_picker_custom_input.snap index 59bc7f381f..ac89e1a23f 100644 --- a/src/tests/snapshots/gitu__tests__merge__merge_picker_custom_input.snap +++ b/src/tests/snapshots/gitu__tests__merge__merge_picker_custom_input.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 921dd6ef05db5d3c +styles_hash: 6f95b383fced9e3c diff --git a/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere_prompt.snap b/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere_prompt.snap index 3bd6121efb..d835e436a7 100644 --- a/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere_prompt.snap +++ b/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 6679953df170d9fd +styles_hash: 65f4fc0ca3a35c1e diff --git a/src/ui.rs b/src/ui.rs index 9d8340c668..1055263184 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,13 +1,17 @@ use std::borrow::Cow; +use crate::Res; use crate::app::State; +use crate::error::Error; use crate::screen; +use crate::term::TermBackend; use crate::ui::layout::LayoutItem; use itertools::Itertools; use layout::LayoutTree; use layout::OPTS; -use ratatui::Frame; -use ratatui::prelude::*; +use ratatui::backend::Backend; +use ratatui::layout::Size; +use ratatui::style::Style; use tui_prompts::State as _; use unicode_segmentation::UnicodeSegmentation; use unicode_width::UnicodeWidthStr; @@ -18,6 +22,7 @@ pub mod picker; const CARET: &str = "\u{2588}"; const DASHES: &str = "────────────────────────────────────────────────────────────────"; +const BLANKS: &str = " "; #[derive(Debug, Clone)] pub(crate) enum UiItem<'a> { @@ -26,8 +31,8 @@ pub(crate) enum UiItem<'a> { } pub(crate) type UiTree<'a> = LayoutTree>; -pub(crate) fn ui(frame: &mut Frame, state: &mut State) { - let size = frame.area().as_size(); +pub(crate) fn ui(term: &mut TermBackend, state: &mut State) -> Res<()> { + let size = term.size().unwrap(); let mut layout = UiTree::new(); layout.vertical(None, OPTS, |layout| { @@ -53,17 +58,19 @@ pub(crate) fn ui(frame: &mut Frame, state: &mut State) { }); }); - layout.compute([frame.area().width, frame.area().height]); + layout.compute([size.width, size.height]); - for item in layout.iter() { - let LayoutItem { data, pos, size } = item; - let area = Rect::new(pos[0], pos[1], size[0], size[1]); - frame.render_widget(data, area); - } + let mut items = layout.iter().collect::>(); + items.sort_by_key(|item| [item.pos[1], item.pos[0]]); + + clear_blanks(term, size, items)?; + term.flush().map_err(Error::Term)?; layout.clear(); - state.screens.last_mut().unwrap().size = frame.area().as_size(); + state.screens.last_mut().unwrap().size = size; + + Ok(()) } impl<'a> Widget for &UiItem<'a> { @@ -175,3 +182,76 @@ pub(crate) fn repeat_chars(layout: &mut UiTree, count: usize, chars: &'static st } }); } + +fn clear_blanks( + term: &mut TermBackend, + size: Size, + items: Vec>>, +) -> Result<(), Error> { + let mut at = [0, 0]; + let mut bg = Style::new(); + let mut bg_end = 0; + for item in items { + let LayoutItem { + data, + pos, + size: item_size, + } = item; + + blank_until(term, &mut at, [0, pos[1]], size.width, bg, bg_end)?; + + match data { + UiItem::Span(text, style) => { + blank_until(term, &mut at, pos, size.width, bg, bg_end)?; + term.queue_move_cursor(pos[0], pos[1])?; + term.queue_print(text, style)?; + + at[0] = pos[0].saturating_add(item_size[0]); + } + UiItem::Style(style) => { + bg = *style; + bg_end = pos[1].saturating_add(item_size[1]); + } + } + } + blank_until(term, &mut at, [0, size.height], size.width, bg, bg_end)?; + Ok(()) +} + +fn blank_until( + term: &mut TermBackend, + at: &mut [u16; 2], + to: [u16; 2], + width: u16, + bg: Style, + bg_end: u16, +) -> Res<()> { + let row_bg = |y| if y < bg_end { bg } else { Style::new() }; + + while at[1] < to[1] { + queue_blanks(term, *at, width.saturating_sub(at[0]), &row_bg(at[1]))?; + *at = [0, at[1] + 1]; + } + + queue_blanks(term, *at, to[0].saturating_sub(at[0]), &row_bg(at[1]))?; + at[0] = at[0].max(to[0]); + + Ok(()) +} + +fn queue_blanks(term: &mut TermBackend, at: [u16; 2], width: u16, style: &Style) -> Res<()> { + if width == 0 { + return Ok(()); + } + + term.queue_move_cursor(at[0], at[1])?; + + let mut left = width as usize; + while left > 0 { + let blanks = left.min(BLANKS.len()); + term.queue_print(&BLANKS[..blanks], style)?; + left -= blanks; + } + + Ok(()) +} From 069f99f3794070c85a9535481bf704ca54ba2ae3 Mon Sep 17 00:00:00 2001 From: altsem Date: Sun, 26 Jul 2026 06:25:19 +0000 Subject: [PATCH 02/11] refactor: lay out items and cmd log without ratatui Line/Span --- src/cmd_log.rs | 42 -------- src/items.rs | 188 -------------------------------- src/screen/mod.rs | 8 +- src/ui.rs | 56 ++++------ src/ui/cmd_log.rs | 62 +++++++++++ src/ui/item.rs | 267 ++++++++++++++++++++++++++++++++++++++++++++++ src/ui/menu.rs | 119 +++++++++++++-------- src/ui/picker.rs | 2 +- 8 files changed, 426 insertions(+), 318 deletions(-) create mode 100644 src/ui/cmd_log.rs create mode 100644 src/ui/item.rs diff --git a/src/cmd_log.rs b/src/cmd_log.rs index 48a30eb37e..7dad8f9772 100644 --- a/src/cmd_log.rs +++ b/src/cmd_log.rs @@ -1,7 +1,4 @@ -use crate::config::Config; use itertools::Itertools; -use ratatui::text::Text; -use ratatui::text::{Line, Span}; use std::borrow::Cow; use std::iter; use std::process::Command; @@ -52,15 +49,6 @@ impl CmdLog { pub(crate) fn is_empty(&self) -> bool { self.entries.is_empty() } - - pub(crate) fn format_log(&self, config: &Config) -> Text<'static> { - Text::from( - self.entries - .iter() - .flat_map(|cmd| format_log_entry(config, cmd)) - .collect::>(), - ) - } } pub(crate) fn command_args(cmd: &Command) -> Cow<'static, str> { @@ -70,36 +58,6 @@ pub(crate) fn command_args(cmd: &Command) -> Cow<'static, str> { .into() } -pub(crate) fn format_log_entry<'a>( - config: &Config, - log: &Arc>, -) -> Vec> { - match &*log.read().unwrap() { - CmdLogEntry::Cmd { args, out } => [Line::from(vec![ - Span::styled( - if out.is_some() { "$ " } else { "Running: " }, - &config.style.info_msg, - ), - Span::styled(args.to_string(), &config.style.command), - ])] - .into_iter() - .chain(out.iter().flat_map(|out| { - if out.is_empty() { - vec![] - } else { - Text::raw(out.to_string()).lines - } - })) - .collect::>(), - CmdLogEntry::Error(err) => { - vec![Line::styled(format!("! {err}"), &config.style.error_msg)] - } - CmdLogEntry::Info(msg) => { - vec![Line::styled(format!("> {msg}"), &config.style.info_msg)] - } - } -} - pub(crate) enum CmdLogEntry { Cmd { args: Cow<'static, str>, diff --git a/src/items.rs b/src/items.rs index 15860260b7..68774fb5b2 100644 --- a/src/items.rs +++ b/src/items.rs @@ -1,17 +1,11 @@ use crate::Res; -use crate::config::Config; use crate::error::Error; use crate::git::diff::Diff; -use crate::gitu_diff::Status; use crate::highlight; use crate::item_data::ItemData; use crate::item_data::Ref; -use crate::item_data::SectionHeader; use git2::Oid; use git2::Repository; -use ratatui::style::Style; -use ratatui::text::Line; -use ratatui::text::Span; use regex::Regex; use std::hash::DefaultHasher; use std::hash::Hash; @@ -30,188 +24,6 @@ pub(crate) struct Item { pub(crate) data: ItemData, } -impl Item { - pub fn to_line(&'_ self, config: &Config) -> Line<'_> { - match self.data.clone() { - ItemData::Raw(content) => Line::raw(content), - ItemData::AllUnstaged(count) => Line::from(vec![ - Span::styled("Unstaged changes", &config.style.section_header), - Span::raw(format!(" ({count})")), - ]), - ItemData::AllStaged(count) => Line::from(vec![ - Span::styled("Staged changes", &config.style.section_header), - Span::raw(format!(" ({count})")), - ]), - ItemData::AllUntracked(_) => { - Line::styled("Untracked files", &config.style.section_header) - } - ItemData::Reference { kind, prefix } => { - let (reference, style) = match kind { - Ref::Tag(tag) => (tag, &config.style.tag), - Ref::Head(branch) => (branch, &config.style.branch), - Ref::Remote(remote) => (remote, &config.style.remote), - }; - - Line::from(vec![Span::raw(prefix), Span::styled(reference, style)]) - } - ItemData::Commit { - short_id, - associated_references, - summary, - .. - } => Line::from_iter(itertools::intersperse( - iter::once(Span::styled(short_id, &config.style.hash)) - .chain( - associated_references - .into_iter() - .map(|reference| match reference { - Ref::Tag(tag) => Span::styled(tag, &config.style.tag), - Ref::Head(branch) => Span::styled(branch, &config.style.branch), - Ref::Remote(remote) => Span::styled(remote, &config.style.remote), - }), - ) - .chain([Span::raw(summary)]), - Span::raw(" "), - )), - ItemData::Untracked(path) => Line::styled( - path.to_string_lossy().into_owned(), - &config.style.file_header, - ), - ItemData::Delta { diff, file_i, .. } => { - let file_diff = &diff.file_diffs[file_i]; - - let content = format!( - "{:8} {}", - format!("{:?}", file_diff.header.status).to_lowercase(), - match file_diff.header.status { - Status::Renamed | Status::Copied => format!( - "{} -> {}", - &file_diff.header.old_file.fmt(&diff.text), - &file_diff.header.new_file.fmt(&diff.text) - ), - Status::Deleted => file_diff.header.old_file.fmt(&diff.text).to_string(), - Status::Added => file_diff.header.new_file.fmt(&diff.text).to_string(), - Status::Modified => file_diff.header.new_file.fmt(&diff.text).to_string(), - Status::Unmerged => file_diff.header.new_file.fmt(&diff.text).to_string(), - } - ); - - Line::styled(content, &config.style.file_header) - } - ItemData::Hunk { - diff, - file_i, - hunk_i, - } => { - let file_diff = &diff.file_diffs[file_i]; - let hunk = &file_diff.hunks[hunk_i]; - let content = &diff.text[hunk.header.range.clone()]; - - Line::styled(content.to_string(), &config.style.hunk_header) - } - ItemData::HunkLine { - diff, - file_i, - hunk_i, - line_range, - line_i, - } => { - let hunk_highlights = - highlight::highlight_hunk(self.id, config, &Rc::clone(&diff), file_i, hunk_i); - - let hunk_content = &diff.hunk_content(file_i, hunk_i); - let hunk_line = &hunk_content[line_range.clone()]; - - let line_highlights = hunk_highlights.get_line_highlights(line_i); - - Line::from_iter(line_highlights.iter().map(|(highlight_range, style)| { - Span::styled( - hunk_line[highlight_range.clone()].replace("\t", " "), - *style, - ) - })) - } - ItemData::Stash { message, id, .. } => Line::from(vec![ - Span::styled(format!("stash@{id}"), &config.style.hash), - Span::raw(format!(" {message}")), - ]), - ItemData::Header(header) => { - let content = match header { - SectionHeader::Remote(remote) => format!("Remote {remote}"), - SectionHeader::Tags => "Tags".to_string(), - SectionHeader::Branches => "Branches".to_string(), - SectionHeader::NoBranch => "No branch".to_string(), - SectionHeader::OnBranch(branch) => format!("On branch {branch}"), - SectionHeader::Rebase(head, onto) => format!("Rebasing {head} onto {onto}"), - SectionHeader::Merge(head) => format!("Merging {head}"), - SectionHeader::Revert(head) => format!("Reverting {head}"), - SectionHeader::CherryPick(head) => format!("Cherry-picking {head}"), - SectionHeader::Stashes => "Stashes".to_string(), - SectionHeader::RecentCommits => "Recent commits".to_string(), - SectionHeader::Commit(oid) => format!("commit {oid}"), - SectionHeader::StashRef(stash_ref) => stash_ref, - SectionHeader::StagedChanges(count) => format!("Staged changes ({count})"), - SectionHeader::UnstagedChanges(count) => format!("Unstaged changes ({count})"), - SectionHeader::UntrackedFiles(count) => format!("Untracked files ({count})"), - SectionHeader::Blame(file, commit) => { - format!("Blame {file} @ {commit}") - } - }; - - Line::styled(content, &config.style.section_header) - } - ItemData::BranchStatus(upstream, ahead, behind) => { - let content = if ahead == 0 && behind == 0 { - format!("Your branch is up to date with '{upstream}'.") - } else if ahead > 0 && behind == 0 { - format!("Your branch is ahead of '{upstream}' by {ahead} commit(s).",) - } else if ahead == 0 && behind > 0 { - format!("Your branch is behind '{upstream}' by {behind} commit(s).",) - } else { - format!( - "Your branch and '{upstream}' have diverged,\nand have {ahead} and {behind} different commits each, respectively." - ) - }; - - Line::raw(content) - } - ItemData::Error(err) => Line::raw(err), - ItemData::BlameHeader { - short_hash, - summary, - .. - } => Line::from(vec![ - Span::styled(format!("{:<8}", short_hash), &config.style.hash), - Span::raw(" "), - Span::raw(summary.clone()), - ]), - ItemData::BlameCodeLine { - blame_file, - line_i, - line_num, - content, - .. - } => { - let mut spans = vec![Span::styled( - format!("{:>4} ", line_num), - &config.style.blame.line_num, - )]; - - for (range, style) in blame_file.highlights.get_line_highlights(line_i) { - if !range.is_empty() && range.end <= content.len() { - spans.push(Span::styled( - content[range.clone()].replace('\t', " "), - *style, - )); - } - } - - Line::from(spans).style(Style::from(&config.style.blame.code_line)) - } - } - } -} - pub(crate) fn create_diff_items( diff: &Rc, depth: usize, diff --git a/src/screen/mod.rs b/src/screen/mod.rs index ebda1c1166..3c749abcb0 100644 --- a/src/screen/mod.rs +++ b/src/screen/mod.rs @@ -574,14 +574,10 @@ fn layout_item<'a>(layout: &mut UiTree<'a>, screen: &'a Screen, hide_cursor: boo layout_span(layout, gutter_char); - let item_line = screen.items[line.item_index].to_line(&screen.config); - item_line.spans.into_iter().for_each(|span| { - let style = bg.patch(item_line.style).patch(span.style); - ui::layout_span(layout, (span.content, style)); - }); + let item = &screen.items[line.item_index]; + ui::item::layout_item(layout, item, &screen.config, bg); // Add ellipsis indicator for collapsed sections - let item = &screen.items[line.item_index]; if screen.is_collapsed(item) { layout_span(layout, ("…".into(), bg)); } diff --git a/src/ui.rs b/src/ui.rs index 1055263184..8635218892 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -16,6 +16,8 @@ use tui_prompts::State as _; use unicode_segmentation::UnicodeSegmentation; use unicode_width::UnicodeWidthStr; +mod cmd_log; +pub(crate) mod item; pub(crate) mod layout; mod menu; pub mod picker; @@ -43,7 +45,12 @@ pub(crate) fn ui(term: &mut TermBackend, state: &mut State) -> Res<()> { layout.vertical(None, OPTS, |layout| { menu::layout_menu(layout, state, size.width as usize); - layout_command_log(layout, state, size.width as usize); + cmd_log::layout_cmd_log( + layout, + &state.current_cmd_log, + &state.config, + size.width as usize, + ); layout_prompt(layout, state, size.width as usize); layout_picker(layout, state, size.width as usize); if !state.pending_keys.is_empty() { @@ -73,23 +80,6 @@ pub(crate) fn ui(term: &mut TermBackend, state: &mut State) -> Res<()> { Ok(()) } -impl<'a> Widget for &UiItem<'a> { - fn render(self, area: Rect, buf: &mut Buffer) { - match self { - UiItem::Span(text, style) => buf.set_string(area.x, area.y, text, *style), - UiItem::Style(style) => buf.set_style(area, *style), - } - } -} - -fn layout_command_log<'a>(layout: &mut UiTree<'a>, state: &State, width: usize) { - if !state.current_cmd_log.is_empty() { - let separator_style = Style::from(&state.config.style.separator); - repeat_chars(layout, width, DASHES, separator_style); - layout_text(layout, state.current_cmd_log.format_log(&state.config)); - } -} - fn layout_prompt<'a>(layout: &mut UiTree<'a>, state: &'a State, width: usize) { let Some(ref prompt_data) = state.prompt.data else { return; @@ -119,29 +109,17 @@ fn layout_picker<'a>(layout: &mut UiTree<'a>, state: &'a State, width: usize) { } } -pub(crate) fn layout_text<'a>(layout: &mut UiTree<'a>, text: Text<'a>) { - layout.vertical(None, OPTS, |layout| { - for line in text { - layout_line(layout, line); - } - }); -} - -pub(crate) fn layout_line<'a>(layout: &mut UiTree<'a>, line: Line<'a>) { - let line_style = line.style; +/// Lays out `content` as a single row of its own. +pub(crate) fn layout_line<'a>(layout: &mut UiTree<'a>, content: Cow<'a, str>, style: Style) { layout.horizontal(None, OPTS, |layout| { - for span in line { - // Merge line.style with span.style - let merged_style = line_style.patch(span.style); - layout_span(layout, (span.content, merged_style)); - } + layout_span(layout, (content, style)); }); } pub(crate) fn layout_span<'a>(layout: &mut UiTree<'a>, span: (Cow<'a, str>, Style)) { match span.0 { Cow::Borrowed(s) => { - for word in s.split_word_bounds() { + for word in words(s) { layout.leaf_with_size( UiItem::Span(Cow::Borrowed(word), span.1), [UnicodeWidthStr::width(word) as u16, 1], @@ -149,7 +127,7 @@ pub(crate) fn layout_span<'a>(layout: &mut UiTree<'a>, span: (Cow<'a, str>, Styl } } Cow::Owned(s) => { - for word in s.split_word_bounds() { + for word in words(&s) { layout.leaf_with_size( UiItem::Span(Cow::Owned(word.into()), span.1), [UnicodeWidthStr::width(word) as u16, 1], @@ -159,6 +137,14 @@ pub(crate) fn layout_span<'a>(layout: &mut UiTree<'a>, span: (Cow<'a, str>, Styl } } +/// Splits into the words to wrap on, dropping line breaks. A span occupies a +/// single row, so a line break would otherwise be printed as-is and shift the +/// rest of the frame. +fn words(text: &str) -> impl Iterator { + text.split_word_bounds() + .filter(|word| !word.bytes().all(|byte| byte == b'\n' || byte == b'\r')) +} + pub(crate) fn repeat_chars(layout: &mut UiTree, count: usize, chars: &'static str, style: Style) { let grapheme_count = chars.grapheme_indices(true).count(); let full = count / grapheme_count; diff --git a/src/ui/cmd_log.rs b/src/ui/cmd_log.rs new file mode 100644 index 0000000000..bc8cc48b0a --- /dev/null +++ b/src/ui/cmd_log.rs @@ -0,0 +1,62 @@ +use std::sync::{Arc, RwLock}; + +use ratatui::style::Style; + +use crate::cmd_log::{CmdLog, CmdLogEntry}; +use crate::config::Config; +use crate::ui::layout::OPTS; +use crate::ui::{DASHES, UiTree, layout_line, layout_span, repeat_chars}; + +pub(crate) fn layout_cmd_log<'a>( + layout: &mut UiTree<'a>, + log: &CmdLog, + config: &Config, + width: usize, +) { + if log.is_empty() { + return; + } + + repeat_chars(layout, width, DASHES, Style::from(&config.style.separator)); + + layout.vertical(None, OPTS, |layout| { + for entry in &log.entries { + layout_entry(layout, entry, config); + } + }); +} + +/// The entry is read under a lock, so its spans have to be owned. +fn layout_entry<'a>(layout: &mut UiTree<'a>, entry: &Arc>, config: &Config) { + match &*entry.read().unwrap() { + CmdLogEntry::Cmd { args, out } => { + layout.horizontal(None, OPTS, |layout| { + layout_span( + layout, + ( + if out.is_some() { "$ " } else { "Running: " }.into(), + Style::from(&config.style.info_msg), + ), + ); + layout_span( + layout, + (args.to_string().into(), Style::from(&config.style.command)), + ); + }); + + for line in out.iter().flat_map(|out| out.lines()) { + layout_line(layout, line.to_string().into(), Style::new()); + } + } + CmdLogEntry::Error(err) => layout_line( + layout, + format!("! {err}").into(), + Style::from(&config.style.error_msg), + ), + CmdLogEntry::Info(msg) => layout_line( + layout, + format!("> {msg}").into(), + Style::from(&config.style.info_msg), + ), + } +} diff --git a/src/ui/item.rs b/src/ui/item.rs new file mode 100644 index 0000000000..71951427dc --- /dev/null +++ b/src/ui/item.rs @@ -0,0 +1,267 @@ +use std::borrow::Cow; + +use ratatui::style::Style; + +use crate::config::Config; +use crate::gitu_diff::Status; +use crate::highlight; +use crate::item_data::{ItemData, Ref, SectionHeader}; +use crate::items::Item; +use crate::ui::{UiTree, layout_span}; + +/// Lays out an [`Item`] as spans in the caller's container, which is expected to +/// be a single row. +/// +/// Every span is patched onto `base`, letting the caller supply a background +/// style such as the selection highlight. +pub(crate) fn layout_item<'a>( + layout: &mut UiTree<'a>, + item: &'a Item, + config: &Config, + base: Style, +) { + let style = &config.style; + + match &item.data { + ItemData::Raw(content) => { + layout_span(layout, (content.as_str().into(), base)); + } + ItemData::AllUnstaged(count) => { + layout_span( + layout, + ( + "Unstaged changes".into(), + base.patch(Style::from(&style.section_header)), + ), + ); + layout_span(layout, (format!(" ({count})").into(), base)); + } + ItemData::AllStaged(count) => { + layout_span( + layout, + ( + "Staged changes".into(), + base.patch(Style::from(&style.section_header)), + ), + ); + layout_span(layout, (format!(" ({count})").into(), base)); + } + ItemData::AllUntracked(_) => { + layout_span( + layout, + ( + "Untracked files".into(), + base.patch(Style::from(&style.section_header)), + ), + ); + } + ItemData::Reference { kind, prefix } => { + layout_span(layout, ((*prefix).into(), base)); + layout_reference(layout, kind, config, base); + } + ItemData::Commit { + short_id, + associated_references, + summary, + .. + } => { + layout_span( + layout, + ( + short_id.as_str().into(), + base.patch(Style::from(&style.hash)), + ), + ); + + for reference in associated_references { + layout_span(layout, (" ".into(), base)); + layout_reference(layout, reference, config, base); + } + + layout_span(layout, (" ".into(), base)); + layout_span(layout, (summary.as_str().into(), base)); + } + ItemData::Untracked(path) => { + layout_span( + layout, + ( + path.to_string_lossy(), + base.patch(Style::from(&style.file_header)), + ), + ); + } + ItemData::Delta { diff, file_i, .. } => { + let file_diff = &diff.file_diffs[*file_i]; + + let content = format!( + "{:8} {}", + format!("{:?}", file_diff.header.status).to_lowercase(), + match file_diff.header.status { + Status::Renamed | Status::Copied => format!( + "{} -> {}", + file_diff.header.old_file.fmt(&diff.text), + file_diff.header.new_file.fmt(&diff.text) + ), + Status::Deleted => file_diff.header.old_file.fmt(&diff.text).to_string(), + Status::Added => file_diff.header.new_file.fmt(&diff.text).to_string(), + Status::Modified => file_diff.header.new_file.fmt(&diff.text).to_string(), + Status::Unmerged => file_diff.header.new_file.fmt(&diff.text).to_string(), + } + ); + + layout_span( + layout, + (content.into(), base.patch(Style::from(&style.file_header))), + ); + } + ItemData::Hunk { + diff, + file_i, + hunk_i, + } => { + let hunk = &diff.file_diffs[*file_i].hunks[*hunk_i]; + let content = &diff.text[hunk.header.range.clone()]; + + layout_span( + layout, + (content.into(), base.patch(Style::from(&style.hunk_header))), + ); + } + ItemData::HunkLine { + diff, + file_i, + hunk_i, + line_range, + line_i, + } => { + let hunk_highlights = + highlight::highlight_hunk(item.id, config, diff, *file_i, *hunk_i); + let hunk_line = &diff.hunk_content(*file_i, *hunk_i)[line_range.clone()]; + + for (highlight_range, highlight_style) in hunk_highlights.get_line_highlights(*line_i) { + layout_span( + layout, + ( + hunk_line[highlight_range.clone()] + .replace('\t', " ") + .into(), + base.patch(*highlight_style), + ), + ); + } + } + ItemData::Stash { message, id, .. } => { + layout_span( + layout, + ( + format!("stash@{id}").into(), + base.patch(Style::from(&style.hash)), + ), + ); + layout_span(layout, (format!(" {message}").into(), base)); + } + ItemData::Header(header) => { + let content: Cow = match header { + SectionHeader::Remote(remote) => format!("Remote {remote}").into(), + SectionHeader::Tags => "Tags".into(), + SectionHeader::Branches => "Branches".into(), + SectionHeader::NoBranch => "No branch".into(), + SectionHeader::OnBranch(branch) => format!("On branch {branch}").into(), + SectionHeader::Rebase(head, onto) => format!("Rebasing {head} onto {onto}").into(), + SectionHeader::Merge(head) => format!("Merging {head}").into(), + SectionHeader::Revert(head) => format!("Reverting {head}").into(), + SectionHeader::CherryPick(head) => format!("Cherry-picking {head}").into(), + SectionHeader::Stashes => "Stashes".into(), + SectionHeader::RecentCommits => "Recent commits".into(), + SectionHeader::Commit(oid) => format!("commit {oid}").into(), + SectionHeader::StashRef(stash_ref) => stash_ref.as_str().into(), + SectionHeader::StagedChanges(count) => format!("Staged changes ({count})").into(), + SectionHeader::UnstagedChanges(count) => { + format!("Unstaged changes ({count})").into() + } + SectionHeader::UntrackedFiles(count) => format!("Untracked files ({count})").into(), + SectionHeader::Blame(file, commit) => format!("Blame {file} @ {commit}").into(), + }; + + layout_span( + layout, + (content, base.patch(Style::from(&style.section_header))), + ); + } + ItemData::BranchStatus(upstream, ahead, behind) => { + let content = if *ahead == 0 && *behind == 0 { + format!("Your branch is up to date with '{upstream}'.") + } else if *ahead > 0 && *behind == 0 { + format!("Your branch is ahead of '{upstream}' by {ahead} commit(s).") + } else if *ahead == 0 && *behind > 0 { + format!("Your branch is behind '{upstream}' by {behind} commit(s).") + } else { + format!( + "Your branch and '{upstream}' have diverged,\nand have {ahead} and {behind} different commits each, respectively." + ) + }; + + layout_span(layout, (content.into(), base)); + } + ItemData::Error(err) => { + layout_span(layout, (err.as_str().into(), base)); + } + ItemData::BlameHeader { + short_hash, + summary, + .. + } => { + layout_span( + layout, + ( + format!("{short_hash:<8}").into(), + base.patch(Style::from(&style.hash)), + ), + ); + layout_span(layout, (" ".into(), base)); + layout_span(layout, (summary.as_str().into(), base)); + } + ItemData::BlameCodeLine { + blame_file, + line_i, + line_num, + content, + .. + } => { + let base = base.patch(Style::from(&style.blame.code_line)); + + layout_span( + layout, + ( + format!("{line_num:>4} ").into(), + base.patch(Style::from(&style.blame.line_num)), + ), + ); + + for (range, highlight_style) in blame_file.highlights.get_line_highlights(*line_i) { + if !range.is_empty() && range.end <= content.len() { + layout_span( + layout, + ( + content[range.clone()].replace('\t', " ").into(), + base.patch(*highlight_style), + ), + ); + } + } + } + } +} + +fn layout_reference<'a>(layout: &mut UiTree<'a>, reference: &'a Ref, config: &Config, base: Style) { + let (name, style) = match reference { + Ref::Tag(tag) => (tag, &config.style.tag), + Ref::Head(branch) => (branch, &config.style.branch), + Ref::Remote(remote) => (remote, &config.style.remote), + }; + + layout_span( + layout, + (name.as_str().into(), base.patch(Style::from(style))), + ); +} diff --git a/src/ui/menu.rs b/src/ui/menu.rs index a2cdf3a0a9..53845966c9 100644 --- a/src/ui/menu.rs +++ b/src/ui/menu.rs @@ -1,13 +1,19 @@ -use std::sync::Arc; +use std::borrow::Cow; +use crate::menu::arg::Arg; +use crate::ui::item::layout_item; use crate::ui::layout::OPTS; -use crate::ui::{self, UiTree, repeat_chars}; -use crate::{app::State, ops::Op, ui::layout_line}; +use crate::ui::{self, UiTree, layout_line, layout_span, repeat_chars}; +use crate::{app::State, config::Config, ops::Op}; use itertools::Itertools; -use ratatui::{ - style::Style, - text::{Line, Span}, -}; +use ratatui::style::Style; +use unicode_width::UnicodeWidthStr; + +/// The value column of a keybind table row. +enum MenuValue<'a> { + Text(Cow<'a, str>), + Arg(&'a Arg), +} pub(crate) fn layout_menu<'a>(layout: &mut UiTree<'a>, state: &'a State, width: usize) { let Some(ref pending) = state.pending_menu else { @@ -22,7 +28,7 @@ pub(crate) fn layout_menu<'a>(layout: &mut UiTree<'a>, state: &'a State, width: return; } - let config = Arc::clone(&state.config); + let config = &state.config; let item = state.screens.last().unwrap().get_selected_item(); let style = &config.style; @@ -52,7 +58,6 @@ pub(crate) fn layout_menu<'a>(layout: &mut UiTree<'a>, state: &'a State, width: }) .partition(|(op, _binds)| matches!(op, Op::OpenMenu(_))); - let line = item.to_line(&config); let separator_style = Style::from(&style.separator); layout.vertical(None, OPTS, |layout| { @@ -64,20 +69,21 @@ pub(crate) fn layout_menu<'a>(layout: &mut UiTree<'a>, state: &'a State, width: layout.vertical(None, OPTS, |layout| { layout_line( layout, - Line::styled(format!("{}", pending.menu), &style.menu.heading), + pending.menu.to_string().into(), + Style::from(&style.menu.heading), ); layout_keybinds_table( layout, + config, non_menu_binds .into_iter() .map(|(op, binds)| { ( - Line::styled( - binds.iter().map(|bind| bind.raw.as_str()).join("/"), - &style.menu.key, + binds.iter().map(|bind| bind.raw.as_str()).join("/").into(), + MenuValue::Text( + op.clone().implementation().display(state).into(), ), - Line::raw(op.clone().implementation().display(state)), ) }) .collect(), @@ -88,22 +94,21 @@ pub(crate) fn layout_menu<'a>(layout: &mut UiTree<'a>, state: &'a State, width: // Column 2: Submenus if !menu_binds.is_empty() { layout.vertical(None, OPTS, |layout| { - layout_line(layout, Line::styled("Submenu", &style.menu.heading)); + layout_line(layout, "Submenu".into(), Style::from(&style.menu.heading)); layout_keybinds_table( layout, + config, menu_binds .into_iter() .map(|(op, binds)| { let Op::OpenMenu(menu) = op else { unreachable!(); }; + ( - Line::styled( - binds.iter().map(|bind| bind.raw.as_str()).join("/"), - &style.menu.key, - ), - Line::raw(menu.to_string()), + binds.iter().map(|bind| bind.raw.as_str()).join("/").into(), + MenuValue::Text(menu.to_string().into()), ) }) .collect(), @@ -114,16 +119,21 @@ pub(crate) fn layout_menu<'a>(layout: &mut UiTree<'a>, state: &'a State, width: // Column 3: Target commands and arguments layout.vertical(None, OPTS, |layout| { if !target_binds.is_empty() { - layout_line(layout, line); + layout.horizontal(None, OPTS, |layout| { + layout_item(layout, item, config, Style::new()); + }); layout_keybinds_table( layout, + config, target_binds .into_iter() .map(|bind| { ( - Line::styled(bind.raw.clone(), &style.menu.key), - Line::raw(bind.op.clone().implementation().display(state)), + bind.raw.as_str().into(), + MenuValue::Text( + bind.op.clone().implementation().display(state).into(), + ), ) }) .collect(), @@ -131,10 +141,11 @@ pub(crate) fn layout_menu<'a>(layout: &mut UiTree<'a>, state: &'a State, width: } if !arg_binds.is_empty() { - layout_line(layout, Line::styled("Arguments", &style.menu.heading)); + layout_line(layout, "Arguments".into(), Style::from(&style.menu.heading)); layout_keybinds_table( layout, + config, arg_binds .into_iter() .map(|bind| { @@ -144,22 +155,7 @@ pub(crate) fn layout_menu<'a>(layout: &mut UiTree<'a>, state: &'a State, width: let arg = pending.args.get(name.as_str()).unwrap(); - ( - Line::styled(bind.raw.clone(), &style.menu.key), - Line::from(vec![ - Span::raw(arg.display), - Span::raw(" ("), - Span::styled( - arg.get_cli_token().to_string(), - if arg.is_active() { - Style::from(&style.menu.active_arg) - } else { - Style::from(&style.menu.inactive_arg) - }, - ), - Span::raw(")"), - ]), - ) + (bind.raw.as_str().into(), MenuValue::Arg(arg)) }) .collect(), ); @@ -169,16 +165,47 @@ pub(crate) fn layout_menu<'a>(layout: &mut UiTree<'a>, state: &'a State, width: }); } -fn layout_keybinds_table<'a>(layout: &mut UiTree<'a>, items: Vec<(Line<'a>, Line<'a>)>) { +fn layout_keybinds_table<'a>( + layout: &mut UiTree<'a>, + config: &Config, + rows: Vec<(Cow<'a, str>, MenuValue<'a>)>, +) { const SPACES: &str = " "; - let max_width = items.iter().fold(0, |acc, (x, _)| acc.max(x.width())) + 1; + let key_style = Style::from(&config.style.menu.key); + let max_width = rows + .iter() + .map(|(key, _)| UnicodeWidthStr::width(key.as_ref())) + .max() + .unwrap_or(0) + + 1; layout.vertical(None, OPTS, |layout| { - for (key, value) in items.iter() { + for (key, value) in rows { + let padding = max_width - UnicodeWidthStr::width(key.as_ref()); + layout.horizontal(None, OPTS, |layout| { - layout_line(layout, key.clone()); - repeat_chars(layout, max_width - key.width(), SPACES, Style::new()); - layout_line(layout, value.clone()); + layout_line(layout, key, key_style); + repeat_chars(layout, padding, SPACES, Style::new()); + + layout.horizontal(None, OPTS, |layout| match value { + MenuValue::Text(text) => layout_span(layout, (text, Style::new())), + MenuValue::Arg(arg) => { + layout_span(layout, (arg.display.into(), Style::new())); + layout_span(layout, (" (".into(), Style::new())); + layout_span( + layout, + ( + arg.get_cli_token().into(), + if arg.is_active() { + Style::from(&config.style.menu.active_arg) + } else { + Style::from(&config.style.menu.inactive_arg) + }, + ), + ); + layout_span(layout, (")".into(), Style::new())); + } + }); }); } }); diff --git a/src/ui/picker.rs b/src/ui/picker.rs index 8ec3239dbd..f7618c0a93 100644 --- a/src/ui/picker.rs +++ b/src/ui/picker.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use ratatui::prelude::*; +use ratatui::style::Style; use tui_prompts::State as _; use unicode_segmentation::UnicodeSegmentation; From d9afdfb85d2d2525b0197f1b0b20ec945144435e Mon Sep 17 00:00:00 2001 From: altsem Date: Sun, 26 Jul 2026 10:25:45 +0200 Subject: [PATCH 03/11] ui bench --- Cargo.toml | 4 ++++ benches/ui.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/app.rs | 12 ++++++------ 3 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 benches/ui.rs diff --git a/Cargo.toml b/Cargo.toml index 372224ce68..83d6b25901 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,10 @@ repository = "https://github.com/altsem/gitu" name = "show" harness = false +[[bench]] +name = "ui" +harness = false + [dev-dependencies] pretty_assertions = "1.4.1" temp-dir = "0.1.16" diff --git a/benches/ui.rs b/benches/ui.rs new file mode 100644 index 0000000000..6943c94534 --- /dev/null +++ b/benches/ui.rs @@ -0,0 +1,45 @@ +use std::rc::Rc; +use std::sync::Arc; + +use criterion::{Criterion, criterion_group, criterion_main}; +use git2::Repository; +use gitu::app::App; +use gitu::cli::{Args, Commands}; +use gitu::config; +use gitu::term::TermBackend; +use ratatui::{Terminal, backend::TestBackend, layout::Size}; + +const REFERENCE: &str = "f4de01c0a12794d7b42a77b2138aa64119b90ea5"; + +/// Times a redraw of an already-built screen, leaving repo access, diff +/// parsing and item creation out of the measurement. +fn bench_redraw(c: &mut Criterion, name: &str, size: Size) { + c.bench_function(name, |b| { + let mut term = Terminal::new(TermBackend::Test { + backend: TestBackend::new(size.width, size.height), + events: vec![], + }) + .unwrap(); + + let args = Args { + command: Some(Commands::Show { + reference: REFERENCE.into(), + }), + ..Default::default() + }; + + let config = Arc::new(config::init_config(args.config.clone()).unwrap()); + let repo = Rc::new(Repository::open_from_env().unwrap()); + let mut app = App::create(repo, size, &args, config, false).unwrap(); + + b.iter(|| app.redraw_now(&mut term).unwrap()); + }); +} + +fn ui(c: &mut Criterion) { + // The whole diff at once, so that per-row costs dominate. + bench_redraw(c, "ui/40x1000", Size::new(40, 1000)); +} + +criterion_group!(benches, ui); +criterion_main!(benches); diff --git a/src/app.rs b/src/app.rs index 9b08c7ee6e..5958ff4c5d 100644 --- a/src/app.rs +++ b/src/app.rs @@ -60,8 +60,8 @@ pub(crate) struct State { inhibit_close_menu: bool, } -pub(crate) struct App { - pub state: State, +pub struct App { + pub(crate) state: State, } impl App { @@ -381,11 +381,11 @@ impl App { self.state.inhibit_close_menu = true; } - pub fn screen_mut(&mut self) -> &mut Screen { + pub(crate) fn screen_mut(&mut self) -> &mut Screen { self.state.screens.last_mut().expect("No screen") } - pub fn screen(&self) -> &Screen { + pub(crate) fn screen(&self) -> &Screen { self.state.screens.last().expect("No screen") } @@ -559,11 +559,11 @@ impl App { } } - pub fn selected_rev(&self) -> Option { + pub(crate) fn selected_rev(&self) -> Option { self.screen().get_selected_item().data.rev() } - pub fn prompt(&mut self, term: &mut Term, params: &PromptParams) -> Res { + pub(crate) fn prompt(&mut self, term: &mut Term, params: &PromptParams) -> Res { let prompt_text = if let Some(default) = (params.create_default_value)(self) { format!("{} (default {}):", params.prompt, default).into() } else { From 49ec7d8b88b3b9da8268b2b33f325e28f285e513 Mon Sep 17 00:00:00 2001 From: altsem Date: Sun, 26 Jul 2026 13:02:00 +0200 Subject: [PATCH 04/11] refactor: remove uses of ratatui::Terminal --- benches/show.rs | 7 ++--- benches/ui.rs | 7 ++--- src/app.rs | 25 ++++++++--------- src/main.rs | 11 ++------ src/ops/remote.rs | 8 ++---- src/prompt.rs | 7 +---- src/term.rs | 62 ++++++----------------------------------- src/tests/helpers/ui.rs | 11 ++++---- src/ui.rs | 1 - 9 files changed, 36 insertions(+), 103 deletions(-) diff --git a/benches/show.rs b/benches/show.rs index 47b0e0d7ed..1354d17788 100644 --- a/benches/show.rs +++ b/benches/show.rs @@ -2,15 +2,14 @@ use std::sync::Arc; use criterion::{Criterion, criterion_group, criterion_main}; use gitu::{cli::Commands, config, term::TermBackend}; -use ratatui::{Terminal, backend::TestBackend}; +use ratatui::backend::TestBackend; fn show(c: &mut Criterion) { c.bench_function("show", |b| { - let mut terminal = Terminal::new(TermBackend::Test { + let mut terminal = TermBackend::Test { backend: TestBackend::new(80, 1000), events: vec![], - }) - .unwrap(); + }; let args = gitu::cli::Args { command: Some(Commands::Show { diff --git a/benches/ui.rs b/benches/ui.rs index 6943c94534..65434c3111 100644 --- a/benches/ui.rs +++ b/benches/ui.rs @@ -7,7 +7,7 @@ use gitu::app::App; use gitu::cli::{Args, Commands}; use gitu::config; use gitu::term::TermBackend; -use ratatui::{Terminal, backend::TestBackend, layout::Size}; +use ratatui::{backend::TestBackend, layout::Size}; const REFERENCE: &str = "f4de01c0a12794d7b42a77b2138aa64119b90ea5"; @@ -15,11 +15,10 @@ const REFERENCE: &str = "f4de01c0a12794d7b42a77b2138aa64119b90ea5"; /// parsing and item creation out of the measurement. fn bench_redraw(c: &mut Criterion, name: &str, size: Size) { c.bench_function(name, |b| { - let mut term = Terminal::new(TermBackend::Test { + let mut term = TermBackend::Test { backend: TestBackend::new(size.width, size.height), events: vec![], - }) - .unwrap(); + }; let args = Args { command: Some(Commands::Show { diff --git a/src/app.rs b/src/app.rs index 5958ff4c5d..17179e1e19 100644 --- a/src/app.rs +++ b/src/app.rs @@ -160,8 +160,8 @@ impl App { pub fn run(&mut self, term: &mut Term, max_tick_delay: Duration) -> Res<()> { while !self.state.quit { - let event = if term.backend_mut().poll_event(max_tick_delay)? { - Some(term.backend_mut().read_event()?) + let event = if term.poll_event(max_tick_delay)? { + Some(term.read_event()?) } else { None }; @@ -250,7 +250,7 @@ impl App { pub fn redraw_now(&mut self, term: &mut Term) -> Res<()> { if self.state.screens.last_mut().is_some() { - ui::ui(term.backend_mut(), &mut self.state)?; + ui::ui(term, &mut self.state)?; self.state.needs_redraw = false; }; @@ -429,7 +429,7 @@ impl App { let log_entry = self.state.current_cmd_log.push_cmd(&cmd); - ui::ui(term.backend_mut(), &mut self.state)?; + ui::ui(term, &mut self.state)?; let mut child = cmd.spawn().map_err(Error::SpawnCmd)?; @@ -496,8 +496,7 @@ impl App { // Redirect stderr so we can capture it via `Child::wait_with_output()` cmd.stderr(Stdio::piped()); - term.backend_mut() - .reset_term_stay_on_alt_screeen(&self.state.config) + term.reset_term_stay_on_alt_screeen(&self.state.config) .map_err(Error::Term)?; let mut child = cmd.spawn().map_err(Error::SpawnCmd)?; @@ -515,9 +514,7 @@ impl App { let status = child.wait().map_err(Error::CouldntAwaitCmd)?; - term.backend_mut() - .setup_term(&self.state.config) - .map_err(Error::Term)?; + term.setup_term(&self.state.config).map_err(Error::Term)?; let out_utf8 = String::from_utf8(strip_ansi_escapes::strip(stderr.clone())) .expect("Error turning command output to String") @@ -578,7 +575,7 @@ impl App { let result = self.handle_prompt(term, params); self.unhide_menu(); - self.state.prompt.reset(term)?; + self.state.prompt.reset(); result } @@ -587,7 +584,7 @@ impl App { self.redraw_now(term)?; loop { - let event = term.backend_mut().read_event()?; + let event = term.read_event()?; self.handle_event(term, event)?; if self.state.prompt.state.status().is_done() { @@ -609,7 +606,7 @@ impl App { let result = self.handle_confirm(term); self.unhide_menu(); - self.state.prompt.reset(term)?; + self.state.prompt.reset(); result } @@ -617,7 +614,7 @@ impl App { fn handle_confirm(&mut self, term: &mut Term) -> Res<()> { self.redraw_now(term)?; loop { - let event = term.backend_mut().read_event()?; + let event = term.read_event()?; self.handle_event(term, event)?; match self.state.prompt.state.value() { @@ -676,7 +673,7 @@ impl App { self.redraw_now(term)?; loop { - let event = term.backend_mut().read_event()?; + let event = term.read_event()?; self.handle_event(term, event)?; if let Some(ref picker) = self.state.picker { diff --git a/src/main.rs b/src/main.rs index ceeb1af6c1..f45677df16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,6 @@ use gitu::{ term::{self, Term}, }; use log::LevelFilter; -use ratatui::Terminal; use std::{backtrace::Backtrace, fmt::Display, panic, sync::Arc}; pub fn main() -> Res<()> { @@ -35,18 +34,14 @@ pub fn main() -> Res<()> { })); log::debug!("Initializing terminal backend"); - let mut term = Terminal::new(term::backend()).map_err(Error::Term)?; + let mut term = term::backend(); if !args.print { - term.backend_mut() - .setup_term(&config_ref) - .map_err(Error::Term)?; + term.setup_term(&config_ref).map_err(Error::Term)?; } let result = setup_term_and_run(&mut term, config_ref.clone(), &args); - term.backend_mut() - .reset_term(&config_ref) - .map_err(Error::Term)?; + term.reset_term(&config_ref).map_err(Error::Term)?; result } diff --git a/src/ops/remote.rs b/src/ops/remote.rs index 9f95c53ae7..006c0b2f0e 100644 --- a/src/ops/remote.rs +++ b/src/ops/remote.rs @@ -94,11 +94,7 @@ impl OpTrait for RemoveRemote { } } -fn remove_remote( - app: &mut App, - term: &mut ratatui::Terminal, - remote_name: &str, -) -> Res<()> { +fn remove_remote(app: &mut App, term: &mut crate::term::Term, remote_name: &str) -> Res<()> { let mut cmd = Command::new("git"); cmd.args(["remote", "remove", remote_name]); @@ -108,7 +104,7 @@ fn remove_remote( fn rename_remote( app: &mut App, - term: &mut ratatui::Terminal, + term: &mut crate::term::Term, remote_name: &str, new_remote_name: &str, ) -> Res<()> { diff --git a/src/prompt.rs b/src/prompt.rs index 142f650b1f..b32def6aac 100644 --- a/src/prompt.rs +++ b/src/prompt.rs @@ -1,6 +1,3 @@ -use super::Res; -use crate::error::Error; -use ratatui::{Terminal, backend::Backend}; use std::borrow::Cow; use tui_prompts::{State, TextState}; @@ -26,10 +23,8 @@ impl Prompt { self.state.focus(); } - pub(crate) fn reset(&mut self, terminal: &mut Terminal) -> Res<()> { + pub(crate) fn reset(&mut self) { self.data = None; self.state = TextState::new(); - terminal.hide_cursor().map_err(Error::Term)?; - Ok(()) } } diff --git a/src/term.rs b/src/term.rs index 467d155049..d30c53e540 100644 --- a/src/term.rs +++ b/src/term.rs @@ -7,11 +7,10 @@ use crossterm::{ terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode}, }; use ratatui::{ - Terminal, backend::{Backend, CrosstermBackend, TestBackend}, buffer::Cell, layout::Size, - prelude::{Position, backend::WindowSize}, + prelude::Position, style::{Color, Style}, }; use std::io::{self, Stdout, stdout}; @@ -19,7 +18,7 @@ use std::time::Duration; use unicode_segmentation::UnicodeSegmentation; use unicode_width::UnicodeWidthStr; -pub type Term = Terminal; +pub type Term = TermBackend; pub fn backend() -> TermBackend { TermBackend::Crossterm(CrosstermBackend::new(stdout())) @@ -121,67 +120,22 @@ fn print_test_span(text: &str, style: &Style, backend: &mut TestBackend) -> io:: backend.set_cursor_position(Position::new(cx, y)) } -impl Backend for TermBackend { - fn draw<'a, I>(&mut self, content: I) -> io::Result<()> - where - I: Iterator, - { - match self { - TermBackend::Crossterm(t) => t.draw(content), - TermBackend::Test { backend, .. } => backend.draw(content), - } - } - - fn hide_cursor(&mut self) -> io::Result<()> { - match self { - TermBackend::Crossterm(t) => t.hide_cursor(), - TermBackend::Test { backend, .. } => backend.hide_cursor(), - } - } - - fn show_cursor(&mut self) -> io::Result<()> { - match self { - TermBackend::Crossterm(t) => t.show_cursor(), - TermBackend::Test { backend, .. } => backend.show_cursor(), - } - } - - fn get_cursor_position(&mut self) -> io::Result { - match self { - TermBackend::Crossterm(t) => t.get_cursor_position(), - TermBackend::Test { backend, .. } => backend.get_cursor_position(), - } - } - - fn set_cursor_position>(&mut self, position: P) -> io::Result<()> { - match self { - TermBackend::Crossterm(t) => t.set_cursor_position(position), - TermBackend::Test { backend, .. } => backend.set_cursor_position(position), - } - } - - fn clear(&mut self) -> io::Result<()> { - match self { - TermBackend::Crossterm(t) => t.clear(), - TermBackend::Test { backend, .. } => backend.clear(), - } - } - - fn size(&self) -> io::Result { +impl TermBackend { + pub(crate) fn size(&self) -> io::Result { match self { TermBackend::Crossterm(t) => t.size(), TermBackend::Test { backend, .. } => backend.size(), } } - fn window_size(&mut self) -> io::Result { + pub(crate) fn clear(&mut self) -> io::Result<()> { match self { - TermBackend::Crossterm(t) => t.window_size(), - TermBackend::Test { backend, .. } => backend.window_size(), + TermBackend::Crossterm(t) => t.clear(), + TermBackend::Test { backend, .. } => backend.clear(), } } - fn flush(&mut self) -> io::Result<()> { + pub(crate) fn flush(&mut self) -> io::Result<()> { match self { TermBackend::Crossterm(t) => Backend::flush(t), TermBackend::Test { backend, .. } => backend.flush(), diff --git a/src/tests/helpers/ui.rs b/src/tests/helpers/ui.rs index 7631c62138..7486f3977c 100644 --- a/src/tests/helpers/ui.rs +++ b/src/tests/helpers/ui.rs @@ -9,7 +9,7 @@ use crate::{ }; use crossterm::event::{Event, KeyEvent, KeyModifiers, MouseButton, MouseEventKind}; use git2::Repository; -use ratatui::{Terminal, backend::TestBackend, layout::Size}; +use ratatui::{backend::TestBackend, layout::Size}; use regex::Regex; use std::{path::PathBuf, rc::Rc, sync::Arc, time::Duration}; @@ -44,11 +44,10 @@ macro_rules! setup_clone { impl TestContext { pub fn setup_clone(test_name: &str) -> Self { let size = Size::new(80, 20); - let term = Terminal::new(TermBackend::Test { + let term = TermBackend::Test { backend: TestBackend::new(size.width, size.height), events: vec![], - }) - .unwrap(); + }; let repo_ctx = RepoTestContext::setup_clone(test_name); Self { term, @@ -82,7 +81,7 @@ impl TestContext { } pub fn update(&mut self, app: &mut App, new_events: Vec) { - let TermBackend::Test { events, .. } = self.term.backend_mut() else { + let TermBackend::Test { events, .. } = &mut self.term else { unreachable!(); }; @@ -93,7 +92,7 @@ impl TestContext { } pub fn redact_buffer(&self) -> String { - let TermBackend::Test { backend, .. } = self.term.backend() else { + let TermBackend::Test { backend, .. } = &self.term else { unreachable!(); }; let mut debug_output = format!("{:?}", TestBuffer(backend.buffer())); diff --git a/src/ui.rs b/src/ui.rs index 8635218892..b3cdadcd4b 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -9,7 +9,6 @@ use crate::ui::layout::LayoutItem; use itertools::Itertools; use layout::LayoutTree; use layout::OPTS; -use ratatui::backend::Backend; use ratatui::layout::Size; use ratatui::style::Style; use tui_prompts::State as _; From 53f324c38e8a63ccb908adda03160d6ff26f6d0f Mon Sep 17 00:00:00 2001 From: altsem Date: Sun, 26 Jul 2026 13:07:18 +0200 Subject: [PATCH 05/11] refactor: remove uses of ratatui::layout::Size --- benches/ui.rs | 8 ++++---- src/app.rs | 3 +-- src/screen/blame.rs | 3 +-- src/screen/log.rs | 3 +-- src/screen/mod.rs | 28 ++++++++++++++-------------- src/screen/show.rs | 3 +-- src/screen/show_refs.rs | 3 +-- src/screen/show_stash.rs | 3 +-- src/screen/status.rs | 3 +-- src/term.rs | 10 ++++++---- src/tests/helpers/ui.rs | 8 ++++---- src/ui.rs | 19 +++++++++---------- 12 files changed, 44 insertions(+), 50 deletions(-) diff --git a/benches/ui.rs b/benches/ui.rs index 65434c3111..33dca46712 100644 --- a/benches/ui.rs +++ b/benches/ui.rs @@ -7,16 +7,16 @@ use gitu::app::App; use gitu::cli::{Args, Commands}; use gitu::config; use gitu::term::TermBackend; -use ratatui::{backend::TestBackend, layout::Size}; +use ratatui::backend::TestBackend; const REFERENCE: &str = "f4de01c0a12794d7b42a77b2138aa64119b90ea5"; /// Times a redraw of an already-built screen, leaving repo access, diff /// parsing and item creation out of the measurement. -fn bench_redraw(c: &mut Criterion, name: &str, size: Size) { +fn bench_redraw(c: &mut Criterion, name: &str, size: (u16, u16)) { c.bench_function(name, |b| { let mut term = TermBackend::Test { - backend: TestBackend::new(size.width, size.height), + backend: TestBackend::new(size.0, size.1), events: vec![], }; @@ -37,7 +37,7 @@ fn bench_redraw(c: &mut Criterion, name: &str, size: Size) { fn ui(c: &mut Criterion) { // The whole diff at once, so that per-row costs dominate. - bench_redraw(c, "ui/40x1000", Size::new(40, 1000)); + bench_redraw(c, "ui/40x1000", (40, 1000)); } criterion_group!(benches, ui); diff --git a/src/app.rs b/src/app.rs index 17179e1e19..395d32faca 100644 --- a/src/app.rs +++ b/src/app.rs @@ -19,7 +19,6 @@ use crossterm::event::MouseButton; use crossterm::event::MouseEvent; use crossterm::event::MouseEventKind; use git2::Repository; -use ratatui::layout::Size; use tui_prompts::State as _; use crate::cli; @@ -67,7 +66,7 @@ pub struct App { impl App { pub fn create( repo: Rc, - size: Size, + size: (u16, u16), args: &cli::Args, config: Arc, enable_async_cmds: bool, diff --git a/src/screen/blame.rs b/src/screen/blame.rs index 326ee2fdd2..8e639c6e34 100644 --- a/src/screen/blame.rs +++ b/src/screen/blame.rs @@ -8,14 +8,13 @@ use crate::{ items::{Item, hash}, }; use git2::Repository; -use ratatui::layout::Size; use super::Screen; pub(crate) fn create( config: Arc, repo: Rc, - size: Size, + size: (u16, u16), file_path: String, commit: Option, target_line: Option, diff --git a/src/screen/log.rs b/src/screen/log.rs index eb06b5e2e3..7e97634448 100644 --- a/src/screen/log.rs +++ b/src/screen/log.rs @@ -1,14 +1,13 @@ use super::Screen; use crate::{Res, config::Config, items::log}; use git2::{Oid, Repository}; -use ratatui::layout::Size; use regex::Regex; use std::{rc::Rc, sync::Arc}; pub(crate) fn create( config: Arc, repo: Rc, - size: Size, + size: (u16, u16), limit: usize, rev: Option, msg_regex: Option, diff --git a/src/screen/mod.rs b/src/screen/mod.rs index 3c749abcb0..90ac8b6e7d 100644 --- a/src/screen/mod.rs +++ b/src/screen/mod.rs @@ -3,7 +3,7 @@ use crate::ui::layout::{LayoutTree, OPTS}; use crate::ui::{UiItem, UiTree, layout_span}; use crate::{item_data::ItemData, ui}; use itertools::Itertools; -use ratatui::{layout::Size, style::Style}; +use ratatui::style::Style; use crate::{Res, config::Config, items::hash}; @@ -29,7 +29,7 @@ pub(crate) enum NavMode { } pub(crate) struct Screen { - pub(crate) size: Size, + pub(crate) size: (u16, u16), cursor: usize, scroll: usize, config: Arc, @@ -48,7 +48,7 @@ pub(crate) struct Screen { impl Screen { pub(crate) fn new( config: Arc, - size: Size, + size: (u16, u16), refresh_items: Box Res>>, ) -> Res { let collapsed = config @@ -143,7 +143,7 @@ impl Screen { let last = BOTTOM_CONTEXT_LINES + last_item_line; - let end_line = self.size.height.saturating_sub(1) as usize; + let end_line = self.size.1.saturating_sub(1) as usize; if last > end_line + self.scroll { self.scroll = last - end_line; } @@ -189,12 +189,12 @@ impl Screen { } pub(crate) fn scroll_view_half_page_up(&mut self) { - let half_screen = self.size.height as usize / 2; + let half_screen = self.size.1 as usize / 2; self.scroll_view_up(half_screen); } pub(crate) fn scroll_view_half_page_down(&mut self) { - let half_screen = self.size.height as usize / 2; + let half_screen = self.size.1 as usize / 2; self.scroll_view_down(half_screen); } @@ -231,7 +231,7 @@ impl Screen { } pub(crate) fn resize(&mut self, w: u16, h: u16) -> Res<()> { - self.size = Size::new(w, h); + self.size = (w, h); self.update_indices()?; self.update_cursor(); Ok(()) @@ -308,7 +308,7 @@ impl Screen { highlighted: false, }; layout_item(&mut layout, self, false, view); - layout.compute([self.size.width, self.size.height]); + layout.compute([self.size.0, self.size.1]); layout .iter() @@ -348,7 +348,7 @@ impl Screen { } fn move_cursor_to_screen_center(&mut self) { - let half_screen = self.size.height as usize / 2; + let half_screen = self.size.1 as usize / 2; self.cursor = self.line_index[self.scroll + half_screen]; } @@ -371,7 +371,7 @@ impl Screen { return 0; } - let max_scroll = len.saturating_sub(self.size.height as usize); + let max_scroll = len.saturating_sub(self.size.1 as usize); let max_scroll = max_scroll.saturating_add(BOTTOM_CONTEXT_LINES); max_scroll.min(len.saturating_sub(1)) } @@ -439,7 +439,7 @@ impl Screen { pub(crate) fn select_matching bool>(&mut self, predicate: F) -> bool { if let Some(item_i) = self.find_item(|item| !item.unselectable && predicate(&item.data)) { self.cursor = item_i; - let half_screen = self.size.height as usize / 2; + let half_screen = self.size.1 as usize / 2; let Some(line_of_item) = self.line_of_item(self.cursor) else { return false; }; @@ -460,7 +460,7 @@ impl Screen { pub(crate) fn select_last_matching bool>(&mut self, predicate: F) -> bool { if let Some(item_i) = self.rfind_item(|item| !item.unselectable && predicate(&item.data)) { self.cursor = item_i; - let half_screen = self.size.height as usize / 2; + let half_screen = self.size.1 as usize / 2; let Some(line_of_item) = self.line_of_item(self.cursor) else { return false; }; @@ -505,7 +505,7 @@ impl Screen { .map(|(&line_i, _)| line_i) } - fn item_views(&'_ self, area: Size) -> impl Iterator { + fn item_views(&'_ self, area: (u16, u16)) -> impl Iterator { let first_visible_item = self .line_index .get(self.scroll) @@ -513,7 +513,7 @@ impl Screen { .unwrap_or(self.items.len().saturating_sub(1)); let scan_start_item = first_visible_item.min(self.cursor); - let scan_end_line = (self.scroll + area.height as usize).min(self.line_index.len()); + let scan_end_line = (self.scroll + area.1 as usize).min(self.line_index.len()); let scan_end_item = self .line_index .get(scan_end_line) diff --git a/src/screen/show.rs b/src/screen/show.rs index bf9ef2239b..1415d793fd 100644 --- a/src/screen/show.rs +++ b/src/screen/show.rs @@ -8,14 +8,13 @@ use crate::{ items::{self, Item, hash}, }; use git2::Repository; -use ratatui::layout::Size; use super::Screen; pub(crate) fn create( config: Arc, repo: Rc, - size: Size, + size: (u16, u16), reference: String, target: Option<(String, u32)>, ) -> Res { diff --git a/src/screen/show_refs.rs b/src/screen/show_refs.rs index 3ee0784257..4cd7483d59 100644 --- a/src/screen/show_refs.rs +++ b/src/screen/show_refs.rs @@ -14,9 +14,8 @@ use crate::{ items::{self, Item, hash}, }; use git2::{Reference, Repository}; -use ratatui::layout::Size; -pub(crate) fn create(config: Arc, repo: Rc, size: Size) -> Res { +pub(crate) fn create(config: Arc, repo: Rc, size: (u16, u16)) -> Res { Screen::new( Arc::clone(&config), size, diff --git a/src/screen/show_stash.rs b/src/screen/show_stash.rs index b0a138fa18..bc74f173b8 100644 --- a/src/screen/show_stash.rs +++ b/src/screen/show_stash.rs @@ -8,14 +8,13 @@ use crate::{ items::{self, Item, hash}, }; use git2::Repository; -use ratatui::layout::Size; use super::Screen; pub(crate) fn create( config: Arc, repo: Rc, - size: Size, + size: (u16, u16), stash_ref: String, ) -> Res { Screen::new( diff --git a/src/screen/status.rs b/src/screen/status.rs index 9968105ec0..59f663a15c 100644 --- a/src/screen/status.rs +++ b/src/screen/status.rs @@ -8,7 +8,6 @@ use crate::{ items::{self, Item, hash}, }; use git2::Repository; -use ratatui::prelude::Size; use std::{hash::Hash, path::PathBuf, rc::Rc, sync::Arc}; enum SectionID { @@ -43,7 +42,7 @@ impl Hash for SectionID { } } -pub(crate) fn create(config: Arc, repo: Rc, size: Size) -> Res { +pub(crate) fn create(config: Arc, repo: Rc, size: (u16, u16)) -> Res { Screen::new( Arc::clone(&config), size, diff --git a/src/term.rs b/src/term.rs index d30c53e540..1ee00f0d28 100644 --- a/src/term.rs +++ b/src/term.rs @@ -9,7 +9,6 @@ use crossterm::{ use ratatui::{ backend::{Backend, CrosstermBackend, TestBackend}, buffer::Cell, - layout::Size, prelude::Position, style::{Color, Style}, }; @@ -121,10 +120,13 @@ fn print_test_span(text: &str, style: &Style, backend: &mut TestBackend) -> io:: } impl TermBackend { - pub(crate) fn size(&self) -> io::Result { + pub(crate) fn size(&self) -> io::Result<(u16, u16)> { match self { - TermBackend::Crossterm(t) => t.size(), - TermBackend::Test { backend, .. } => backend.size(), + TermBackend::Crossterm(_) => crossterm::terminal::size(), + TermBackend::Test { backend, .. } => { + let size = backend.size()?; + Ok((size.width, size.height)) + } } } diff --git a/src/tests/helpers/ui.rs b/src/tests/helpers/ui.rs index 7486f3977c..7cbddc2ba1 100644 --- a/src/tests/helpers/ui.rs +++ b/src/tests/helpers/ui.rs @@ -9,7 +9,7 @@ use crate::{ }; use crossterm::event::{Event, KeyEvent, KeyModifiers, MouseButton, MouseEventKind}; use git2::Repository; -use ratatui::{backend::TestBackend, layout::Size}; +use ratatui::backend::TestBackend; use regex::Regex; use std::{path::PathBuf, rc::Rc, sync::Arc, time::Duration}; @@ -32,7 +32,7 @@ pub struct TestContext { pub term: Term, pub dir: PathBuf, pub remote_dir: PathBuf, - pub size: Size, + pub size: (u16, u16), config: Arc, } @@ -43,9 +43,9 @@ macro_rules! setup_clone { impl TestContext { pub fn setup_clone(test_name: &str) -> Self { - let size = Size::new(80, 20); + let size = (80, 20); let term = TermBackend::Test { - backend: TestBackend::new(size.width, size.height), + backend: TestBackend::new(size.0, size.1), events: vec![], }; let repo_ctx = RepoTestContext::setup_clone(test_name); diff --git a/src/ui.rs b/src/ui.rs index b3cdadcd4b..aca4ddd9cc 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -9,7 +9,6 @@ use crate::ui::layout::LayoutItem; use itertools::Itertools; use layout::LayoutTree; use layout::OPTS; -use ratatui::layout::Size; use ratatui::style::Style; use tui_prompts::State as _; use unicode_segmentation::UnicodeSegmentation; @@ -43,15 +42,15 @@ pub(crate) fn ui(term: &mut TermBackend, state: &mut State) -> Res<()> { }); layout.vertical(None, OPTS, |layout| { - menu::layout_menu(layout, state, size.width as usize); + menu::layout_menu(layout, state, size.0 as usize); cmd_log::layout_cmd_log( layout, &state.current_cmd_log, &state.config, - size.width as usize, + size.0 as usize, ); - layout_prompt(layout, state, size.width as usize); - layout_picker(layout, state, size.width as usize); + layout_prompt(layout, state, size.0 as usize); + layout_picker(layout, state, size.0 as usize); if !state.pending_keys.is_empty() { let keys = &state .pending_keys @@ -64,7 +63,7 @@ pub(crate) fn ui(term: &mut TermBackend, state: &mut State) -> Res<()> { }); }); - layout.compute([size.width, size.height]); + layout.compute([size.0, size.1]); let mut items = layout.iter().collect::>(); items.sort_by_key(|item| [item.pos[1], item.pos[0]]); @@ -170,7 +169,7 @@ pub(crate) fn repeat_chars(layout: &mut UiTree, count: usize, chars: &'static st fn clear_blanks( term: &mut TermBackend, - size: Size, + size: (u16, u16), items: Vec>>, ) -> Result<(), Error> { let mut at = [0, 0]; @@ -183,11 +182,11 @@ fn clear_blanks( size: item_size, } = item; - blank_until(term, &mut at, [0, pos[1]], size.width, bg, bg_end)?; + blank_until(term, &mut at, [0, pos[1]], size.0, bg, bg_end)?; match data { UiItem::Span(text, style) => { - blank_until(term, &mut at, pos, size.width, bg, bg_end)?; + blank_until(term, &mut at, pos, size.0, bg, bg_end)?; term.queue_move_cursor(pos[0], pos[1])?; term.queue_print(text, style)?; @@ -199,7 +198,7 @@ fn clear_blanks( } } } - blank_until(term, &mut at, [0, size.height], size.width, bg, bg_end)?; + blank_until(term, &mut at, [0, size.1], size.0, bg, bg_end)?; Ok(()) } From 0af7f8f71cd6bae0bda5d84cf55398e136ec0841 Mon Sep 17 00:00:00 2001 From: altsem Date: Sun, 26 Jul 2026 13:16:52 +0200 Subject: [PATCH 06/11] refactor: remove uses of ratatui::backend::TestBackend --- benches/show.rs | 9 +- benches/ui.rs | 5 +- src/term.rs | 184 +++++++++++++++++++++++---------- src/tests/helpers/ui.rs | 11 +- src/tests/helpers/ui/buffer.rs | 19 ++-- 5 files changed, 148 insertions(+), 80 deletions(-) diff --git a/benches/show.rs b/benches/show.rs index 1354d17788..ef4b119071 100644 --- a/benches/show.rs +++ b/benches/show.rs @@ -1,13 +1,16 @@ use std::sync::Arc; use criterion::{Criterion, criterion_group, criterion_main}; -use gitu::{cli::Commands, config, term::TermBackend}; -use ratatui::backend::TestBackend; +use gitu::{ + cli::Commands, + config, + term::{TermBackend, TestBuffer}, +}; fn show(c: &mut Criterion) { c.bench_function("show", |b| { let mut terminal = TermBackend::Test { - backend: TestBackend::new(80, 1000), + buffer: TestBuffer::new(80, 1000), events: vec![], }; diff --git a/benches/ui.rs b/benches/ui.rs index 33dca46712..45269baeea 100644 --- a/benches/ui.rs +++ b/benches/ui.rs @@ -6,8 +6,7 @@ use git2::Repository; use gitu::app::App; use gitu::cli::{Args, Commands}; use gitu::config; -use gitu::term::TermBackend; -use ratatui::backend::TestBackend; +use gitu::term::{TermBackend, TestBuffer}; const REFERENCE: &str = "f4de01c0a12794d7b42a77b2138aa64119b90ea5"; @@ -16,7 +15,7 @@ const REFERENCE: &str = "f4de01c0a12794d7b42a77b2138aa64119b90ea5"; fn bench_redraw(c: &mut Criterion, name: &str, size: (u16, u16)) { c.bench_function(name, |b| { let mut term = TermBackend::Test { - backend: TestBackend::new(size.0, size.1), + buffer: TestBuffer::new(size.0, size.1), events: vec![], }; diff --git a/src/term.rs b/src/term.rs index 1ee00f0d28..78263a1b95 100644 --- a/src/term.rs +++ b/src/term.rs @@ -7,10 +7,8 @@ use crossterm::{ terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode}, }; use ratatui::{ - backend::{Backend, CrosstermBackend, TestBackend}, - buffer::Cell, - prelude::Position, - style::{Color, Style}, + backend::{Backend, CrosstermBackend}, + style::{Color, Modifier, Style}, }; use std::io::{self, Stdout, stdout}; use std::time::Duration; @@ -27,18 +25,121 @@ pub enum TermBackend { Crossterm(CrosstermBackend), #[allow(dead_code)] Test { - backend: TestBackend, + buffer: TestBuffer, events: Vec, }, } +#[derive(Clone, PartialEq)] +pub struct TestCell { + pub symbol: String, + pub fg: Color, + pub bg: Color, + pub underline_color: Color, + pub modifier: Modifier, +} + +impl Default for TestCell { + fn default() -> Self { + TestCell { + symbol: " ".to_string(), + fg: Color::Reset, + bg: Color::Reset, + underline_color: Color::Reset, + modifier: Modifier::empty(), + } + } +} + +impl TestCell { + fn set(&mut self, symbol: &str, style: &Style) { + self.symbol.clear(); + self.symbol.push_str(symbol); + + if let Some(fg) = style.fg { + self.fg = fg; + } + if let Some(bg) = style.bg { + self.bg = bg; + } + if let Some(underline_color) = style.underline_color { + self.underline_color = underline_color; + } + + self.modifier.insert(style.add_modifier); + self.modifier.remove(style.sub_modifier); + } +} + +pub struct TestBuffer { + pub cells: Vec, + pub width: u16, + pub height: u16, + cursor: (u16, u16), +} + +impl TestBuffer { + pub fn new(width: u16, height: u16) -> Self { + TestBuffer { + cells: vec![TestCell::default(); width as usize * height as usize], + width, + height, + cursor: (0, 0), + } + } + + fn clear(&mut self) { + self.cells.fill(TestCell::default()); + } + + fn cell_mut(&mut self, x: u16, y: u16) -> Option<&mut TestCell> { + if x >= self.width || y >= self.height { + return None; + } + + self.cells + .get_mut(y as usize * self.width as usize + x as usize) + } + + fn print(&mut self, text: &str, style: &Style) { + let (mut x, y) = self.cursor; + + for grapheme in text.graphemes(true) { + let grapheme_width = grapheme.width() as u16; + if grapheme_width == 0 || x >= self.width { + continue; + } + + if let Some(cell) = self.cell_mut(x, y) { + *cell = TestCell::default(); + cell.set(grapheme, style); + } + x += 1; + + for _ in 1..grapheme_width { + if x >= self.width { + break; + } + + if let Some(cell) = self.cell_mut(x, y) { + *cell = TestCell::default(); + } + x += 1; + } + } + + self.cursor = (x, y); + } +} + impl TermBackend { pub(crate) fn queue_move_cursor(&mut self, x: u16, y: u16) -> Res<()> { match self { TermBackend::Crossterm(t) => crossterm::queue!(t, MoveTo(x, y)).map_err(Error::Term), - TermBackend::Test { backend, .. } => backend - .set_cursor_position(Position::new(x, y)) - .map_err(Error::Term), + TermBackend::Test { buffer, .. } => { + buffer.cursor = (x, y); + Ok(()) + } } } @@ -49,23 +150,24 @@ impl TermBackend { Ok(()) } - TermBackend::Test { backend, .. } => { - print_test_span(text, style, backend).map_err(Error::Term) + TermBackend::Test { buffer, .. } => { + buffer.print(text, style); + Ok(()) } } } } -const ATTRS: &[(ratatui::style::Modifier, Attribute)] = &[ - (ratatui::style::Modifier::BOLD, Attribute::Bold), - (ratatui::style::Modifier::DIM, Attribute::Dim), - (ratatui::style::Modifier::ITALIC, Attribute::Italic), - (ratatui::style::Modifier::UNDERLINED, Attribute::Underlined), - (ratatui::style::Modifier::SLOW_BLINK, Attribute::SlowBlink), - (ratatui::style::Modifier::RAPID_BLINK, Attribute::RapidBlink), - (ratatui::style::Modifier::REVERSED, Attribute::Reverse), - (ratatui::style::Modifier::HIDDEN, Attribute::Hidden), - (ratatui::style::Modifier::CROSSED_OUT, Attribute::CrossedOut), +const ATTRS: &[(Modifier, Attribute)] = &[ + (Modifier::BOLD, Attribute::Bold), + (Modifier::DIM, Attribute::Dim), + (Modifier::ITALIC, Attribute::Italic), + (Modifier::UNDERLINED, Attribute::Underlined), + (Modifier::SLOW_BLINK, Attribute::SlowBlink), + (Modifier::RAPID_BLINK, Attribute::RapidBlink), + (Modifier::REVERSED, Attribute::Reverse), + (Modifier::HIDDEN, Attribute::Hidden), + (Modifier::CROSSED_OUT, Attribute::CrossedOut), ]; fn print_crossterm_span( @@ -89,58 +191,28 @@ fn print_crossterm_span( Ok(()) } -fn print_test_span(text: &str, style: &Style, backend: &mut TestBackend) -> io::Result<()> { - let Position { x, y } = backend.get_cursor_position()?; - let width = backend.size()?.width; - - let mut cells = Vec::new(); - let mut cx = x; - for grapheme in text.graphemes(true) { - let grapheme_width = grapheme.width() as u16; - if grapheme_width == 0 || cx >= width { - continue; - } - - let mut cell = Cell::default(); - cell.set_symbol(grapheme).set_style(*style); - cells.push((cx, y, cell)); - cx += 1; - - for _ in 1..grapheme_width { - if cx >= width { - break; - } - cells.push((cx, y, Cell::default())); - cx += 1; - } - } - - backend.draw(cells.iter().map(|(x, y, cell)| (*x, *y, cell)))?; - backend.set_cursor_position(Position::new(cx, y)) -} - impl TermBackend { pub(crate) fn size(&self) -> io::Result<(u16, u16)> { match self { TermBackend::Crossterm(_) => crossterm::terminal::size(), - TermBackend::Test { backend, .. } => { - let size = backend.size()?; - Ok((size.width, size.height)) - } + TermBackend::Test { buffer, .. } => Ok((buffer.width, buffer.height)), } } pub(crate) fn clear(&mut self) -> io::Result<()> { match self { TermBackend::Crossterm(t) => t.clear(), - TermBackend::Test { backend, .. } => backend.clear(), + TermBackend::Test { buffer, .. } => { + buffer.clear(); + Ok(()) + } } } pub(crate) fn flush(&mut self) -> io::Result<()> { match self { TermBackend::Crossterm(t) => Backend::flush(t), - TermBackend::Test { backend, .. } => backend.flush(), + TermBackend::Test { .. } => Ok(()), } } } diff --git a/src/tests/helpers/ui.rs b/src/tests/helpers/ui.rs index 7cbddc2ba1..7c3b5ceb2a 100644 --- a/src/tests/helpers/ui.rs +++ b/src/tests/helpers/ui.rs @@ -4,16 +4,15 @@ use crate::{ config::{self, Config}, error::Error, key_parser::parse_test_keys, - term::{Term, TermBackend}, + term::{Term, TermBackend, TestBuffer}, tests::helpers::RepoTestContext, }; use crossterm::event::{Event, KeyEvent, KeyModifiers, MouseButton, MouseEventKind}; use git2::Repository; -use ratatui::backend::TestBackend; use regex::Regex; use std::{path::PathBuf, rc::Rc, sync::Arc, time::Duration}; -use self::buffer::TestBuffer; +use self::buffer::DebugBuffer; mod buffer; @@ -45,7 +44,7 @@ impl TestContext { pub fn setup_clone(test_name: &str) -> Self { let size = (80, 20); let term = TermBackend::Test { - backend: TestBackend::new(size.0, size.1), + buffer: TestBuffer::new(size.0, size.1), events: vec![], }; let repo_ctx = RepoTestContext::setup_clone(test_name); @@ -92,10 +91,10 @@ impl TestContext { } pub fn redact_buffer(&self) -> String { - let TermBackend::Test { backend, .. } = &self.term else { + let TermBackend::Test { buffer, .. } = &self.term else { unreachable!(); }; - let mut debug_output = format!("{:?}", TestBuffer(backend.buffer())); + let mut debug_output = format!("{:?}", DebugBuffer(buffer)); redact(&mut debug_output, "From file://(.*)\n"); redact(&mut debug_output, "To file://(/.*)\n"); diff --git a/src/tests/helpers/ui/buffer.rs b/src/tests/helpers/ui/buffer.rs index 17543a89b9..56b327479e 100644 --- a/src/tests/helpers/ui/buffer.rs +++ b/src/tests/helpers/ui/buffer.rs @@ -1,32 +1,27 @@ -use ratatui::buffer::Buffer; +use crate::term::TestBuffer; use std::{ fmt::{Formatter, Result}, hash::{DefaultHasher, Hash, Hasher}, }; use unicode_width::UnicodeWidthStr; -pub(crate) struct TestBuffer<'a>(pub &'a Buffer); +pub(crate) struct DebugBuffer<'a>(pub &'a TestBuffer); -impl std::fmt::Debug for TestBuffer<'_> { +impl std::fmt::Debug for DebugBuffer<'_> { // Stolen from ratatui-0.26.1/src/buffer/buffer.rs:394 fn fmt(&self, f: &mut Formatter<'_>) -> Result { let mut last_style = None; let mut styles = vec![]; - for (y, line) in self - .0 - .content - .chunks(self.0.area.width as usize) - .enumerate() - { + for (y, line) in self.0.cells.chunks(self.0.width as usize).enumerate() { let mut overwritten = vec![]; let mut skip: usize = 0; for (x, c) in line.iter().enumerate() { if skip == 0 { - f.write_str(c.symbol())?; + f.write_str(&c.symbol)?; } else { - overwritten.push((x, c.symbol())); + overwritten.push((x, &c.symbol)); } - skip = std::cmp::max(skip, c.symbol().width()).saturating_sub(1); + skip = std::cmp::max(skip, c.symbol.width()).saturating_sub(1); { let style = (c.fg, c.bg, c.underline_color, c.modifier); if last_style != Some(style) { From 9f16ce29d4e9da475fa9ec7a89ac286989dbb252 Mon Sep 17 00:00:00 2001 From: altsem Date: Sun, 26 Jul 2026 13:19:36 +0200 Subject: [PATCH 07/11] refactor: remove more ratatui uses in term.rs --- src/term.rs | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/term.rs b/src/term.rs index 78263a1b95..d9df7561e5 100644 --- a/src/term.rs +++ b/src/term.rs @@ -4,13 +4,13 @@ use crossterm::{ cursor::{self, MoveTo}, event::{DisableMouseCapture, EnableMouseCapture, Event}, style::{Attribute, Colors, Print, SetAttribute, SetColors}, - terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode}, -}; -use ratatui::{ - backend::{Backend, CrosstermBackend}, - style::{Color, Modifier, Style}, + terminal::{ + Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, + enable_raw_mode, + }, }; -use std::io::{self, Stdout, stdout}; +use ratatui::style::{Color, Modifier, Style}; +use std::io::{self, Stdout, Write, stdout}; use std::time::Duration; use unicode_segmentation::UnicodeSegmentation; use unicode_width::UnicodeWidthStr; @@ -18,11 +18,11 @@ use unicode_width::UnicodeWidthStr; pub type Term = TermBackend; pub fn backend() -> TermBackend { - TermBackend::Crossterm(CrosstermBackend::new(stdout())) + TermBackend::Crossterm(stdout()) } pub enum TermBackend { - Crossterm(CrosstermBackend), + Crossterm(Stdout), #[allow(dead_code)] Test { buffer: TestBuffer, @@ -170,11 +170,7 @@ const ATTRS: &[(Modifier, Attribute)] = &[ (Modifier::CROSSED_OUT, Attribute::CrossedOut), ]; -fn print_crossterm_span( - text: &str, - style: &Style, - t: &mut CrosstermBackend, -) -> Result<(), io::Error> { +fn print_crossterm_span(text: &str, style: &Style, t: &mut Stdout) -> Result<(), io::Error> { let fg = style.fg.unwrap_or(Color::Reset); let bg = style.bg.unwrap_or(Color::Reset); @@ -201,7 +197,7 @@ impl TermBackend { pub(crate) fn clear(&mut self) -> io::Result<()> { match self { - TermBackend::Crossterm(t) => t.clear(), + TermBackend::Crossterm(t) => crossterm::queue!(t, Clear(ClearType::All)), TermBackend::Test { buffer, .. } => { buffer.clear(); Ok(()) @@ -211,7 +207,7 @@ impl TermBackend { pub(crate) fn flush(&mut self) -> io::Result<()> { match self { - TermBackend::Crossterm(t) => Backend::flush(t), + TermBackend::Crossterm(t) => t.flush(), TermBackend::Test { .. } => Ok(()), } } From 02fd469eb7992d90e2e71b48806676d5fa207451 Mon Sep 17 00:00:00 2001 From: altsem Date: Sun, 26 Jul 2026 13:40:31 +0200 Subject: [PATCH 08/11] feat: port over config from Ratatui --- Cargo.lock | 5 - Cargo.toml | 2 +- src/config.rs | 6 +- src/highlight.rs | 2 +- src/lib.rs | 1 + src/screen/mod.rs | 2 +- src/style.rs | 321 ++++++++++++++++++ src/term.rs | 8 +- src/tests/helpers/ui/buffer.rs | 4 +- .../snapshots/gitu__tests__binary_file.snap | 2 +- ...ests__blame__blame_enter_on_code_line.snap | 2 +- ...__tests__blame__blame_enter_on_header.snap | 2 +- .../gitu__tests__blame__blame_from_hunk.snap | 2 +- ..._blame__blame_from_hunk_shifted_lines.snap | 2 +- ...ests__blame__blame_navigate_code_line.snap | 2 +- ..._blame__blame_re_blame_from_code_line.snap | 2 +- ...ts__blame__blame_re_blame_from_header.snap | 2 +- .../gitu__tests__branch__branch_menu.snap | 2 +- ...u__tests__branch__checkout_new_branch.snap | 2 +- .../gitu__tests__branch__checkout_picker.snap | 2 +- ...tests__branch__checkout_picker_cancel.snap | 2 +- ...ts__branch__checkout_select_from_list.snap | 2 +- ...ts__branch__checkout_use_custom_input.snap | 2 +- .../gitu__tests__branch__delete_picker.snap | 2 +- ...__tests__branch__delete_picker_cancel.snap | 2 +- ...ests__branch__delete_select_from_list.snap | 2 +- ...tests__branch__delete_unmerged_branch.snap | 2 +- ...ests__branch__delete_use_custom_input.snap | 2 +- ..._tests__branch__rename_current_branch.snap | 2 +- .../gitu__tests__branch__rename_picker.snap | 2 +- ...__tests__branch__rename_picker_cancel.snap | 2 +- ...ests__branch__rename_select_from_list.snap | 2 +- .../gitu__tests__branch__spinoff_branch.snap | 2 +- ..._spinoff_branch_with_unmerged_commits.snap | 2 +- ...ests__branch__spinoff_existing_branch.snap | 2 +- ...gitu__tests__cherry_pick__cherry_pick.snap | 2 +- ...tests__cherry_pick__cherry_pick_abort.snap | 2 +- ...rry_pick__cherry_pick_conflict_status.snap | 2 +- ...ts__cherry_pick__cherry_pick_continue.snap | 2 +- ..._tests__cherry_pick__cherry_pick_menu.snap | 2 +- ...s__cherry_pick__cherry_pick_no_commit.snap | 2 +- ...ests__cherry_pick__cherry_pick_prompt.snap | 2 +- ...herry_pick__cherry_pick_prompt_cancel.snap | 2 +- .../snapshots/gitu__tests__chmod_file.snap | 2 +- ...itu__tests__collapsed_sections_config.snap | 2 +- .../gitu__tests__commit__commit_extend.snap | 2 +- ...__tests__commit__commit_instant_fixup.snap | 2 +- ...fixup_stashes_changes_and_keeps_empty.snap | 2 +- .../gitu__tests__commit__commit_menu.snap | 2 +- .../snapshots/gitu__tests__copied_file.snap | 2 +- .../snapshots/gitu__tests__crlf_diff.snap | 2 +- .../snapshots/gitu__tests__deleted_file.snap | 2 +- ...gitu__tests__discard__branch_selected.snap | 2 +- ...sts__discard__branch_selected_confirm.snap | 2 +- ...iscard__discard_branch_confirm_prompt.snap | 2 +- ...tu__tests__discard__discard_branch_no.snap | 2 +- ...u__tests__discard__discard_branch_yes.snap | 2 +- ...tu__tests__discard__discard_file_move.snap | 2 +- ...rd_staged_file_while_unstaged_changes.snap | 2 +- ...rd_staged_hunk_while_unstaged_changes.snap | 2 +- ...rd_staged_line_while_unstaged_changes.snap | 2 +- ...ests__discard__discard_unstaged_delta.snap | 2 +- ...tests__discard__discard_unstaged_hunk.snap | 2 +- ...tests__discard__discard_unstaged_line.snap | 2 +- ...ests__discard__discard_untracked_file.snap | 2 +- ...iscard__discard_untracked_staged_file.snap | 2 +- ...ts__discard__unmerged_branch_selected.snap | 2 +- ...rged_branch_selected_unmerged_confirm.snap | 2 +- ...__editor__exit_from_picker_exits_menu.snap | 2 +- ...itu__tests__editor__move_next_sibling.snap | 2 +- ...editor__move_next_then_parent_section.snap | 2 +- ...itu__tests__editor__move_prev_sibling.snap | 2 +- ...ts__editor__re_enter_picker_from_menu.snap | 2 +- .../gitu__tests__editor__scroll_down.snap | 2 +- ..._tests__editor__scroll_past_selection.snap | 2 +- .../snapshots/gitu__tests__ext_diff.snap | 2 +- ...u__tests__fetch__fetch_from_elsewhere.snap | 2 +- ...s__fetch__fetch_from_elsewhere_prompt.snap | 2 +- ..._tests__fetch__fetch_from_push_remote.snap | 2 +- ..._fetch__fetch_from_push_remote_prompt.snap | 2 +- ...tu__tests__fetch__fetch_from_upstream.snap | 2 +- ...ts__fetch__fetch_from_upstream_prompt.snap | 2 +- ...enu_existing_push_remote_and_upstream.snap | 2 +- ..._fetch_menu_no_remote_or_upstream_set.snap | 2 +- .../snapshots/gitu__tests__fetch_all.snap | 2 +- .../snapshots/gitu__tests__fresh_init.snap | 2 +- .../gitu__tests__go_down_past_collapsed.snap | 2 +- .../snapshots/gitu__tests__help_menu.snap | 2 +- .../gitu__tests__hide_untracked.snap | 2 +- .../gitu__tests__inside_submodule.snap | 2 +- src/tests/snapshots/gitu__tests__log.snap | 2 +- .../gitu__tests__log__grep_no_match.snap | 2 +- .../gitu__tests__log__grep_prompt.snap | 2 +- .../gitu__tests__log__grep_second.snap | 2 +- .../gitu__tests__log__grep_second_other.snap | 2 +- .../gitu__tests__log__grep_set_example.snap | 2 +- .../gitu__tests__log__limit_2_commits.snap | 2 +- ...tu__tests__log__limit_2_commits_other.snap | 2 +- .../gitu__tests__log__limit_invalid.snap | 2 +- .../gitu__tests__log__limit_prompt.snap | 2 +- .../gitu__tests__log__limit_set_10.snap | 2 +- .../gitu__tests__log__log_empty_branch.snap | 2 +- .../gitu__tests__log__log_other.snap | 2 +- .../gitu__tests__log__log_other_input.snap | 2 +- .../gitu__tests__log__log_other_invalid.snap | 2 +- .../gitu__tests__log__log_other_prompt.snap | 2 +- .../gitu__tests__merge__merge_ff_only.snap | 2 +- .../gitu__tests__merge__merge_menu.snap | 2 +- .../gitu__tests__merge__merge_no_ff.snap | 2 +- .../gitu__tests__merge__merge_picker.snap | 2 +- ...tu__tests__merge__merge_picker_cancel.snap | 2 +- ...sts__merge__merge_picker_custom_input.snap | 2 +- ..._picker_duplicate_names_select_branch.snap | 2 +- ...rge_picker_duplicate_names_select_tag.snap | 2 +- ..._tests__merge__merge_select_from_list.snap | 2 +- ..._tests__merge__merge_use_custom_input.snap | 2 +- .../gitu__tests__merge_conflict.snap | 2 +- .../gitu__tests__mouse_select_hunk_line.snap | 2 +- ...ests__mouse_select_ignore_empty_lines.snap | 2 +- ...sts__mouse_select_ignore_empty_region.snap | 2 +- .../gitu__tests__mouse_select_item.snap | 2 +- ..._tests__mouse_show_ignore_empty_lines.snap | 2 +- ...tests__mouse_show_ignore_empty_region.snap | 2 +- .../gitu__tests__mouse_show_item.snap | 2 +- ...tu__tests__mouse_toggle_selected_item.snap | 2 +- .../gitu__tests__mouse_wheel_scroll_down.snap | 2 +- .../gitu__tests__mouse_wheel_scroll_up.snap | 2 +- .../snapshots/gitu__tests__moved_file.snap | 2 +- .../snapshots/gitu__tests__new_commit.snap | 2 +- .../snapshots/gitu__tests__new_file.snap | 2 +- .../gitu__tests__non_ascii_filename.snap | 2 +- .../snapshots/gitu__tests__non_utf8_diff.snap | 2 +- ...itu__tests__pull__pull_from_elsewhere.snap | 2 +- ...sts__pull__pull_from_elsewhere_prompt.snap | 2 +- ...enu_existing_push_remote_and_upstream.snap | 2 +- ...__pull_menu_no_remote_or_upstream_set.snap | 2 +- .../gitu__tests__pull__pull_push_remote.snap | 2 +- ..._tests__pull__pull_push_remote_prompt.snap | 2 +- ...__tests__pull__pull_setup_push_remote.snap | 2 +- ...itu__tests__pull__pull_setup_upstream.snap | 2 +- ...ull__pull_setup_upstream_same_as_head.snap | 2 +- .../gitu__tests__pull__pull_upstream.snap | 2 +- ...tu__tests__pull__pull_upstream_prompt.snap | 2 +- .../gitu__tests__push__force_push.snap | 2 +- ...push__open_push_menu_after_dash_input.snap | 2 +- .../gitu__tests__push__push_elsewhere.snap | 2 +- ...u__tests__push__push_elsewhere_prompt.snap | 2 +- ...enu_existing_push_remote_and_upstream.snap | 2 +- ...itu__tests__push__push_menu_no_branch.snap | 2 +- ...__push_menu_no_remote_or_upstream_set.snap | 2 +- .../gitu__tests__push__push_push_remote.snap | 2 +- ..._tests__push__push_push_remote_prompt.snap | 2 +- ...__tests__push__push_setup_push_remote.snap | 2 +- ...itu__tests__push__push_setup_upstream.snap | 2 +- ...ush__push_setup_upstream_same_as_head.snap | 2 +- .../gitu__tests__push__push_upstream.snap | 2 +- ...tu__tests__push__push_upstream_prompt.snap | 2 +- .../gitu__tests__quit__confirm_quit.snap | 2 +- ...itu__tests__quit__confirm_quit_prompt.snap | 2 +- .../snapshots/gitu__tests__quit__quit.snap | 2 +- .../gitu__tests__quit__quit_from_menu.snap | 2 +- ...gitu__tests__rebase__rebase_elsewhere.snap | 2 +- ...ests__rebase__rebase_elsewhere_prompt.snap | 2 +- .../gitu__tests__rebase__rebase_menu.snap | 2 +- .../gitu__tests__rebase_conflict.snap | 2 +- ...itu__tests__recent_commits_with_limit.snap | 2 +- .../gitu__tests__remote__add_remote.snap | 2 +- ...tests__remote__add_remote_name_prompt.snap | 2 +- ..._tests__remote__add_remote_url_prompt.snap | 2 +- .../gitu__tests__remote__remote_menu.snap | 2 +- .../gitu__tests__remote__remove_remote.snap | 2 +- .../gitu__tests__remote__rename_remote.snap | 2 +- ...ts__remote__rename_remote_name_prompt.snap | 2 +- ...remote__rename_remote_new_name_prompt.snap | 2 +- .../gitu__tests__reset__reset_hard.snap | 2 +- .../gitu__tests__reset__reset_menu.snap | 2 +- .../gitu__tests__reset__reset_mixed.snap | 2 +- .../gitu__tests__reset__reset_soft.snap | 2 +- ...gitu__tests__reset__reset_soft_prompt.snap | 2 +- ..._tests__reverse__reverse_staged_delta.snap | 2 +- ...__tests__reverse__reverse_staged_hunk.snap | 2 +- ...__tests__reverse__reverse_staged_line.snap | 2 +- ...ests__reverse__reverse_unstaged_delta.snap | 2 +- ...tests__reverse__reverse_unstaged_hunk.snap | 2 +- ...tests__reverse__reverse_unstaged_line.snap | 2 +- .../snapshots/gitu__tests__revert_abort.snap | 2 +- .../snapshots/gitu__tests__revert_commit.snap | 2 +- .../gitu__tests__revert_commit_prompt.snap | 2 +- .../gitu__tests__revert_conflict.snap | 2 +- .../snapshots/gitu__tests__revert_menu.snap | 2 +- src/tests/snapshots/gitu__tests__show.snap | 2 +- ..._show_refs__show_refs_at_local_branch.snap | 2 +- ...show_refs__show_refs_at_remote_branch.snap | 2 +- ...u__tests__show_refs__show_refs_at_tag.snap | 2 +- .../snapshots/gitu__tests__show_stash.snap | 2 +- .../gitu__tests__stage__stage_added_line.snap | 2 +- ...itu__tests__stage__stage_all_unstaged.snap | 2 +- ...tu__tests__stage__stage_all_untracked.snap | 2 +- ...itu__tests__stage__stage_changes_crlf.snap | 2 +- ..._stage__stage_deleted_executable_file.snap | 2 +- ...itu__tests__stage__stage_deleted_file.snap | 2 +- ...stage__stage_file_with_spaces_in_name.snap | 2 +- ...itu__tests__stage__stage_removed_line.snap | 2 +- .../gitu__tests__stage__staged_file.snap | 2 +- ...tests__stage_last_hunk_of_first_delta.snap | 2 +- .../snapshots/gitu__tests__stash__stash.snap | 2 +- .../gitu__tests__stash__stash_apply.snap | 2 +- ...tu__tests__stash__stash_apply_default.snap | 2 +- ...sts__stash__stash_apply_file_as_patch.snap | 2 +- ...sts__stash__stash_apply_hunk_as_patch.snap | 2 +- ...sts__stash__stash_apply_line_as_patch.snap | 2 +- ...itu__tests__stash__stash_apply_prompt.snap | 2 +- ...u__tests__stash__stash_apply_selected.snap | 2 +- .../gitu__tests__stash__stash_drop.snap | 2 +- ...itu__tests__stash__stash_drop_default.snap | 2 +- ...gitu__tests__stash__stash_drop_prompt.snap | 2 +- .../gitu__tests__stash__stash_index.snap | 2 +- ...itu__tests__stash__stash_index_prompt.snap | 2 +- ...tu__tests__stash__stash_keeping_index.snap | 2 +- ...ts__stash__stash_keeping_index_prompt.snap | 2 +- .../gitu__tests__stash__stash_menu.snap | 2 +- .../gitu__tests__stash__stash_pop.snap | 2 +- ...gitu__tests__stash__stash_pop_default.snap | 2 +- .../gitu__tests__stash__stash_pop_prompt.snap | 2 +- .../gitu__tests__stash__stash_prompt.snap | 2 +- ...itu__tests__stash__stash_working_tree.snap | 2 +- ...sts__stash__stash_working_tree_prompt.snap | 2 +- ...orking_tree_when_everything_is_staged.snap | 2 +- ...h_working_tree_when_nothing_is_staged.snap | 2 +- .../gitu__tests__stash_list_with_limit.snap | 2 +- .../gitu__tests__syntax_highlighted.snap | 2 +- .../snapshots/gitu__tests__tab_diff.snap | 2 +- ...nstage_added_file_with_spaces_in_name.snap | 2 +- ...u__tests__unstage__unstage_added_line.snap | 2 +- ...u__tests__unstage__unstage_all_staged.snap | 2 +- ...tage__unstage_deleted_executable_file.snap | 2 +- ..._tests__unstage__unstage_deleted_file.snap | 2 +- ..._tests__unstage__unstage_removed_line.snap | 2 +- .../gitu__tests__unstaged_changes.snap | 2 +- .../gitu__tests__updated_externally.snap | 2 +- src/ui.rs | 4 +- src/ui/cmd_log.rs | 2 +- src/ui/item.rs | 2 +- src/ui/menu.rs | 2 +- src/ui/picker.rs | 2 +- 245 files changed, 567 insertions(+), 258 deletions(-) create mode 100644 src/style.rs diff --git a/Cargo.lock b/Cargo.lock index 7b0a679ae6..46a6630a69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -146,9 +146,6 @@ name = "bitflags" version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" -dependencies = [ - "serde_core", -] [[package]] name = "bumpalo" @@ -340,7 +337,6 @@ dependencies = [ "itoa", "rustversion", "ryu", - "serde", "static_assertions", ] @@ -1415,7 +1411,6 @@ dependencies = [ "itertools 0.13.0", "lru", "paste", - "serde", "strum", "unicode-segmentation", "unicode-truncate", diff --git a/Cargo.toml b/Cargo.toml index 83d6b25901..1e47bfb3bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,7 @@ log = "0.4.28" nom = "8.0.0" notify = "8.0.0" serde = { version = "1.0.225", features = ["derive"] } -ratatui = { version = "0.29.0", features = ["serde"] } +ratatui = "0.29.0" simple-logging = "2.0.2" toml = "0.8.23" tui-prompts = "0.5.2" diff --git a/src/config.rs b/src/config.rs index 5b1ef96e15..a8a496d1a8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,6 @@ use std::{collections::BTreeMap, path::PathBuf}; +use crate::style::{Color, Modifier, Style}; use crate::{Bindings, Res, error::Error, key_parser, menu::Menu, ops::Op}; use crossterm::event::{KeyCode, KeyModifiers}; use etcetera::{BaseStrategy, choose_base_strategy}; @@ -7,7 +8,6 @@ use figment::{ Figment, providers::{Format, Toml}, }; -use ratatui::style::{Color, Modifier, Style}; use serde::Deserialize; const DEFAULT_CONFIG: &str = include_str!("default_config.toml"); @@ -245,7 +245,6 @@ impl From<&StyleConfigEntry> for Style { Style { fg: val.fg, bg: val.bg, - underline_color: None, add_modifier: val.mods.unwrap_or(Modifier::empty()), sub_modifier: Modifier::empty(), } @@ -257,7 +256,6 @@ impl From<&SymbolStyleConfigEntry> for Style { Style { fg: val.fg, bg: val.bg, - underline_color: None, add_modifier: val.mods.unwrap_or(Modifier::empty()), sub_modifier: Modifier::empty(), } @@ -377,11 +375,11 @@ pub(crate) fn init_test_config() -> Res { #[cfg(test)] mod tests { + use crate::style::Color; use figment::{ Figment, providers::{Format, Toml}, }; - use ratatui::style::Color; use super::{DEFAULT_CONFIG, FigmentConfig}; diff --git a/src/highlight.rs b/src/highlight.rs index d7af433ff2..15030912ae 100644 --- a/src/highlight.rs +++ b/src/highlight.rs @@ -3,11 +3,11 @@ use crate::config::DiffHighlightConfig; use crate::config::SyntaxHighlightConfig; use crate::git::diff::Diff; use crate::gitu_diff; +use crate::style::Style; use crate::syntax_parser; use crate::syntax_parser::SyntaxTag; use cached::{SizedCache, proc_macro::cached}; use itertools::Itertools; -use ratatui::style::Style; use std::iter; use std::iter::Peekable; use std::ops::Range; diff --git a/src/lib.rs b/src/lib.rs index 0f8ca83ff4..48b7d23f28 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ mod ops; pub mod picker; mod prompt; mod screen; +pub mod style; mod syntax_parser; pub mod term; #[cfg(test)] diff --git a/src/screen/mod.rs b/src/screen/mod.rs index 90ac8b6e7d..770dda013a 100644 --- a/src/screen/mod.rs +++ b/src/screen/mod.rs @@ -1,9 +1,9 @@ use crate::config::StyleConfig; +use crate::style::Style; use crate::ui::layout::{LayoutTree, OPTS}; use crate::ui::{UiItem, UiTree, layout_span}; use crate::{item_data::ItemData, ui}; use itertools::Itertools; -use ratatui::style::Style; use crate::{Res, config::Config, items::hash}; diff --git a/src/style.rs b/src/style.rs new file mode 100644 index 0000000000..8a93a6dbf1 --- /dev/null +++ b/src/style.rs @@ -0,0 +1,321 @@ +use serde::{Deserialize, Deserializer, de}; +use std::str::FromStr; + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Style { + pub fg: Option, + pub bg: Option, + pub add_modifier: Modifier, + pub sub_modifier: Modifier, +} + +impl Style { + pub const fn new() -> Self { + Style { + fg: None, + bg: None, + add_modifier: Modifier::empty(), + sub_modifier: Modifier::empty(), + } + } + + /// Lays `other` over `self`, with what `other` leaves unset showing through. + pub fn patch(mut self, other: Style) -> Style { + self.fg = other.fg.or(self.fg); + self.bg = other.bg.or(self.bg); + + self.add_modifier.remove(other.sub_modifier); + self.add_modifier.insert(other.add_modifier); + self.sub_modifier.remove(other.add_modifier); + self.sub_modifier.insert(other.sub_modifier); + + self + } +} + +/// The prompt symbols come out of tui-prompts as ratatui spans. +impl From for Style { + fn from(style: ratatui::style::Style) -> Self { + Style { + fg: style.fg.map(Color::from), + bg: style.bg.map(Color::from), + add_modifier: Modifier(style.add_modifier.bits()), + sub_modifier: Modifier(style.sub_modifier.bits()), + } + } +} + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Color { + #[default] + Reset, + Black, + Red, + Green, + Yellow, + Blue, + Magenta, + Cyan, + Gray, + DarkGray, + LightRed, + LightGreen, + LightYellow, + LightBlue, + LightMagenta, + LightCyan, + White, + Rgb(u8, u8, u8), + Indexed(u8), +} + +impl From for crossterm::style::Color { + fn from(color: Color) -> Self { + match color { + Color::Reset => Self::Reset, + Color::Black => Self::Black, + Color::Red => Self::DarkRed, + Color::Green => Self::DarkGreen, + Color::Yellow => Self::DarkYellow, + Color::Blue => Self::DarkBlue, + Color::Magenta => Self::DarkMagenta, + Color::Cyan => Self::DarkCyan, + Color::Gray => Self::Grey, + Color::DarkGray => Self::DarkGrey, + Color::LightRed => Self::Red, + Color::LightGreen => Self::Green, + Color::LightYellow => Self::Yellow, + Color::LightBlue => Self::Blue, + Color::LightMagenta => Self::Magenta, + Color::LightCyan => Self::Cyan, + Color::White => Self::White, + Color::Rgb(r, g, b) => Self::Rgb { r, g, b }, + Color::Indexed(i) => Self::AnsiValue(i), + } + } +} + +impl From for Color { + fn from(color: ratatui::style::Color) -> Self { + use ratatui::style::Color as R; + + match color { + R::Reset => Self::Reset, + R::Black => Self::Black, + R::Red => Self::Red, + R::Green => Self::Green, + R::Yellow => Self::Yellow, + R::Blue => Self::Blue, + R::Magenta => Self::Magenta, + R::Cyan => Self::Cyan, + R::Gray => Self::Gray, + R::DarkGray => Self::DarkGray, + R::LightRed => Self::LightRed, + R::LightGreen => Self::LightGreen, + R::LightYellow => Self::LightYellow, + R::LightBlue => Self::LightBlue, + R::LightMagenta => Self::LightMagenta, + R::LightCyan => Self::LightCyan, + R::White => Self::White, + R::Rgb(r, g, b) => Self::Rgb(r, g, b), + R::Indexed(i) => Self::Indexed(i), + } + } +} + +impl FromStr for Color { + type Err = ParseColorError; + + fn from_str(s: &str) -> Result { + // Colors are written by hand in the config, so accept the spellings + // that are in the wild rather than one canonical form. + let name = s + .to_lowercase() + .replace([' ', '-', '_'], "") + .replace("bright", "light") + .replace("grey", "gray") + .replace("silver", "gray") + .replace("lightblack", "darkgray") + .replace("lightwhite", "white") + .replace("lightgray", "white"); + + Ok(match name.as_str() { + "reset" => Self::Reset, + "black" => Self::Black, + "red" => Self::Red, + "green" => Self::Green, + "yellow" => Self::Yellow, + "blue" => Self::Blue, + "magenta" => Self::Magenta, + "cyan" => Self::Cyan, + "gray" => Self::Gray, + "darkgray" => Self::DarkGray, + "lightred" => Self::LightRed, + "lightgreen" => Self::LightGreen, + "lightyellow" => Self::LightYellow, + "lightblue" => Self::LightBlue, + "lightmagenta" => Self::LightMagenta, + "lightcyan" => Self::LightCyan, + "white" => Self::White, + _ => { + if let Ok(index) = s.parse::() { + Self::Indexed(index) + } else if let Some((r, g, b)) = parse_hex_color(s) { + Self::Rgb(r, g, b) + } else { + return Err(ParseColorError); + } + } + }) + } +} + +fn parse_hex_color(s: &str) -> Option<(u8, u8, u8)> { + let hex = s.strip_prefix('#')?; + if hex.len() != 6 { + return None; + } + + // Indexing would panic where a multi-byte char straddles the split. + let channel = |range: std::ops::Range| u8::from_str_radix(hex.get(range)?, 16).ok(); + Some((channel(0..2)?, channel(2..4)?, channel(4..6)?)) +} + +#[derive(Debug)] +pub struct ParseColorError; + +impl std::fmt::Display for ParseColorError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("invalid color") + } +} + +impl std::error::Error for ParseColorError {} + +impl<'de> Deserialize<'de> for Color { + fn deserialize>(deserializer: D) -> Result { + let s = String::deserialize(deserializer)?; + Color::from_str(&s).map_err(|_| de::Error::custom(format!("unknown color: {s}"))) + } +} + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Modifier(pub u16); + +impl Modifier { + pub const BOLD: Self = Modifier(0b0000_0000_0001); + pub const DIM: Self = Modifier(0b0000_0000_0010); + pub const ITALIC: Self = Modifier(0b0000_0000_0100); + pub const UNDERLINED: Self = Modifier(0b0000_0000_1000); + pub const SLOW_BLINK: Self = Modifier(0b0000_0001_0000); + pub const RAPID_BLINK: Self = Modifier(0b0000_0010_0000); + pub const REVERSED: Self = Modifier(0b0000_0100_0000); + pub const HIDDEN: Self = Modifier(0b0000_1000_0000); + pub const CROSSED_OUT: Self = Modifier(0b0001_0000_0000); + + const NAMED: &'static [(&'static str, Self)] = &[ + ("BOLD", Self::BOLD), + ("DIM", Self::DIM), + ("ITALIC", Self::ITALIC), + ("UNDERLINED", Self::UNDERLINED), + ("SLOW_BLINK", Self::SLOW_BLINK), + ("RAPID_BLINK", Self::RAPID_BLINK), + ("REVERSED", Self::REVERSED), + ("HIDDEN", Self::HIDDEN), + ("CROSSED_OUT", Self::CROSSED_OUT), + ]; + + pub const fn empty() -> Self { + Modifier(0) + } + + pub fn contains(self, other: Self) -> bool { + self.0 & other.0 == other.0 + } + + pub fn insert(&mut self, other: Self) { + self.0 |= other.0; + } + + pub fn remove(&mut self, other: Self) { + self.0 &= !other.0; + } +} + +impl FromStr for Modifier { + type Err = ParseModifierError; + + fn from_str(s: &str) -> Result { + let mut modifier = Modifier::empty(); + + if s.trim().is_empty() { + return Ok(modifier); + } + + for name in s.split('|') { + let name = name.trim(); + let (_, flag) = Modifier::NAMED + .iter() + .find(|(named, _)| named.eq_ignore_ascii_case(name)) + .ok_or(ParseModifierError)?; + + modifier.insert(*flag); + } + + Ok(modifier) + } +} + +#[derive(Debug)] +pub struct ParseModifierError; + +impl std::fmt::Display for ParseModifierError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("invalid modifier") + } +} + +impl std::error::Error for ParseModifierError {} + +impl<'de> Deserialize<'de> for Modifier { + fn deserialize>(deserializer: D) -> Result { + let s = String::deserialize(deserializer)?; + Modifier::from_str(&s).map_err(|_| de::Error::custom(format!("unknown modifier: {s}"))) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_modifiers() { + assert_eq!(Modifier::from_str("").unwrap(), Modifier::empty()); + assert_eq!(Modifier::from_str("BOLD").unwrap(), Modifier::BOLD); + + let mut both = Modifier::BOLD; + both.insert(Modifier::ITALIC); + assert_eq!(Modifier::from_str("BOLD|ITALIC").unwrap(), both); + assert_eq!(Modifier::from_str("BOLD | ITALIC").unwrap(), both); + + assert!(Modifier::from_str("NONSENSE").is_err()); + } + + #[test] + fn parse_colors() { + assert_eq!(Color::from_str("light blue").unwrap(), Color::LightBlue); + assert_eq!(Color::from_str("LightBlue").unwrap(), Color::LightBlue); + assert_eq!(Color::from_str("bright-blue").unwrap(), Color::LightBlue); + assert_eq!(Color::from_str("grey").unwrap(), Color::Gray); + assert_eq!(Color::from_str("reset").unwrap(), Color::Reset); + assert_eq!(Color::from_str("255").unwrap(), Color::Indexed(255)); + assert_eq!( + Color::from_str("#707070").unwrap(), + Color::Rgb(112, 112, 112) + ); + + assert!(Color::from_str("#70707").is_err()); + assert!(Color::from_str("#€abc").is_err()); + assert!(Color::from_str("nonsense").is_err()); + } +} diff --git a/src/term.rs b/src/term.rs index d9df7561e5..a377456937 100644 --- a/src/term.rs +++ b/src/term.rs @@ -1,3 +1,4 @@ +use crate::style::{Color, Modifier, Style}; use crate::{Res, config::Config, error::Error}; use crossterm::{ QueueableCommand, @@ -9,7 +10,6 @@ use crossterm::{ enable_raw_mode, }, }; -use ratatui::style::{Color, Modifier, Style}; use std::io::{self, Stdout, Write, stdout}; use std::time::Duration; use unicode_segmentation::UnicodeSegmentation; @@ -35,7 +35,6 @@ pub struct TestCell { pub symbol: String, pub fg: Color, pub bg: Color, - pub underline_color: Color, pub modifier: Modifier, } @@ -45,7 +44,6 @@ impl Default for TestCell { symbol: " ".to_string(), fg: Color::Reset, bg: Color::Reset, - underline_color: Color::Reset, modifier: Modifier::empty(), } } @@ -62,10 +60,6 @@ impl TestCell { if let Some(bg) = style.bg { self.bg = bg; } - if let Some(underline_color) = style.underline_color { - self.underline_color = underline_color; - } - self.modifier.insert(style.add_modifier); self.modifier.remove(style.sub_modifier); } diff --git a/src/tests/helpers/ui/buffer.rs b/src/tests/helpers/ui/buffer.rs index 56b327479e..e686a5b53f 100644 --- a/src/tests/helpers/ui/buffer.rs +++ b/src/tests/helpers/ui/buffer.rs @@ -23,10 +23,10 @@ impl std::fmt::Debug for DebugBuffer<'_> { } skip = std::cmp::max(skip, c.symbol.width()).saturating_sub(1); { - let style = (c.fg, c.bg, c.underline_color, c.modifier); + let style = (c.fg, c.bg, c.modifier); if last_style != Some(style) { last_style = Some(style); - styles.push((x, y, c.fg, c.bg, c.underline_color, c.modifier)); + styles.push((x, y, c.fg, c.bg, c.modifier)); } } } diff --git a/src/tests/snapshots/gitu__tests__binary_file.snap b/src/tests/snapshots/gitu__tests__binary_file.snap index fe595300a4..445124e698 100644 --- a/src/tests/snapshots/gitu__tests__binary_file.snap +++ b/src/tests/snapshots/gitu__tests__binary_file.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 2ac73f967fc59190 +styles_hash: 667054dbc230d885 diff --git a/src/tests/snapshots/gitu__tests__blame__blame_enter_on_code_line.snap b/src/tests/snapshots/gitu__tests__blame__blame_enter_on_code_line.snap index af95326a4c..52f010db00 100644 --- a/src/tests/snapshots/gitu__tests__blame__blame_enter_on_code_line.snap +++ b/src/tests/snapshots/gitu__tests__blame__blame_enter_on_code_line.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 53ab6c4805700159 +styles_hash: 2b9f3fa8eaaf850 diff --git a/src/tests/snapshots/gitu__tests__blame__blame_enter_on_header.snap b/src/tests/snapshots/gitu__tests__blame__blame_enter_on_header.snap index af95326a4c..52f010db00 100644 --- a/src/tests/snapshots/gitu__tests__blame__blame_enter_on_header.snap +++ b/src/tests/snapshots/gitu__tests__blame__blame_enter_on_header.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 53ab6c4805700159 +styles_hash: 2b9f3fa8eaaf850 diff --git a/src/tests/snapshots/gitu__tests__blame__blame_from_hunk.snap b/src/tests/snapshots/gitu__tests__blame__blame_from_hunk.snap index 56cbcf3438..2798527cb7 100644 --- a/src/tests/snapshots/gitu__tests__blame__blame_from_hunk.snap +++ b/src/tests/snapshots/gitu__tests__blame__blame_from_hunk.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 8f174603e5263fc7 +styles_hash: 3f93a26f637aa45 diff --git a/src/tests/snapshots/gitu__tests__blame__blame_from_hunk_shifted_lines.snap b/src/tests/snapshots/gitu__tests__blame__blame_from_hunk_shifted_lines.snap index c121cff779..df92f40c43 100644 --- a/src/tests/snapshots/gitu__tests__blame__blame_from_hunk_shifted_lines.snap +++ b/src/tests/snapshots/gitu__tests__blame__blame_from_hunk_shifted_lines.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 5775387cf04ec79 +styles_hash: 14e13ada23e1829e diff --git a/src/tests/snapshots/gitu__tests__blame__blame_navigate_code_line.snap b/src/tests/snapshots/gitu__tests__blame__blame_navigate_code_line.snap index 864944bfa1..2b7fc6fea4 100644 --- a/src/tests/snapshots/gitu__tests__blame__blame_navigate_code_line.snap +++ b/src/tests/snapshots/gitu__tests__blame__blame_navigate_code_line.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: ddb1fc6e53dc63a8 +styles_hash: bf87595f7dd29626 diff --git a/src/tests/snapshots/gitu__tests__blame__blame_re_blame_from_code_line.snap b/src/tests/snapshots/gitu__tests__blame__blame_re_blame_from_code_line.snap index 25ddb22c6c..9101bf1b66 100644 --- a/src/tests/snapshots/gitu__tests__blame__blame_re_blame_from_code_line.snap +++ b/src/tests/snapshots/gitu__tests__blame__blame_re_blame_from_code_line.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: f6ac29ed54b120db +styles_hash: 281b71913767ed49 diff --git a/src/tests/snapshots/gitu__tests__blame__blame_re_blame_from_header.snap b/src/tests/snapshots/gitu__tests__blame__blame_re_blame_from_header.snap index 25ddb22c6c..9101bf1b66 100644 --- a/src/tests/snapshots/gitu__tests__blame__blame_re_blame_from_header.snap +++ b/src/tests/snapshots/gitu__tests__blame__blame_re_blame_from_header.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: f6ac29ed54b120db +styles_hash: 281b71913767ed49 diff --git a/src/tests/snapshots/gitu__tests__branch__branch_menu.snap b/src/tests/snapshots/gitu__tests__branch__branch_menu.snap index a9514b9d2f..d4b1410cf3 100644 --- a/src/tests/snapshots/gitu__tests__branch__branch_menu.snap +++ b/src/tests/snapshots/gitu__tests__branch__branch_menu.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() K Delete branch | m Rename branch | q/esc Quit/Close | -styles_hash: cdf143286ee83a68 +styles_hash: f3500db39944be2f diff --git a/src/tests/snapshots/gitu__tests__branch__checkout_new_branch.snap b/src/tests/snapshots/gitu__tests__branch__checkout_new_branch.snap index 4cd551344b..d54d3de533 100644 --- a/src/tests/snapshots/gitu__tests__branch__checkout_new_branch.snap +++ b/src/tests/snapshots/gitu__tests__branch__checkout_new_branch.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git checkout -b new | Switched to a new branch 'new' | -styles_hash: fc716abcbd3de04a +styles_hash: afd3b8aa17fb4c8f diff --git a/src/tests/snapshots/gitu__tests__branch__checkout_picker.snap b/src/tests/snapshots/gitu__tests__branch__checkout_picker.snap index 62c87e1e2a..8ea38e9937 100644 --- a/src/tests/snapshots/gitu__tests__branch__checkout_picker.snap +++ b/src/tests/snapshots/gitu__tests__branch__checkout_picker.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: d0729ae36786267b +styles_hash: b250c9a77d4d5cec diff --git a/src/tests/snapshots/gitu__tests__branch__checkout_picker_cancel.snap b/src/tests/snapshots/gitu__tests__branch__checkout_picker_cancel.snap index fe93e837d7..70854b33da 100644 --- a/src/tests/snapshots/gitu__tests__branch__checkout_picker_cancel.snap +++ b/src/tests/snapshots/gitu__tests__branch__checkout_picker_cancel.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 5ea219649635416a +styles_hash: 7b605cf80abe284 diff --git a/src/tests/snapshots/gitu__tests__branch__checkout_select_from_list.snap b/src/tests/snapshots/gitu__tests__branch__checkout_select_from_list.snap index 44d0c8a5a5..9273691df9 100644 --- a/src/tests/snapshots/gitu__tests__branch__checkout_select_from_list.snap +++ b/src/tests/snapshots/gitu__tests__branch__checkout_select_from_list.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git checkout feature-a | Switched to branch 'feature-a' | -styles_hash: ed07bb3ef72d6e56 +styles_hash: 2f476764ee015367 diff --git a/src/tests/snapshots/gitu__tests__branch__checkout_use_custom_input.snap b/src/tests/snapshots/gitu__tests__branch__checkout_use_custom_input.snap index d502f11baf..74beacd7e8 100644 --- a/src/tests/snapshots/gitu__tests__branch__checkout_use_custom_input.snap +++ b/src/tests/snapshots/gitu__tests__branch__checkout_use_custom_input.snap @@ -22,4 +22,4 @@ Or undo this operation with: git switch - | Turn off this advice by setting config variable advice.detachedHead to false | HEAD is now at b66a0bf add initial-file | -styles_hash: cfd01b18ca92dee4 +styles_hash: d9a7a96bb61e275e diff --git a/src/tests/snapshots/gitu__tests__branch__delete_picker.snap b/src/tests/snapshots/gitu__tests__branch__delete_picker.snap index c86d5923bb..6b665fe9bf 100644 --- a/src/tests/snapshots/gitu__tests__branch__delete_picker.snap +++ b/src/tests/snapshots/gitu__tests__branch__delete_picker.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 6a255f9ee8d30c59 +styles_hash: 950ad1ca1b25dd92 diff --git a/src/tests/snapshots/gitu__tests__branch__delete_picker_cancel.snap b/src/tests/snapshots/gitu__tests__branch__delete_picker_cancel.snap index fe93e837d7..70854b33da 100644 --- a/src/tests/snapshots/gitu__tests__branch__delete_picker_cancel.snap +++ b/src/tests/snapshots/gitu__tests__branch__delete_picker_cancel.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 5ea219649635416a +styles_hash: 7b605cf80abe284 diff --git a/src/tests/snapshots/gitu__tests__branch__delete_select_from_list.snap b/src/tests/snapshots/gitu__tests__branch__delete_select_from_list.snap index 8711580f00..e660e59fd7 100644 --- a/src/tests/snapshots/gitu__tests__branch__delete_select_from_list.snap +++ b/src/tests/snapshots/gitu__tests__branch__delete_select_from_list.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Branch is not fully merged. Really delete? (y or n) › █ | -styles_hash: 34185cd7d71d1f27 +styles_hash: cac1287c177321c0 diff --git a/src/tests/snapshots/gitu__tests__branch__delete_unmerged_branch.snap b/src/tests/snapshots/gitu__tests__branch__delete_unmerged_branch.snap index eab5a80e98..1d46549ae8 100644 --- a/src/tests/snapshots/gitu__tests__branch__delete_unmerged_branch.snap +++ b/src/tests/snapshots/gitu__tests__branch__delete_unmerged_branch.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git branch -d -f bugfix-123 | Deleted branch bugfix-123 (was 33a8c4d). | -styles_hash: 86ceb55a114a2ae +styles_hash: 52f5b75cab04a311 diff --git a/src/tests/snapshots/gitu__tests__branch__delete_use_custom_input.snap b/src/tests/snapshots/gitu__tests__branch__delete_use_custom_input.snap index 8711580f00..e660e59fd7 100644 --- a/src/tests/snapshots/gitu__tests__branch__delete_use_custom_input.snap +++ b/src/tests/snapshots/gitu__tests__branch__delete_use_custom_input.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Branch is not fully merged. Really delete? (y or n) › █ | -styles_hash: 34185cd7d71d1f27 +styles_hash: cac1287c177321c0 diff --git a/src/tests/snapshots/gitu__tests__branch__rename_current_branch.snap b/src/tests/snapshots/gitu__tests__branch__rename_current_branch.snap index 432a2b27fa..fa06c447ec 100644 --- a/src/tests/snapshots/gitu__tests__branch__rename_current_branch.snap +++ b/src/tests/snapshots/gitu__tests__branch__rename_current_branch.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git branch -m main main-rename | -styles_hash: ea8b06a9b8042d62 +styles_hash: 89a6b9cc378b1c3b diff --git a/src/tests/snapshots/gitu__tests__branch__rename_picker.snap b/src/tests/snapshots/gitu__tests__branch__rename_picker.snap index 14a18c0e0f..79cbcacdf6 100644 --- a/src/tests/snapshots/gitu__tests__branch__rename_picker.snap +++ b/src/tests/snapshots/gitu__tests__branch__rename_picker.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 8f7a659399e0489e +styles_hash: c6f2b0c353de4247 diff --git a/src/tests/snapshots/gitu__tests__branch__rename_picker_cancel.snap b/src/tests/snapshots/gitu__tests__branch__rename_picker_cancel.snap index fe93e837d7..70854b33da 100644 --- a/src/tests/snapshots/gitu__tests__branch__rename_picker_cancel.snap +++ b/src/tests/snapshots/gitu__tests__branch__rename_picker_cancel.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 5ea219649635416a +styles_hash: 7b605cf80abe284 diff --git a/src/tests/snapshots/gitu__tests__branch__rename_select_from_list.snap b/src/tests/snapshots/gitu__tests__branch__rename_select_from_list.snap index 4ee60283dd..7f7ffe8ffd 100644 --- a/src/tests/snapshots/gitu__tests__branch__rename_select_from_list.snap +++ b/src/tests/snapshots/gitu__tests__branch__rename_select_from_list.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git branch -m feature-a feature-rename | -styles_hash: 2b5fb9a917713dd6 +styles_hash: 5c61e2b785462988 diff --git a/src/tests/snapshots/gitu__tests__branch__spinoff_branch.snap b/src/tests/snapshots/gitu__tests__branch__spinoff_branch.snap index 674d904349..0679dd2cd9 100644 --- a/src/tests/snapshots/gitu__tests__branch__spinoff_branch.snap +++ b/src/tests/snapshots/gitu__tests__branch__spinoff_branch.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() $ git checkout -b new | Switched to a new branch 'new' | > Branch main not changed | -styles_hash: 510f0d108f9759f2 +styles_hash: 24d0651b7748f079 diff --git a/src/tests/snapshots/gitu__tests__branch__spinoff_branch_with_unmerged_commits.snap b/src/tests/snapshots/gitu__tests__branch__spinoff_branch_with_unmerged_commits.snap index dd6972459c..f4acfc8c29 100644 --- a/src/tests/snapshots/gitu__tests__branch__spinoff_branch_with_unmerged_commits.snap +++ b/src/tests/snapshots/gitu__tests__branch__spinoff_branch_with_unmerged_commits.snap @@ -22,4 +22,4 @@ Switched to a new branch 'new' $ git update-ref -m "reset: moving to b66a0bf82020d6a386e94d0fceedec1f817d20c7" | refs/heads/main b66a0bf82020d6a386e94d0fceedec1f817d20c7 | > Branch main was reset to b66a0bf82020d6a386e94d0fceedec1f817d20c7 | -styles_hash: f1c23e60f9d29904 +styles_hash: 14991fd5fd26b58d diff --git a/src/tests/snapshots/gitu__tests__branch__spinoff_existing_branch.snap b/src/tests/snapshots/gitu__tests__branch__spinoff_existing_branch.snap index dbaca57824..32ceb39c3b 100644 --- a/src/tests/snapshots/gitu__tests__branch__spinoff_existing_branch.snap +++ b/src/tests/snapshots/gitu__tests__branch__spinoff_existing_branch.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ! Cannot spin-off feature-a. It already exists | -styles_hash: 67e9d103b840ee58 +styles_hash: a93310bcec6f8973 diff --git a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick.snap b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick.snap index 07f4031eea..1510c598a3 100644 --- a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick.snap +++ b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git cherry-pick other-branch | -styles_hash: 1386c91c12bf9893 +styles_hash: f3a37ee58f76a6c1 diff --git a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_abort.snap b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_abort.snap index 902af3bc4d..b4c42b4c48 100644 --- a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_abort.snap +++ b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_abort.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git cherry-pick --abort | -styles_hash: 5869d9403f787304 +styles_hash: b757c2512bb1402b diff --git a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_conflict_status.snap b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_conflict_status.snap index c987da42a9..32a258c2c9 100644 --- a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_conflict_status.snap +++ b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_conflict_status.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 9b5add9091fc728d +styles_hash: 48a7724d7616702c diff --git a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_continue.snap b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_continue.snap index 14bb901fb2..dada7d6a7c 100644 --- a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_continue.snap +++ b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_continue.snap @@ -22,4 +22,4 @@ hint: Fix them up in the work tree, and then use 'git add/rm ' hint: as appropriate to mark resolution and make a commit. | fatal: Exiting because of an unresolved conflict. | ! 'git cherry-pick--continue' exited with code: 128 | -styles_hash: fac6f201096c5cdc +styles_hash: d1efaefa69a22e79 diff --git a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_menu.snap b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_menu.snap index eb90f97eb9..9f22d5a3fa 100644 --- a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_menu.snap +++ b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_menu.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() c Continue -n Don't commit (--no-commit) | A Cherry-pick commit(s) -s Add Signed-off-by lines (--signoff) | q/esc Quit/Close | -styles_hash: a7abbd2adaf32d30 +styles_hash: 5c7ec187d6f8e88d diff --git a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_no_commit.snap b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_no_commit.snap index d24ac63e45..ac79a899ad 100644 --- a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_no_commit.snap +++ b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_no_commit.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() $ git cherry-pick --no-commit Aother-branch | fatal: bad revision 'Aother-branch' | ! 'git cherry-pick--no-commitAother-branch' exited with code: 128 | -styles_hash: 909239aa67e66107 +styles_hash: ae8ffd321649ca3f diff --git a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_prompt.snap b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_prompt.snap index bd64720487..d950abd60c 100644 --- a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_prompt.snap +++ b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: f868f120e27e8b1b +styles_hash: f16f0086760d9b1 diff --git a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_prompt_cancel.snap b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_prompt_cancel.snap index 50a926ce76..47991c0644 100644 --- a/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_prompt_cancel.snap +++ b/src/tests/snapshots/gitu__tests__cherry_pick__cherry_pick_prompt_cancel.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 4c49c12dcc50cb4b +styles_hash: 2a60169a6477b57a diff --git a/src/tests/snapshots/gitu__tests__chmod_file.snap b/src/tests/snapshots/gitu__tests__chmod_file.snap index 0a8cc8b452..834760bb21 100644 --- a/src/tests/snapshots/gitu__tests__chmod_file.snap +++ b/src/tests/snapshots/gitu__tests__chmod_file.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 1e469a2968dd9d14 +styles_hash: 48cb59b6ba00374c diff --git a/src/tests/snapshots/gitu__tests__collapsed_sections_config.snap b/src/tests/snapshots/gitu__tests__collapsed_sections_config.snap index 15b40a2097..59bf0d6e3a 100644 --- a/src/tests/snapshots/gitu__tests__collapsed_sections_config.snap +++ b/src/tests/snapshots/gitu__tests__collapsed_sections_config.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 887fd7e89f337304 +styles_hash: c1b5d9b336d37d55 diff --git a/src/tests/snapshots/gitu__tests__commit__commit_extend.snap b/src/tests/snapshots/gitu__tests__commit__commit_extend.snap index f89da3d87e..250d13869f 100644 --- a/src/tests/snapshots/gitu__tests__commit__commit_extend.snap +++ b/src/tests/snapshots/gitu__tests__commit__commit_extend.snap @@ -22,4 +22,4 @@ each, respectively. | ────────────────────────────────────────────────────────────────────────────────| $ git commit --amend --no-edit | -styles_hash: 289029b9617670c2 +styles_hash: 5ae7f274843081cb diff --git a/src/tests/snapshots/gitu__tests__commit__commit_instant_fixup.snap b/src/tests/snapshots/gitu__tests__commit__commit_instant_fixup.snap index a3f92adca4..c4c48a5058 100644 --- a/src/tests/snapshots/gitu__tests__commit__commit_instant_fixup.snap +++ b/src/tests/snapshots/gitu__tests__commit__commit_instant_fixup.snap @@ -22,4 +22,4 @@ $ git commit --fixup efc77f3bea683ce4ea27f2e9d7d1bdf04c91a57f 1 file changed, 1 insertion(+), 1 deletion(-) | $ git rebase -i -q --autostash --keep-empty --autosquash | efc77f3bea683ce4ea27f2e9d7d1bdf04c91a57f^ | -styles_hash: 6fb28ebf48baeb5e +styles_hash: 34a63ec32b3bafb diff --git a/src/tests/snapshots/gitu__tests__commit__commit_instant_fixup_stashes_changes_and_keeps_empty.snap b/src/tests/snapshots/gitu__tests__commit__commit_instant_fixup_stashes_changes_and_keeps_empty.snap index 9b411fc69e..05705d7f3e 100644 --- a/src/tests/snapshots/gitu__tests__commit__commit_instant_fixup_stashes_changes_and_keeps_empty.snap +++ b/src/tests/snapshots/gitu__tests__commit__commit_instant_fixup_stashes_changes_and_keeps_empty.snap @@ -22,4 +22,4 @@ $ git rebase -i -q --autostash --keep-empty --autosquash efc77f3bea683ce4ea27f2e9d7d1bdf04c91a57f^ | Applied autostash. | Created autostash: d682ced | -styles_hash: ccd126e002cf43b4 +styles_hash: 33fe1f4f566a5d2a diff --git a/src/tests/snapshots/gitu__tests__commit__commit_menu.snap b/src/tests/snapshots/gitu__tests__commit__commit_menu.snap index c0663a3c9e..f3e946fa00 100644 --- a/src/tests/snapshots/gitu__tests__commit__commit_menu.snap +++ b/src/tests/snapshots/gitu__tests__commit__commit_menu.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() q/esc Quit/Close -R Claim authorship and reset author date (--reset-author) | -s Add Signed-off-by line (--signoff) | -v Show diff of changes to be committed (--verbose) | -styles_hash: 76a5f2a964e77056 +styles_hash: 178efd168e126b3e diff --git a/src/tests/snapshots/gitu__tests__copied_file.snap b/src/tests/snapshots/gitu__tests__copied_file.snap index 5d775ea390..4d18817e12 100644 --- a/src/tests/snapshots/gitu__tests__copied_file.snap +++ b/src/tests/snapshots/gitu__tests__copied_file.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 2bb10d15c578771b +styles_hash: 7f74f4c358d0d1d1 diff --git a/src/tests/snapshots/gitu__tests__crlf_diff.snap b/src/tests/snapshots/gitu__tests__crlf_diff.snap index c5207c326b..f926c4ef58 100644 --- a/src/tests/snapshots/gitu__tests__crlf_diff.snap +++ b/src/tests/snapshots/gitu__tests__crlf_diff.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: b0d01159a2674933 +styles_hash: 11bdd1533d7fbfb7 diff --git a/src/tests/snapshots/gitu__tests__deleted_file.snap b/src/tests/snapshots/gitu__tests__deleted_file.snap index 85f25ae16a..f2b5c3840c 100644 --- a/src/tests/snapshots/gitu__tests__deleted_file.snap +++ b/src/tests/snapshots/gitu__tests__deleted_file.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: badf8c339aba8de6 +styles_hash: e279097c411f8396 diff --git a/src/tests/snapshots/gitu__tests__discard__branch_selected.snap b/src/tests/snapshots/gitu__tests__discard__branch_selected.snap index 0d3a68fe6c..2dab1cfb6d 100644 --- a/src/tests/snapshots/gitu__tests__discard__branch_selected.snap +++ b/src/tests/snapshots/gitu__tests__discard__branch_selected.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git branch -d merged | Deleted branch merged (was b66a0bf). | -styles_hash: dd0c306c9b4c03e8 +styles_hash: 99db55147303043e diff --git a/src/tests/snapshots/gitu__tests__discard__branch_selected_confirm.snap b/src/tests/snapshots/gitu__tests__discard__branch_selected_confirm.snap index 41f7d0b6ac..a435e351ed 100644 --- a/src/tests/snapshots/gitu__tests__discard__branch_selected_confirm.snap +++ b/src/tests/snapshots/gitu__tests__discard__branch_selected_confirm.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Really discard? (y or n) › █ | -styles_hash: 71ca860e8eb65c2 +styles_hash: 7ee167ab1e7e41ed diff --git a/src/tests/snapshots/gitu__tests__discard__discard_branch_confirm_prompt.snap b/src/tests/snapshots/gitu__tests__discard__discard_branch_confirm_prompt.snap index 11a8f201a0..bfdc770e11 100644 --- a/src/tests/snapshots/gitu__tests__discard__discard_branch_confirm_prompt.snap +++ b/src/tests/snapshots/gitu__tests__discard__discard_branch_confirm_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Really discard? (y or n) › █ | -styles_hash: 617872565b197db8 +styles_hash: c5aa53d308a4869e diff --git a/src/tests/snapshots/gitu__tests__discard__discard_branch_no.snap b/src/tests/snapshots/gitu__tests__discard__discard_branch_no.snap index 2b1e66507e..64edbeaea3 100644 --- a/src/tests/snapshots/gitu__tests__discard__discard_branch_no.snap +++ b/src/tests/snapshots/gitu__tests__discard__discard_branch_no.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 25b2be4c9a1311be +styles_hash: 2dcdd2c93f7b7c45 diff --git a/src/tests/snapshots/gitu__tests__discard__discard_branch_yes.snap b/src/tests/snapshots/gitu__tests__discard__discard_branch_yes.snap index eb28ba7102..d4a6e87726 100644 --- a/src/tests/snapshots/gitu__tests__discard__discard_branch_yes.snap +++ b/src/tests/snapshots/gitu__tests__discard__discard_branch_yes.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git branch -d asd | Deleted branch asd (was b66a0bf). | -styles_hash: 23987ef05a8bf7e +styles_hash: ab0e1a16029dbb52 diff --git a/src/tests/snapshots/gitu__tests__discard__discard_file_move.snap b/src/tests/snapshots/gitu__tests__discard__discard_file_move.snap index 5ecfea51be..88ebdcd403 100644 --- a/src/tests/snapshots/gitu__tests__discard__discard_file_move.snap +++ b/src/tests/snapshots/gitu__tests__discard__discard_file_move.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git apply --reverse --index --recount | -styles_hash: ba16ed1baaafac0e +styles_hash: 408bd4bdde94e463 diff --git a/src/tests/snapshots/gitu__tests__discard__discard_staged_file_while_unstaged_changes.snap b/src/tests/snapshots/gitu__tests__discard__discard_staged_file_while_unstaged_changes.snap index 0239cab825..afa205dd61 100644 --- a/src/tests/snapshots/gitu__tests__discard__discard_staged_file_while_unstaged_changes.snap +++ b/src/tests/snapshots/gitu__tests__discard__discard_staged_file_while_unstaged_changes.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() $ git apply --reverse --index --recount | error: initial-file: does not match index | ! 'git apply --reverse --index --recount' exited with code: 1 | -styles_hash: 9bd09231ddbd251f +styles_hash: 41414be8aed71b39 diff --git a/src/tests/snapshots/gitu__tests__discard__discard_staged_hunk_while_unstaged_changes.snap b/src/tests/snapshots/gitu__tests__discard__discard_staged_hunk_while_unstaged_changes.snap index 0965fa6b8b..8b63489b69 100644 --- a/src/tests/snapshots/gitu__tests__discard__discard_staged_hunk_while_unstaged_changes.snap +++ b/src/tests/snapshots/gitu__tests__discard__discard_staged_hunk_while_unstaged_changes.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() $ git apply --reverse --index --recount | error: initial-file: does not match index | ! 'git apply --reverse --index --recount' exited with code: 1 | -styles_hash: f7e6c68a251c8e9c +styles_hash: 1f1e5f67fa5a5bb9 diff --git a/src/tests/snapshots/gitu__tests__discard__discard_staged_line_while_unstaged_changes.snap b/src/tests/snapshots/gitu__tests__discard__discard_staged_line_while_unstaged_changes.snap index ab0d07d876..486a071980 100644 --- a/src/tests/snapshots/gitu__tests__discard__discard_staged_line_while_unstaged_changes.snap +++ b/src/tests/snapshots/gitu__tests__discard__discard_staged_line_while_unstaged_changes.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() $ git apply --reverse --index --recount | error: initial-file: does not match index | ! 'git apply --reverse --index --recount' exited with code: 1 | -styles_hash: 9a57d59afd88f922 +styles_hash: 97da2565a66858c5 diff --git a/src/tests/snapshots/gitu__tests__discard__discard_unstaged_delta.snap b/src/tests/snapshots/gitu__tests__discard__discard_unstaged_delta.snap index cbcf578fea..d69e716ae8 100644 --- a/src/tests/snapshots/gitu__tests__discard__discard_unstaged_delta.snap +++ b/src/tests/snapshots/gitu__tests__discard__discard_unstaged_delta.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git apply --reverse --recount | -styles_hash: 1b874ccb583c7648 +styles_hash: 3fc4d06472e98a9d diff --git a/src/tests/snapshots/gitu__tests__discard__discard_unstaged_hunk.snap b/src/tests/snapshots/gitu__tests__discard__discard_unstaged_hunk.snap index 028a4a2a09..a37db694d1 100644 --- a/src/tests/snapshots/gitu__tests__discard__discard_unstaged_hunk.snap +++ b/src/tests/snapshots/gitu__tests__discard__discard_unstaged_hunk.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git apply --reverse --recount | -styles_hash: 8f7c4c587f69ffd4 +styles_hash: 605627068763c1ee diff --git a/src/tests/snapshots/gitu__tests__discard__discard_unstaged_line.snap b/src/tests/snapshots/gitu__tests__discard__discard_unstaged_line.snap index 2e8495c68c..109a5ff86d 100644 --- a/src/tests/snapshots/gitu__tests__discard__discard_unstaged_line.snap +++ b/src/tests/snapshots/gitu__tests__discard__discard_unstaged_line.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git apply --reverse --recount | -styles_hash: 6795b03f13817018 +styles_hash: 3dc1a544e2914fd9 diff --git a/src/tests/snapshots/gitu__tests__discard__discard_untracked_file.snap b/src/tests/snapshots/gitu__tests__discard__discard_untracked_file.snap index 7c37b544b5..48b297513d 100644 --- a/src/tests/snapshots/gitu__tests__discard__discard_untracked_file.snap +++ b/src/tests/snapshots/gitu__tests__discard__discard_untracked_file.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git clean --force some-file | Removing some-file | -styles_hash: 96f58e6839f4cd +styles_hash: 33182dff4f601327 diff --git a/src/tests/snapshots/gitu__tests__discard__discard_untracked_staged_file.snap b/src/tests/snapshots/gitu__tests__discard__discard_untracked_staged_file.snap index f04c621c27..c32cff8eda 100644 --- a/src/tests/snapshots/gitu__tests__discard__discard_untracked_staged_file.snap +++ b/src/tests/snapshots/gitu__tests__discard__discard_untracked_staged_file.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git apply --reverse --index --recount | -styles_hash: b3e7414ab8f124a1 +styles_hash: ea25e9ecaba87b2d diff --git a/src/tests/snapshots/gitu__tests__discard__unmerged_branch_selected.snap b/src/tests/snapshots/gitu__tests__discard__unmerged_branch_selected.snap index 0ed161653e..7b437299e9 100644 --- a/src/tests/snapshots/gitu__tests__discard__unmerged_branch_selected.snap +++ b/src/tests/snapshots/gitu__tests__discard__unmerged_branch_selected.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git branch -d -f unmerged | Deleted branch unmerged (was c84f226). | -styles_hash: 7c47eb9adb3596aa +styles_hash: 538d5a2b41c4c7cb diff --git a/src/tests/snapshots/gitu__tests__discard__unmerged_branch_selected_unmerged_confirm.snap b/src/tests/snapshots/gitu__tests__discard__unmerged_branch_selected_unmerged_confirm.snap index 89e92cf2f3..4533e6050c 100644 --- a/src/tests/snapshots/gitu__tests__discard__unmerged_branch_selected_unmerged_confirm.snap +++ b/src/tests/snapshots/gitu__tests__discard__unmerged_branch_selected_unmerged_confirm.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Branch is not fully merged. Really delete? (y or n) › █ | -styles_hash: 491853582373e2bc +styles_hash: f35de1469c9b1486 diff --git a/src/tests/snapshots/gitu__tests__editor__exit_from_picker_exits_menu.snap b/src/tests/snapshots/gitu__tests__editor__exit_from_picker_exits_menu.snap index d03704f938..8e8f3416f4 100644 --- a/src/tests/snapshots/gitu__tests__editor__exit_from_picker_exits_menu.snap +++ b/src/tests/snapshots/gitu__tests__editor__exit_from_picker_exits_menu.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: f47a6512af0aca26 +styles_hash: 146fca7ccd68cab7 diff --git a/src/tests/snapshots/gitu__tests__editor__move_next_sibling.snap b/src/tests/snapshots/gitu__tests__editor__move_next_sibling.snap index 1d8ad20985..b9abceddd8 100644 --- a/src/tests/snapshots/gitu__tests__editor__move_next_sibling.snap +++ b/src/tests/snapshots/gitu__tests__editor__move_next_sibling.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ▌+line 15 (file-2) | ▌+line 16 (file-2) | ▌+line 17 (file-2) | -styles_hash: 8b4a7c91283b4dc +styles_hash: 3459c94eb2754adf diff --git a/src/tests/snapshots/gitu__tests__editor__move_next_then_parent_section.snap b/src/tests/snapshots/gitu__tests__editor__move_next_then_parent_section.snap index c626588d62..cb6fe4dbef 100644 --- a/src/tests/snapshots/gitu__tests__editor__move_next_then_parent_section.snap +++ b/src/tests/snapshots/gitu__tests__editor__move_next_then_parent_section.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ▌+line 15 (file-1) | ▌+line 16 (file-1) | ▌+line 17 (file-1) | -styles_hash: 77349537e5766256 +styles_hash: 4aa2c126ebd307c4 diff --git a/src/tests/snapshots/gitu__tests__editor__move_prev_sibling.snap b/src/tests/snapshots/gitu__tests__editor__move_prev_sibling.snap index 04af938cb2..0d6982c161 100644 --- a/src/tests/snapshots/gitu__tests__editor__move_prev_sibling.snap +++ b/src/tests/snapshots/gitu__tests__editor__move_prev_sibling.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() +line 12 (file-1) | +line 13 (file-1) | +line 14 (file-1) | -styles_hash: b8977a09f6b87dab +styles_hash: 22f905f36bfa2d53 diff --git a/src/tests/snapshots/gitu__tests__editor__re_enter_picker_from_menu.snap b/src/tests/snapshots/gitu__tests__editor__re_enter_picker_from_menu.snap index eea969d927..22c9b55ce1 100644 --- a/src/tests/snapshots/gitu__tests__editor__re_enter_picker_from_menu.snap +++ b/src/tests/snapshots/gitu__tests__editor__re_enter_picker_from_menu.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 49e995be810c0237 +styles_hash: 9ee80d670d7d5d8b diff --git a/src/tests/snapshots/gitu__tests__editor__scroll_down.snap b/src/tests/snapshots/gitu__tests__editor__scroll_down.snap index ab0131ee6d..f13000f882 100644 --- a/src/tests/snapshots/gitu__tests__editor__scroll_down.snap +++ b/src/tests/snapshots/gitu__tests__editor__scroll_down.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() @@ -0,0 +1,20 @@ | +line 1 (file-2) | +line 2 (file-2) | -styles_hash: ee3d46c497e041fa +styles_hash: 4ae3f6fa09b6520e diff --git a/src/tests/snapshots/gitu__tests__editor__scroll_past_selection.snap b/src/tests/snapshots/gitu__tests__editor__scroll_past_selection.snap index 1241613be4..af1d30c2f5 100644 --- a/src/tests/snapshots/gitu__tests__editor__scroll_past_selection.snap +++ b/src/tests/snapshots/gitu__tests__editor__scroll_past_selection.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() +line 20 (file-2) | modified file-3 | @@ -0,0 +1,20 @@ | -styles_hash: ba6ffe68111a437 +styles_hash: 6d1ffa09ebf6daca diff --git a/src/tests/snapshots/gitu__tests__ext_diff.snap b/src/tests/snapshots/gitu__tests__ext_diff.snap index 25b00167a5..4ae7c906a9 100644 --- a/src/tests/snapshots/gitu__tests__ext_diff.snap +++ b/src/tests/snapshots/gitu__tests__ext_diff.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 78d73e0b179ed03a +styles_hash: 875d69d553a5f62a diff --git a/src/tests/snapshots/gitu__tests__fetch__fetch_from_elsewhere.snap b/src/tests/snapshots/gitu__tests__fetch__fetch_from_elsewhere.snap index 692c50ace5..30ea435fbf 100644 --- a/src/tests/snapshots/gitu__tests__fetch__fetch_from_elsewhere.snap +++ b/src/tests/snapshots/gitu__tests__fetch__fetch_from_elsewhere.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git fetch origin | -styles_hash: 91a0547682745b50 +styles_hash: dde9bcfbe8787ef9 diff --git a/src/tests/snapshots/gitu__tests__fetch__fetch_from_elsewhere_prompt.snap b/src/tests/snapshots/gitu__tests__fetch__fetch_from_elsewhere_prompt.snap index 9d7688841e..a5c56c5bfa 100644 --- a/src/tests/snapshots/gitu__tests__fetch__fetch_from_elsewhere_prompt.snap +++ b/src/tests/snapshots/gitu__tests__fetch__fetch_from_elsewhere_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Select remote: › █ | -styles_hash: d4bf27d871c90729 +styles_hash: 27b62992ccb47712 diff --git a/src/tests/snapshots/gitu__tests__fetch__fetch_from_push_remote.snap b/src/tests/snapshots/gitu__tests__fetch__fetch_from_push_remote.snap index 692c50ace5..30ea435fbf 100644 --- a/src/tests/snapshots/gitu__tests__fetch__fetch_from_push_remote.snap +++ b/src/tests/snapshots/gitu__tests__fetch__fetch_from_push_remote.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git fetch origin | -styles_hash: 91a0547682745b50 +styles_hash: dde9bcfbe8787ef9 diff --git a/src/tests/snapshots/gitu__tests__fetch__fetch_from_push_remote_prompt.snap b/src/tests/snapshots/gitu__tests__fetch__fetch_from_push_remote_prompt.snap index 4d8eaece5e..2033fa1999 100644 --- a/src/tests/snapshots/gitu__tests__fetch__fetch_from_push_remote_prompt.snap +++ b/src/tests/snapshots/gitu__tests__fetch__fetch_from_push_remote_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Set pushRemote then fetch: › █ | -styles_hash: 5912af6faa12579e +styles_hash: ad681b11abeab0fe diff --git a/src/tests/snapshots/gitu__tests__fetch__fetch_from_upstream.snap b/src/tests/snapshots/gitu__tests__fetch__fetch_from_upstream.snap index 692c50ace5..30ea435fbf 100644 --- a/src/tests/snapshots/gitu__tests__fetch__fetch_from_upstream.snap +++ b/src/tests/snapshots/gitu__tests__fetch__fetch_from_upstream.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git fetch origin | -styles_hash: 91a0547682745b50 +styles_hash: dde9bcfbe8787ef9 diff --git a/src/tests/snapshots/gitu__tests__fetch__fetch_from_upstream_prompt.snap b/src/tests/snapshots/gitu__tests__fetch__fetch_from_upstream_prompt.snap index cc1bb636d2..19e138d0ab 100644 --- a/src/tests/snapshots/gitu__tests__fetch__fetch_from_upstream_prompt.snap +++ b/src/tests/snapshots/gitu__tests__fetch__fetch_from_upstream_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Set upstream then fetch: › █ | -styles_hash: a9ce1b225e9e7e38 +styles_hash: c82b1e41e00ab83d diff --git a/src/tests/snapshots/gitu__tests__fetch__fetch_menu_existing_push_remote_and_upstream.snap b/src/tests/snapshots/gitu__tests__fetch__fetch_menu_existing_push_remote_and_upstream.snap index 10e7afa1ac..0ec28e6aee 100644 --- a/src/tests/snapshots/gitu__tests__fetch__fetch_menu_existing_push_remote_and_upstream.snap +++ b/src/tests/snapshots/gitu__tests__fetch__fetch_menu_existing_push_remote_and_upstream.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() u from origin | e from elsewhere | q/esc Quit/Close | -styles_hash: 17731e0c232c3b88 +styles_hash: bd383ea18c28e750 diff --git a/src/tests/snapshots/gitu__tests__fetch__fetch_menu_no_remote_or_upstream_set.snap b/src/tests/snapshots/gitu__tests__fetch__fetch_menu_no_remote_or_upstream_set.snap index 3bd4e8e3e4..b7090055a7 100644 --- a/src/tests/snapshots/gitu__tests__fetch__fetch_menu_no_remote_or_upstream_set.snap +++ b/src/tests/snapshots/gitu__tests__fetch__fetch_menu_no_remote_or_upstream_set.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() u from upstream, setting that | e from elsewhere | q/esc Quit/Close | -styles_hash: fbb28b712f78e61e +styles_hash: 440a2e96e23b3a85 diff --git a/src/tests/snapshots/gitu__tests__fetch_all.snap b/src/tests/snapshots/gitu__tests__fetch_all.snap index 03a80f619e..79f6050c0c 100644 --- a/src/tests/snapshots/gitu__tests__fetch_all.snap +++ b/src/tests/snapshots/gitu__tests__fetch_all.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() $ git fetch --all --jobs 10 | From file:// b66a0bf..d07f2d3 main -> origin/main | -styles_hash: f448eeaae20a6982 +styles_hash: 8a8e7ce3455f812c diff --git a/src/tests/snapshots/gitu__tests__fresh_init.snap b/src/tests/snapshots/gitu__tests__fresh_init.snap index e8fccbb494..aa5c174457 100644 --- a/src/tests/snapshots/gitu__tests__fresh_init.snap +++ b/src/tests/snapshots/gitu__tests__fresh_init.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: a4529b27ea78d70b +styles_hash: 858def92cd8abc8d diff --git a/src/tests/snapshots/gitu__tests__go_down_past_collapsed.snap b/src/tests/snapshots/gitu__tests__go_down_past_collapsed.snap index 2955cde860..4a7ea56bb2 100644 --- a/src/tests/snapshots/gitu__tests__go_down_past_collapsed.snap +++ b/src/tests/snapshots/gitu__tests__go_down_past_collapsed.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: ced58bcec150cda1 +styles_hash: 779d350d6a38043e diff --git a/src/tests/snapshots/gitu__tests__help_menu.snap b/src/tests/snapshots/gitu__tests__help_menu.snap index 9e774ffd91..9e0aa1afd8 100644 --- a/src/tests/snapshots/gitu__tests__help_menu.snap +++ b/src/tests/snapshots/gitu__tests__help_menu.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ctrl+e Scroll view down z Stash | g+r Refresh | q/esc Quit/Close | -styles_hash: f683951757a0712c +styles_hash: eacaf294c6f7ca0a diff --git a/src/tests/snapshots/gitu__tests__hide_untracked.snap b/src/tests/snapshots/gitu__tests__hide_untracked.snap index 2f484aa8d3..85bea39a79 100644 --- a/src/tests/snapshots/gitu__tests__hide_untracked.snap +++ b/src/tests/snapshots/gitu__tests__hide_untracked.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: f47a6512af0aca26 +styles_hash: 146fca7ccd68cab7 diff --git a/src/tests/snapshots/gitu__tests__inside_submodule.snap b/src/tests/snapshots/gitu__tests__inside_submodule.snap index 2f484aa8d3..85bea39a79 100644 --- a/src/tests/snapshots/gitu__tests__inside_submodule.snap +++ b/src/tests/snapshots/gitu__tests__inside_submodule.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: f47a6512af0aca26 +styles_hash: 146fca7ccd68cab7 diff --git a/src/tests/snapshots/gitu__tests__log.snap b/src/tests/snapshots/gitu__tests__log.snap index 3b8cca5112..644d910288 100644 --- a/src/tests/snapshots/gitu__tests__log.snap +++ b/src/tests/snapshots/gitu__tests__log.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 7c34283c9cbd748b +styles_hash: 47d7b32e1c94166c diff --git a/src/tests/snapshots/gitu__tests__log__grep_no_match.snap b/src/tests/snapshots/gitu__tests__log__grep_no_match.snap index d3d96944e8..97f74dc1ea 100644 --- a/src/tests/snapshots/gitu__tests__log__grep_no_match.snap +++ b/src/tests/snapshots/gitu__tests__log__grep_no_match.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 90ecdf643519e051 +styles_hash: fd361eadad4094c9 diff --git a/src/tests/snapshots/gitu__tests__log__grep_prompt.snap b/src/tests/snapshots/gitu__tests__log__grep_prompt.snap index cef1f071d9..817c6ced08 100644 --- a/src/tests/snapshots/gitu__tests__log__grep_prompt.snap +++ b/src/tests/snapshots/gitu__tests__log__grep_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() q/esc Quit/Close | ────────────────────────────────────────────────────────────────────────────────| ? Search messages: › █ | -styles_hash: 30915effaeaeb2e3 +styles_hash: f2eebb39c405f80c diff --git a/src/tests/snapshots/gitu__tests__log__grep_second.snap b/src/tests/snapshots/gitu__tests__log__grep_second.snap index a612fdf680..324f7364be 100644 --- a/src/tests/snapshots/gitu__tests__log__grep_second.snap +++ b/src/tests/snapshots/gitu__tests__log__grep_second.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 48d19316a51368e3 +styles_hash: c60740e4f1c77f24 diff --git a/src/tests/snapshots/gitu__tests__log__grep_second_other.snap b/src/tests/snapshots/gitu__tests__log__grep_second_other.snap index a612fdf680..324f7364be 100644 --- a/src/tests/snapshots/gitu__tests__log__grep_second_other.snap +++ b/src/tests/snapshots/gitu__tests__log__grep_second_other.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 48d19316a51368e3 +styles_hash: c60740e4f1c77f24 diff --git a/src/tests/snapshots/gitu__tests__log__grep_set_example.snap b/src/tests/snapshots/gitu__tests__log__grep_set_example.snap index 2bfcca8eeb..fd5375438b 100644 --- a/src/tests/snapshots/gitu__tests__log__grep_set_example.snap +++ b/src/tests/snapshots/gitu__tests__log__grep_set_example.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() l current -F Search messages (--grep=example) | o other -n Limit number of commits (-n=256) | q/esc Quit/Close | -styles_hash: 5877b9adb59fe24d +styles_hash: c3ce2be766716a22 diff --git a/src/tests/snapshots/gitu__tests__log__limit_2_commits.snap b/src/tests/snapshots/gitu__tests__log__limit_2_commits.snap index 90a5ae2fed..854bdd466c 100644 --- a/src/tests/snapshots/gitu__tests__log__limit_2_commits.snap +++ b/src/tests/snapshots/gitu__tests__log__limit_2_commits.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: a908290abddd40c9 +styles_hash: 60358599816f45c diff --git a/src/tests/snapshots/gitu__tests__log__limit_2_commits_other.snap b/src/tests/snapshots/gitu__tests__log__limit_2_commits_other.snap index 90a5ae2fed..854bdd466c 100644 --- a/src/tests/snapshots/gitu__tests__log__limit_2_commits_other.snap +++ b/src/tests/snapshots/gitu__tests__log__limit_2_commits_other.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: a908290abddd40c9 +styles_hash: 60358599816f45c diff --git a/src/tests/snapshots/gitu__tests__log__limit_invalid.snap b/src/tests/snapshots/gitu__tests__log__limit_invalid.snap index 5fbc1c74e3..97e5950660 100644 --- a/src/tests/snapshots/gitu__tests__log__limit_invalid.snap +++ b/src/tests/snapshots/gitu__tests__log__limit_invalid.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ! Value must be a number greater than 0 | -styles_hash: bd845daabc6ec344 +styles_hash: 7eab8669eff1a2e4 diff --git a/src/tests/snapshots/gitu__tests__log__limit_prompt.snap b/src/tests/snapshots/gitu__tests__log__limit_prompt.snap index cdca916481..99299c482c 100644 --- a/src/tests/snapshots/gitu__tests__log__limit_prompt.snap +++ b/src/tests/snapshots/gitu__tests__log__limit_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() q/esc Quit/Close | ────────────────────────────────────────────────────────────────────────────────| ? Limit number of commits (default 256): › █ | -styles_hash: 99ca458c7c196a27 +styles_hash: 62cf3084d4145092 diff --git a/src/tests/snapshots/gitu__tests__log__limit_set_10.snap b/src/tests/snapshots/gitu__tests__log__limit_set_10.snap index 073a41dbbd..2547dc0422 100644 --- a/src/tests/snapshots/gitu__tests__log__limit_set_10.snap +++ b/src/tests/snapshots/gitu__tests__log__limit_set_10.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() l current -F Search messages (--grep) | o other -n Limit number of commits (-n=10) | q/esc Quit/Close | -styles_hash: 195bb974698466ed +styles_hash: 706331cc5663f6bb diff --git a/src/tests/snapshots/gitu__tests__log__log_empty_branch.snap b/src/tests/snapshots/gitu__tests__log__log_empty_branch.snap index 2049dfc25c..403391f51c 100644 --- a/src/tests/snapshots/gitu__tests__log__log_empty_branch.snap +++ b/src/tests/snapshots/gitu__tests__log__log_empty_branch.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 355101d0bd329837 +styles_hash: 278229390e566dff diff --git a/src/tests/snapshots/gitu__tests__log__log_other.snap b/src/tests/snapshots/gitu__tests__log__log_other.snap index ed6b5a89a1..54bbfdd6cc 100644 --- a/src/tests/snapshots/gitu__tests__log__log_other.snap +++ b/src/tests/snapshots/gitu__tests__log__log_other.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 99c011aa1629f1d +styles_hash: 289a0cd5847e04b0 diff --git a/src/tests/snapshots/gitu__tests__log__log_other_input.snap b/src/tests/snapshots/gitu__tests__log__log_other_input.snap index ed6b5a89a1..54bbfdd6cc 100644 --- a/src/tests/snapshots/gitu__tests__log__log_other_input.snap +++ b/src/tests/snapshots/gitu__tests__log__log_other_input.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 99c011aa1629f1d +styles_hash: 289a0cd5847e04b0 diff --git a/src/tests/snapshots/gitu__tests__log__log_other_invalid.snap b/src/tests/snapshots/gitu__tests__log__log_other_invalid.snap index b511e0f58c..469a922969 100644 --- a/src/tests/snapshots/gitu__tests__log__log_other_invalid.snap +++ b/src/tests/snapshots/gitu__tests__log__log_other_invalid.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| ! Couldn't find git revision: failed to parse revision specifier - Invalid | pattern ' '; class=Invalid (3); code=InvalidSpec (-12) | -styles_hash: db8d105d97033047 +styles_hash: 9fcf3c3e448ea67b diff --git a/src/tests/snapshots/gitu__tests__log__log_other_prompt.snap b/src/tests/snapshots/gitu__tests__log__log_other_prompt.snap index 58b650f9f0..bd98581a57 100644 --- a/src/tests/snapshots/gitu__tests__log__log_other_prompt.snap +++ b/src/tests/snapshots/gitu__tests__log__log_other_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Log rev (default 6c08cf78a4544ae4dda8e6161a61070867c60246): › █ | -styles_hash: 3bf733ac5c610d53 +styles_hash: 179fa0488686d01b diff --git a/src/tests/snapshots/gitu__tests__merge__merge_ff_only.snap b/src/tests/snapshots/gitu__tests__merge__merge_ff_only.snap index d5029ac271..00b77254a7 100644 --- a/src/tests/snapshots/gitu__tests__merge__merge_ff_only.snap +++ b/src/tests/snapshots/gitu__tests__merge__merge_ff_only.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git merge --ff-only other-branch | -styles_hash: 22e96ae1e6b12a5f +styles_hash: fca97718c66f94c4 diff --git a/src/tests/snapshots/gitu__tests__merge__merge_menu.snap b/src/tests/snapshots/gitu__tests__merge__merge_menu.snap index 9e3885316e..b461392f76 100644 --- a/src/tests/snapshots/gitu__tests__merge__merge_menu.snap +++ b/src/tests/snapshots/gitu__tests__merge__merge_menu.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() a abort -n No fast-forward (--no-ff) | c continue | q/ Quit/Close | -styles_hash: 7b86e45a0c70a078 +styles_hash: 6076d7c1a8622919 diff --git a/src/tests/snapshots/gitu__tests__merge__merge_no_ff.snap b/src/tests/snapshots/gitu__tests__merge__merge_no_ff.snap index c0b74eb779..9a1ee0283b 100644 --- a/src/tests/snapshots/gitu__tests__merge__merge_no_ff.snap +++ b/src/tests/snapshots/gitu__tests__merge__merge_no_ff.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git merge --no-ff other-branch | -styles_hash: 533f988da88d3c89 +styles_hash: 1b316859ae953e65 diff --git a/src/tests/snapshots/gitu__tests__merge__merge_picker.snap b/src/tests/snapshots/gitu__tests__merge__merge_picker.snap index aef0a95396..4955dddf5e 100644 --- a/src/tests/snapshots/gitu__tests__merge__merge_picker.snap +++ b/src/tests/snapshots/gitu__tests__merge__merge_picker.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 16f8dd2fc9f8bc2f +styles_hash: c25a5258336b74b8 diff --git a/src/tests/snapshots/gitu__tests__merge__merge_picker_cancel.snap b/src/tests/snapshots/gitu__tests__merge__merge_picker_cancel.snap index 65b3b5a298..28130892a2 100644 --- a/src/tests/snapshots/gitu__tests__merge__merge_picker_cancel.snap +++ b/src/tests/snapshots/gitu__tests__merge__merge_picker_cancel.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: f47a6512af0aca26 +styles_hash: 146fca7ccd68cab7 diff --git a/src/tests/snapshots/gitu__tests__merge__merge_picker_custom_input.snap b/src/tests/snapshots/gitu__tests__merge__merge_picker_custom_input.snap index ac89e1a23f..5cbeede7ea 100644 --- a/src/tests/snapshots/gitu__tests__merge__merge_picker_custom_input.snap +++ b/src/tests/snapshots/gitu__tests__merge__merge_picker_custom_input.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 6f95b383fced9e3c +styles_hash: 2b22a7699d978802 diff --git a/src/tests/snapshots/gitu__tests__merge__merge_picker_duplicate_names_select_branch.snap b/src/tests/snapshots/gitu__tests__merge__merge_picker_duplicate_names_select_branch.snap index df920e9a33..a605e6471d 100644 --- a/src/tests/snapshots/gitu__tests__merge__merge_picker_duplicate_names_select_branch.snap +++ b/src/tests/snapshots/gitu__tests__merge__merge_picker_duplicate_names_select_branch.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() $ git merge v1.0.0 | warning: refname 'v1.0.0' is ambiguous. | warning: refname 'v1.0.0' is ambiguous. | -styles_hash: 96ba88c230adae56 +styles_hash: 18b35e057dbb09a6 diff --git a/src/tests/snapshots/gitu__tests__merge__merge_picker_duplicate_names_select_tag.snap b/src/tests/snapshots/gitu__tests__merge__merge_picker_duplicate_names_select_tag.snap index 4d207b761a..bba09ede7c 100644 --- a/src/tests/snapshots/gitu__tests__merge__merge_picker_duplicate_names_select_tag.snap +++ b/src/tests/snapshots/gitu__tests__merge__merge_picker_duplicate_names_select_tag.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git merge refs/tags/v1.0.0 | -styles_hash: 253546b91b05cb9 +styles_hash: 8f456f85cedc4d7c diff --git a/src/tests/snapshots/gitu__tests__merge__merge_select_from_list.snap b/src/tests/snapshots/gitu__tests__merge__merge_select_from_list.snap index 4f622169b7..38baf89923 100644 --- a/src/tests/snapshots/gitu__tests__merge__merge_select_from_list.snap +++ b/src/tests/snapshots/gitu__tests__merge__merge_select_from_list.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git merge feature-a | -styles_hash: 994114f03d7a9c3c +styles_hash: 6d38fe575fb2440d diff --git a/src/tests/snapshots/gitu__tests__merge__merge_use_custom_input.snap b/src/tests/snapshots/gitu__tests__merge__merge_use_custom_input.snap index ca2a305f50..4f4c01881b 100644 --- a/src/tests/snapshots/gitu__tests__merge__merge_use_custom_input.snap +++ b/src/tests/snapshots/gitu__tests__merge__merge_use_custom_input.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git merge b66a0bf82020d6a386e94d0fceedec1f817d20c7 | -styles_hash: 1913e3f30ba0cc1b +styles_hash: 73e9fdd5d2c4fca5 diff --git a/src/tests/snapshots/gitu__tests__merge_conflict.snap b/src/tests/snapshots/gitu__tests__merge_conflict.snap index b909fe8ca1..fbe395ed42 100644 --- a/src/tests/snapshots/gitu__tests__merge_conflict.snap +++ b/src/tests/snapshots/gitu__tests__merge_conflict.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: f80e04421a39123 +styles_hash: 70ddc098023ff277 diff --git a/src/tests/snapshots/gitu__tests__mouse_select_hunk_line.snap b/src/tests/snapshots/gitu__tests__mouse_select_hunk_line.snap index 962de5e541..87a5cf0b5b 100644 --- a/src/tests/snapshots/gitu__tests__mouse_select_hunk_line.snap +++ b/src/tests/snapshots/gitu__tests__mouse_select_hunk_line.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 9e60da5cf26728a4 +styles_hash: a8106d9752eb08f7 diff --git a/src/tests/snapshots/gitu__tests__mouse_select_ignore_empty_lines.snap b/src/tests/snapshots/gitu__tests__mouse_select_ignore_empty_lines.snap index 85379f83b6..d3fc68ac0c 100644 --- a/src/tests/snapshots/gitu__tests__mouse_select_ignore_empty_lines.snap +++ b/src/tests/snapshots/gitu__tests__mouse_select_ignore_empty_lines.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 96cd3159bc3b002 +styles_hash: c8491f47b65cb53b diff --git a/src/tests/snapshots/gitu__tests__mouse_select_ignore_empty_region.snap b/src/tests/snapshots/gitu__tests__mouse_select_ignore_empty_region.snap index 85379f83b6..d3fc68ac0c 100644 --- a/src/tests/snapshots/gitu__tests__mouse_select_ignore_empty_region.snap +++ b/src/tests/snapshots/gitu__tests__mouse_select_ignore_empty_region.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 96cd3159bc3b002 +styles_hash: c8491f47b65cb53b diff --git a/src/tests/snapshots/gitu__tests__mouse_select_item.snap b/src/tests/snapshots/gitu__tests__mouse_select_item.snap index 62a5aab872..85ce58da9f 100644 --- a/src/tests/snapshots/gitu__tests__mouse_select_item.snap +++ b/src/tests/snapshots/gitu__tests__mouse_select_item.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 47dabecbf8cc26c3 +styles_hash: 8384a852e904d4e1 diff --git a/src/tests/snapshots/gitu__tests__mouse_show_ignore_empty_lines.snap b/src/tests/snapshots/gitu__tests__mouse_show_ignore_empty_lines.snap index 57b1ee67ee..c6d2097990 100644 --- a/src/tests/snapshots/gitu__tests__mouse_show_ignore_empty_lines.snap +++ b/src/tests/snapshots/gitu__tests__mouse_show_ignore_empty_lines.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 756a2316769a9390 +styles_hash: abb13d9c1779e6fc diff --git a/src/tests/snapshots/gitu__tests__mouse_show_ignore_empty_region.snap b/src/tests/snapshots/gitu__tests__mouse_show_ignore_empty_region.snap index 57b1ee67ee..c6d2097990 100644 --- a/src/tests/snapshots/gitu__tests__mouse_show_ignore_empty_region.snap +++ b/src/tests/snapshots/gitu__tests__mouse_show_ignore_empty_region.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 756a2316769a9390 +styles_hash: abb13d9c1779e6fc diff --git a/src/tests/snapshots/gitu__tests__mouse_show_item.snap b/src/tests/snapshots/gitu__tests__mouse_show_item.snap index 644bd38836..f76e403bcc 100644 --- a/src/tests/snapshots/gitu__tests__mouse_show_item.snap +++ b/src/tests/snapshots/gitu__tests__mouse_show_item.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: aa867385650c4035 +styles_hash: 1d4ae1b59e628f73 diff --git a/src/tests/snapshots/gitu__tests__mouse_toggle_selected_item.snap b/src/tests/snapshots/gitu__tests__mouse_toggle_selected_item.snap index 84fcd17ed9..1f3132fed8 100644 --- a/src/tests/snapshots/gitu__tests__mouse_toggle_selected_item.snap +++ b/src/tests/snapshots/gitu__tests__mouse_toggle_selected_item.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: ad7a877442acc5a7 +styles_hash: 7ff7988689cb4002 diff --git a/src/tests/snapshots/gitu__tests__mouse_wheel_scroll_down.snap b/src/tests/snapshots/gitu__tests__mouse_wheel_scroll_down.snap index 681817679d..bf0ef5c5cf 100644 --- a/src/tests/snapshots/gitu__tests__mouse_wheel_scroll_down.snap +++ b/src/tests/snapshots/gitu__tests__mouse_wheel_scroll_down.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() modified file17… | modified file18… | modified file19… | -styles_hash: e2b83c90b357195b +styles_hash: 639a67cc29c6712b diff --git a/src/tests/snapshots/gitu__tests__mouse_wheel_scroll_up.snap b/src/tests/snapshots/gitu__tests__mouse_wheel_scroll_up.snap index f40ae9408f..5e3ad7b242 100644 --- a/src/tests/snapshots/gitu__tests__mouse_wheel_scroll_up.snap +++ b/src/tests/snapshots/gitu__tests__mouse_wheel_scroll_up.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | Recent commits | ae744cc main add file30 | -styles_hash: 9d0bedcc92bfcaa8 +styles_hash: 5f4e827357c1ae2c diff --git a/src/tests/snapshots/gitu__tests__moved_file.snap b/src/tests/snapshots/gitu__tests__moved_file.snap index 4f1b217b41..57a5c55368 100644 --- a/src/tests/snapshots/gitu__tests__moved_file.snap +++ b/src/tests/snapshots/gitu__tests__moved_file.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 43a9ff7990a714d +styles_hash: d39ea159178d85b8 diff --git a/src/tests/snapshots/gitu__tests__new_commit.snap b/src/tests/snapshots/gitu__tests__new_commit.snap index d65de6c990..556f265c72 100644 --- a/src/tests/snapshots/gitu__tests__new_commit.snap +++ b/src/tests/snapshots/gitu__tests__new_commit.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: e010edc5475641a +styles_hash: 99cd49a2de846aca diff --git a/src/tests/snapshots/gitu__tests__new_file.snap b/src/tests/snapshots/gitu__tests__new_file.snap index 4af855dd26..3f44b492b3 100644 --- a/src/tests/snapshots/gitu__tests__new_file.snap +++ b/src/tests/snapshots/gitu__tests__new_file.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 303d1d0cfdc63762 +styles_hash: 5a2305acc18d235e diff --git a/src/tests/snapshots/gitu__tests__non_ascii_filename.snap b/src/tests/snapshots/gitu__tests__non_ascii_filename.snap index 588ab7a999..34bd67936e 100644 --- a/src/tests/snapshots/gitu__tests__non_ascii_filename.snap +++ b/src/tests/snapshots/gitu__tests__non_ascii_filename.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: e79b629595dfd37f +styles_hash: ab172fef81cd0c1b diff --git a/src/tests/snapshots/gitu__tests__non_utf8_diff.snap b/src/tests/snapshots/gitu__tests__non_utf8_diff.snap index 9d52e22b93..6838b173a4 100644 --- a/src/tests/snapshots/gitu__tests__non_utf8_diff.snap +++ b/src/tests/snapshots/gitu__tests__non_utf8_diff.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 232c1529ecd86f60 +styles_hash: dfa2cd7993ecbc65 diff --git a/src/tests/snapshots/gitu__tests__pull__pull_from_elsewhere.snap b/src/tests/snapshots/gitu__tests__pull__pull_from_elsewhere.snap index a2c3cf15b7..11d6ba1adb 100644 --- a/src/tests/snapshots/gitu__tests__pull__pull_from_elsewhere.snap +++ b/src/tests/snapshots/gitu__tests__pull__pull_from_elsewhere.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git pull origin | Already up to date. | -styles_hash: b401f8433340269 +styles_hash: e36f64119a8fa528 diff --git a/src/tests/snapshots/gitu__tests__pull__pull_from_elsewhere_prompt.snap b/src/tests/snapshots/gitu__tests__pull__pull_from_elsewhere_prompt.snap index a512f5c390..e442c7e5a5 100644 --- a/src/tests/snapshots/gitu__tests__pull__pull_from_elsewhere_prompt.snap +++ b/src/tests/snapshots/gitu__tests__pull__pull_from_elsewhere_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Select remote: › █ | -styles_hash: d4bf27d871c90729 +styles_hash: 27b62992ccb47712 diff --git a/src/tests/snapshots/gitu__tests__pull__pull_menu_existing_push_remote_and_upstream.snap b/src/tests/snapshots/gitu__tests__pull__pull_menu_existing_push_remote_and_upstream.snap index 4a334ac067..de0fa0156f 100644 --- a/src/tests/snapshots/gitu__tests__pull__pull_menu_existing_push_remote_and_upstream.snap +++ b/src/tests/snapshots/gitu__tests__pull__pull_menu_existing_push_remote_and_upstream.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() u from origin/main | e from elsewhere | q/esc Quit/Close | -styles_hash: 921d63089e120af4 +styles_hash: 4a11b7c07eb8d40f diff --git a/src/tests/snapshots/gitu__tests__pull__pull_menu_no_remote_or_upstream_set.snap b/src/tests/snapshots/gitu__tests__pull__pull_menu_no_remote_or_upstream_set.snap index e9eb2eeec7..d5ad932c03 100644 --- a/src/tests/snapshots/gitu__tests__pull__pull_menu_no_remote_or_upstream_set.snap +++ b/src/tests/snapshots/gitu__tests__pull__pull_menu_no_remote_or_upstream_set.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() u upstream, setting that | e from elsewhere | q/esc Quit/Close | -styles_hash: c5e18172f3d27bf5 +styles_hash: 637e0025914b9fa1 diff --git a/src/tests/snapshots/gitu__tests__pull__pull_push_remote.snap b/src/tests/snapshots/gitu__tests__pull__pull_push_remote.snap index a024e5474a..9207db6ad5 100644 --- a/src/tests/snapshots/gitu__tests__pull__pull_push_remote.snap +++ b/src/tests/snapshots/gitu__tests__pull__pull_push_remote.snap @@ -22,4 +22,4 @@ $ git pull origin refs/heads/main From file:// * branch main -> FETCH_HEAD | Already up to date. | -styles_hash: 8d2c591f621fface +styles_hash: cd9783096eb47a06 diff --git a/src/tests/snapshots/gitu__tests__pull__pull_push_remote_prompt.snap b/src/tests/snapshots/gitu__tests__pull__pull_push_remote_prompt.snap index e38e2c150a..1d74815b6f 100644 --- a/src/tests/snapshots/gitu__tests__pull__pull_push_remote_prompt.snap +++ b/src/tests/snapshots/gitu__tests__pull__pull_push_remote_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Set pushRemote then pull: › █ | -styles_hash: 74c60e97b247cdc3 +styles_hash: a5d5f61ccef869f diff --git a/src/tests/snapshots/gitu__tests__pull__pull_setup_push_remote.snap b/src/tests/snapshots/gitu__tests__pull__pull_setup_push_remote.snap index 4a334ac067..de0fa0156f 100644 --- a/src/tests/snapshots/gitu__tests__pull__pull_setup_push_remote.snap +++ b/src/tests/snapshots/gitu__tests__pull__pull_setup_push_remote.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() u from origin/main | e from elsewhere | q/esc Quit/Close | -styles_hash: 921d63089e120af4 +styles_hash: 4a11b7c07eb8d40f diff --git a/src/tests/snapshots/gitu__tests__pull__pull_setup_upstream.snap b/src/tests/snapshots/gitu__tests__pull__pull_setup_upstream.snap index e5a25f5da9..a99e0b0846 100644 --- a/src/tests/snapshots/gitu__tests__pull__pull_setup_upstream.snap +++ b/src/tests/snapshots/gitu__tests__pull__pull_setup_upstream.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() u from main | e from elsewhere | q/esc Quit/Close | -styles_hash: 7bc7b0fa946fd8ec +styles_hash: d08770b212d329e1 diff --git a/src/tests/snapshots/gitu__tests__pull__pull_setup_upstream_same_as_head.snap b/src/tests/snapshots/gitu__tests__pull__pull_setup_upstream_same_as_head.snap index b5e63d4119..cad2009e99 100644 --- a/src/tests/snapshots/gitu__tests__pull__pull_setup_upstream_same_as_head.snap +++ b/src/tests/snapshots/gitu__tests__pull__pull_setup_upstream_same_as_head.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git branch --set-upstream-to new-branch | warning: not setting branch 'new-branch' as its own upstream | -styles_hash: 279b7bfb84f655f4 +styles_hash: 18594f01cd281b8f diff --git a/src/tests/snapshots/gitu__tests__pull__pull_upstream.snap b/src/tests/snapshots/gitu__tests__pull__pull_upstream.snap index 96ef611778..f2a44301cc 100644 --- a/src/tests/snapshots/gitu__tests__pull__pull_upstream.snap +++ b/src/tests/snapshots/gitu__tests__pull__pull_upstream.snap @@ -22,4 +22,4 @@ Fast-forward remote-file | 1 + | 1 file changed, 1 insertion(+) | create mode 100644 remote-file | -styles_hash: cf16b967e587e1a4 +styles_hash: b6ce47a26557253d diff --git a/src/tests/snapshots/gitu__tests__pull__pull_upstream_prompt.snap b/src/tests/snapshots/gitu__tests__pull__pull_upstream_prompt.snap index ebd4bed27b..abab688c94 100644 --- a/src/tests/snapshots/gitu__tests__pull__pull_upstream_prompt.snap +++ b/src/tests/snapshots/gitu__tests__pull__pull_upstream_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Set upstream then pull: › █ | -styles_hash: 192f52eb6bc15ece +styles_hash: ba13237f9bab9178 diff --git a/src/tests/snapshots/gitu__tests__push__force_push.snap b/src/tests/snapshots/gitu__tests__push__force_push.snap index f479bb01ac..1a944177ad 100644 --- a/src/tests/snapshots/gitu__tests__push__force_push.snap +++ b/src/tests/snapshots/gitu__tests__push__force_push.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() $ git push --force-with-lease origin refs/heads/main:refs/heads/main | To file:// b66a0bf..e7eb2bd main -> main | -styles_hash: 55025d554763c6c6 +styles_hash: b915bcc23d3116ec diff --git a/src/tests/snapshots/gitu__tests__push__open_push_menu_after_dash_input.snap b/src/tests/snapshots/gitu__tests__push__open_push_menu_after_dash_input.snap index c6ce1b1241..b625e85b66 100644 --- a/src/tests/snapshots/gitu__tests__push__open_push_menu_after_dash_input.snap +++ b/src/tests/snapshots/gitu__tests__push__open_push_menu_after_dash_input.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() u to origin/main -F Force (--force) | e to elsewhere -f Force with lease (--force-with-lease) | q/esc Quit/Close -h Disable hooks (--no-verify) | -styles_hash: 423a5e46d8d37364 +styles_hash: 7526b958731867e9 diff --git a/src/tests/snapshots/gitu__tests__push__push_elsewhere.snap b/src/tests/snapshots/gitu__tests__push__push_elsewhere.snap index 880306fb97..b263b74de9 100644 --- a/src/tests/snapshots/gitu__tests__push__push_elsewhere.snap +++ b/src/tests/snapshots/gitu__tests__push__push_elsewhere.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git push origin | Everything up-to-date | -styles_hash: b401f8433340269 +styles_hash: e36f64119a8fa528 diff --git a/src/tests/snapshots/gitu__tests__push__push_elsewhere_prompt.snap b/src/tests/snapshots/gitu__tests__push__push_elsewhere_prompt.snap index a9526691ba..4318e8305e 100644 --- a/src/tests/snapshots/gitu__tests__push__push_elsewhere_prompt.snap +++ b/src/tests/snapshots/gitu__tests__push__push_elsewhere_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Select remote: › █ | -styles_hash: d4bf27d871c90729 +styles_hash: 27b62992ccb47712 diff --git a/src/tests/snapshots/gitu__tests__push__push_menu_existing_push_remote_and_upstream.snap b/src/tests/snapshots/gitu__tests__push__push_menu_existing_push_remote_and_upstream.snap index 8999c239cb..78994d4f0a 100644 --- a/src/tests/snapshots/gitu__tests__push__push_menu_existing_push_remote_and_upstream.snap +++ b/src/tests/snapshots/gitu__tests__push__push_menu_existing_push_remote_and_upstream.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() u to origin/main -F Force (--force) | e to elsewhere -f Force with lease (--force-with-lease) | q/esc Quit/Close -h Disable hooks (--no-verify) | -styles_hash: 48bf3603bf81dcbf +styles_hash: 7d2fbf4f1a23e447 diff --git a/src/tests/snapshots/gitu__tests__push__push_menu_no_branch.snap b/src/tests/snapshots/gitu__tests__push__push_menu_no_branch.snap index 5c54e4055e..da728267e7 100644 --- a/src/tests/snapshots/gitu__tests__push__push_menu_no_branch.snap +++ b/src/tests/snapshots/gitu__tests__push__push_menu_no_branch.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ! Head is not a branch | -styles_hash: 8b09634a27b31084 +styles_hash: d260d25f0d19e8e diff --git a/src/tests/snapshots/gitu__tests__push__push_menu_no_remote_or_upstream_set.snap b/src/tests/snapshots/gitu__tests__push__push_menu_no_remote_or_upstream_set.snap index 804af857fb..f9c8e16596 100644 --- a/src/tests/snapshots/gitu__tests__push__push_menu_no_remote_or_upstream_set.snap +++ b/src/tests/snapshots/gitu__tests__push__push_menu_no_remote_or_upstream_set.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() u upstream, setting that -F Force (--force) | e to elsewhere -f Force with lease (--force-with-lease) | q/esc Quit/Close -h Disable hooks (--no-verify) | -styles_hash: 116e27f679f6d5ff +styles_hash: 43714840095b2bfd diff --git a/src/tests/snapshots/gitu__tests__push__push_push_remote.snap b/src/tests/snapshots/gitu__tests__push__push_push_remote.snap index 7bcbe60442..84245bca6c 100644 --- a/src/tests/snapshots/gitu__tests__push__push_push_remote.snap +++ b/src/tests/snapshots/gitu__tests__push__push_push_remote.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git push origin refs/heads/main:refs/heads/main | Everything up-to-date | -styles_hash: 6a5623491f4acf92 +styles_hash: 90200a7dd1c6e23a diff --git a/src/tests/snapshots/gitu__tests__push__push_push_remote_prompt.snap b/src/tests/snapshots/gitu__tests__push__push_push_remote_prompt.snap index 3d2c0d2622..89b529cd25 100644 --- a/src/tests/snapshots/gitu__tests__push__push_push_remote_prompt.snap +++ b/src/tests/snapshots/gitu__tests__push__push_push_remote_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Set pushRemote then push: › █ | -styles_hash: 92fb80f8cf77f949 +styles_hash: d828804d73527c4f diff --git a/src/tests/snapshots/gitu__tests__push__push_setup_push_remote.snap b/src/tests/snapshots/gitu__tests__push__push_setup_push_remote.snap index 8999c239cb..78994d4f0a 100644 --- a/src/tests/snapshots/gitu__tests__push__push_setup_push_remote.snap +++ b/src/tests/snapshots/gitu__tests__push__push_setup_push_remote.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() u to origin/main -F Force (--force) | e to elsewhere -f Force with lease (--force-with-lease) | q/esc Quit/Close -h Disable hooks (--no-verify) | -styles_hash: 48bf3603bf81dcbf +styles_hash: 7d2fbf4f1a23e447 diff --git a/src/tests/snapshots/gitu__tests__push__push_setup_upstream.snap b/src/tests/snapshots/gitu__tests__push__push_setup_upstream.snap index f0f52b2954..dbc9543e9c 100644 --- a/src/tests/snapshots/gitu__tests__push__push_setup_upstream.snap +++ b/src/tests/snapshots/gitu__tests__push__push_setup_upstream.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() u to main -F Force (--force) | e to elsewhere -f Force with lease (--force-with-lease) | q/esc Quit/Close -h Disable hooks (--no-verify) | -styles_hash: c595ed9845173179 +styles_hash: d8ef8e3b4e8b12dd diff --git a/src/tests/snapshots/gitu__tests__push__push_setup_upstream_same_as_head.snap b/src/tests/snapshots/gitu__tests__push__push_setup_upstream_same_as_head.snap index 8d6867b8d0..7273e86ec4 100644 --- a/src/tests/snapshots/gitu__tests__push__push_setup_upstream_same_as_head.snap +++ b/src/tests/snapshots/gitu__tests__push__push_setup_upstream_same_as_head.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git branch --set-upstream-to new-branch | warning: not setting branch 'new-branch' as its own upstream | -styles_hash: 9cde3208c7a1e5fe +styles_hash: 2bcaab435dbe1378 diff --git a/src/tests/snapshots/gitu__tests__push__push_upstream.snap b/src/tests/snapshots/gitu__tests__push__push_upstream.snap index 33c19bda59..ea9457da35 100644 --- a/src/tests/snapshots/gitu__tests__push__push_upstream.snap +++ b/src/tests/snapshots/gitu__tests__push__push_upstream.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() $ git push origin refs/heads/main:refs/heads/main | To file:// b66a0bf..e7eb2bd main -> main | -styles_hash: 7c6cd7afeae2ed31 +styles_hash: 86d7176114348d55 diff --git a/src/tests/snapshots/gitu__tests__push__push_upstream_prompt.snap b/src/tests/snapshots/gitu__tests__push__push_upstream_prompt.snap index 2b8b54ad1e..9fc7036b5d 100644 --- a/src/tests/snapshots/gitu__tests__push__push_upstream_prompt.snap +++ b/src/tests/snapshots/gitu__tests__push__push_upstream_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Set upstream then push: › █ | -styles_hash: 192f52eb6bc15ece +styles_hash: ba13237f9bab9178 diff --git a/src/tests/snapshots/gitu__tests__quit__confirm_quit.snap b/src/tests/snapshots/gitu__tests__quit__confirm_quit.snap index ab37e51ce0..fcc8baa002 100644 --- a/src/tests/snapshots/gitu__tests__quit__confirm_quit.snap +++ b/src/tests/snapshots/gitu__tests__quit__confirm_quit.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: f47a6512af0aca26 +styles_hash: 146fca7ccd68cab7 diff --git a/src/tests/snapshots/gitu__tests__quit__confirm_quit_prompt.snap b/src/tests/snapshots/gitu__tests__quit__confirm_quit_prompt.snap index ec48a9c1f5..89c55f46a5 100644 --- a/src/tests/snapshots/gitu__tests__quit__confirm_quit_prompt.snap +++ b/src/tests/snapshots/gitu__tests__quit__confirm_quit_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Really quit? (y or n) › █ | -styles_hash: 635af03980970fcf +styles_hash: 93ed7b333b2ffd22 diff --git a/src/tests/snapshots/gitu__tests__quit__quit.snap b/src/tests/snapshots/gitu__tests__quit__quit.snap index ab37e51ce0..fcc8baa002 100644 --- a/src/tests/snapshots/gitu__tests__quit__quit.snap +++ b/src/tests/snapshots/gitu__tests__quit__quit.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: f47a6512af0aca26 +styles_hash: 146fca7ccd68cab7 diff --git a/src/tests/snapshots/gitu__tests__quit__quit_from_menu.snap b/src/tests/snapshots/gitu__tests__quit__quit_from_menu.snap index ab37e51ce0..fcc8baa002 100644 --- a/src/tests/snapshots/gitu__tests__quit__quit_from_menu.snap +++ b/src/tests/snapshots/gitu__tests__quit__quit_from_menu.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: f47a6512af0aca26 +styles_hash: 146fca7ccd68cab7 diff --git a/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere.snap b/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere.snap index 3f386267b7..c02a8a83c5 100644 --- a/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere.snap +++ b/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git rebase --autostash main | Successfully rebased and updated refs/heads/other-branch. | -styles_hash: e4b2d1eeab466a0a +styles_hash: 20cf77cd40a6d649 diff --git a/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere_prompt.snap b/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere_prompt.snap index d835e436a7..63076aa66e 100644 --- a/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere_prompt.snap +++ b/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 65f4fc0ca3a35c1e +styles_hash: 4791402e3deec007 diff --git a/src/tests/snapshots/gitu__tests__rebase__rebase_menu.snap b/src/tests/snapshots/gitu__tests__rebase__rebase_menu.snap index 3085f793c6..6b0cb122aa 100644 --- a/src/tests/snapshots/gitu__tests__rebase__rebase_menu.snap +++ b/src/tests/snapshots/gitu__tests__rebase__rebase_menu.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 3f2fe756e501a308 +styles_hash: 416c0ac7d3db7f70 diff --git a/src/tests/snapshots/gitu__tests__rebase_conflict.snap b/src/tests/snapshots/gitu__tests__rebase_conflict.snap index 63ae632b76..8373742308 100644 --- a/src/tests/snapshots/gitu__tests__rebase_conflict.snap +++ b/src/tests/snapshots/gitu__tests__rebase_conflict.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: c444654cc76064bb +styles_hash: 5533e392052aceb3 diff --git a/src/tests/snapshots/gitu__tests__recent_commits_with_limit.snap b/src/tests/snapshots/gitu__tests__recent_commits_with_limit.snap index 8b4bf0f4a4..4c577953fb 100644 --- a/src/tests/snapshots/gitu__tests__recent_commits_with_limit.snap +++ b/src/tests/snapshots/gitu__tests__recent_commits_with_limit.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 4ff6b6bda1dfee35 +styles_hash: 571c653ad285c374 diff --git a/src/tests/snapshots/gitu__tests__remote__add_remote.snap b/src/tests/snapshots/gitu__tests__remote__add_remote.snap index 2b6abaf578..da83887f8e 100644 --- a/src/tests/snapshots/gitu__tests__remote__add_remote.snap +++ b/src/tests/snapshots/gitu__tests__remote__add_remote.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git remote add test localhost | -styles_hash: e5be2cc8ca3f42c +styles_hash: 59157445a4a6240a diff --git a/src/tests/snapshots/gitu__tests__remote__add_remote_name_prompt.snap b/src/tests/snapshots/gitu__tests__remote__add_remote_name_prompt.snap index bbab91252c..3c60f5d383 100644 --- a/src/tests/snapshots/gitu__tests__remote__add_remote_name_prompt.snap +++ b/src/tests/snapshots/gitu__tests__remote__add_remote_name_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Remote name: › █ | -styles_hash: 72b62dcf583033f7 +styles_hash: b233f4cd45b013cb diff --git a/src/tests/snapshots/gitu__tests__remote__add_remote_url_prompt.snap b/src/tests/snapshots/gitu__tests__remote__add_remote_url_prompt.snap index 27ef92d280..0d45eb5649 100644 --- a/src/tests/snapshots/gitu__tests__remote__add_remote_url_prompt.snap +++ b/src/tests/snapshots/gitu__tests__remote__add_remote_url_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Remote url: › █ | -styles_hash: 533c0c32916d0d32 +styles_hash: b6ca886ae9935933 diff --git a/src/tests/snapshots/gitu__tests__remote__remote_menu.snap b/src/tests/snapshots/gitu__tests__remote__remote_menu.snap index 2c30382588..d830e823c6 100644 --- a/src/tests/snapshots/gitu__tests__remote__remote_menu.snap +++ b/src/tests/snapshots/gitu__tests__remote__remote_menu.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() K remove remote | r rename remote | q/esc Quit/Close | -styles_hash: f68bba68cc2d8ad6 +styles_hash: bda3f6303d72b6b4 diff --git a/src/tests/snapshots/gitu__tests__remote__remove_remote.snap b/src/tests/snapshots/gitu__tests__remote__remove_remote.snap index 98450544ef..31617d3952 100644 --- a/src/tests/snapshots/gitu__tests__remote__remove_remote.snap +++ b/src/tests/snapshots/gitu__tests__remote__remove_remote.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git remote remove origin | -styles_hash: 292952155cdc697b +styles_hash: 28202c97ccf86688 diff --git a/src/tests/snapshots/gitu__tests__remote__rename_remote.snap b/src/tests/snapshots/gitu__tests__remote__rename_remote.snap index 54a1561187..4ec28206d7 100644 --- a/src/tests/snapshots/gitu__tests__remote__rename_remote.snap +++ b/src/tests/snapshots/gitu__tests__remote__rename_remote.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git remote rename origin origin2 | -styles_hash: a39db450fcdce2da +styles_hash: 1deab4cb8adf653a diff --git a/src/tests/snapshots/gitu__tests__remote__rename_remote_name_prompt.snap b/src/tests/snapshots/gitu__tests__remote__rename_remote_name_prompt.snap index 1c8ffe5a25..13c229253d 100644 --- a/src/tests/snapshots/gitu__tests__remote__rename_remote_name_prompt.snap +++ b/src/tests/snapshots/gitu__tests__remote__rename_remote_name_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Rename remote: › █ | -styles_hash: d4bf27d871c90729 +styles_hash: 27b62992ccb47712 diff --git a/src/tests/snapshots/gitu__tests__remote__rename_remote_new_name_prompt.snap b/src/tests/snapshots/gitu__tests__remote__rename_remote_new_name_prompt.snap index 0f9593b52f..1893f2c9e0 100644 --- a/src/tests/snapshots/gitu__tests__remote__rename_remote_new_name_prompt.snap +++ b/src/tests/snapshots/gitu__tests__remote__rename_remote_new_name_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Rename to: › █ | -styles_hash: e71a307199e38aa3 +styles_hash: 39fd6cbc76086bbb diff --git a/src/tests/snapshots/gitu__tests__reset__reset_hard.snap b/src/tests/snapshots/gitu__tests__reset__reset_hard.snap index 8c9687079b..e72fe663e8 100644 --- a/src/tests/snapshots/gitu__tests__reset__reset_hard.snap +++ b/src/tests/snapshots/gitu__tests__reset__reset_hard.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: f47a6512af0aca26 +styles_hash: 146fca7ccd68cab7 diff --git a/src/tests/snapshots/gitu__tests__reset__reset_menu.snap b/src/tests/snapshots/gitu__tests__reset__reset_menu.snap index cb43969cd9..f91cf4cbb1 100644 --- a/src/tests/snapshots/gitu__tests__reset__reset_menu.snap +++ b/src/tests/snapshots/gitu__tests__reset__reset_menu.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() m mixed | h hard | q/esc Quit/Close | -styles_hash: f5d50e0a53ae7611 +styles_hash: 83a9f669e53d0e1c diff --git a/src/tests/snapshots/gitu__tests__reset__reset_mixed.snap b/src/tests/snapshots/gitu__tests__reset__reset_mixed.snap index a8a44d6470..3fa4fcd976 100644 --- a/src/tests/snapshots/gitu__tests__reset__reset_mixed.snap +++ b/src/tests/snapshots/gitu__tests__reset__reset_mixed.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 4738e02f19882d7d +styles_hash: 8d0a6a68bd80d839 diff --git a/src/tests/snapshots/gitu__tests__reset__reset_soft.snap b/src/tests/snapshots/gitu__tests__reset__reset_soft.snap index ecafabdce9..cfb81e633d 100644 --- a/src/tests/snapshots/gitu__tests__reset__reset_soft.snap +++ b/src/tests/snapshots/gitu__tests__reset__reset_soft.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: fef12cfe8789d4e2 +styles_hash: f5205687ef182b5f diff --git a/src/tests/snapshots/gitu__tests__reset__reset_soft_prompt.snap b/src/tests/snapshots/gitu__tests__reset__reset_soft_prompt.snap index 4b73f9b38a..e2c0e31663 100644 --- a/src/tests/snapshots/gitu__tests__reset__reset_soft_prompt.snap +++ b/src/tests/snapshots/gitu__tests__reset__reset_soft_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Soft reset to (default origin/main): › q█ | -styles_hash: b52d9c7eb5f4d8e3 +styles_hash: a45602c82423cd02 diff --git a/src/tests/snapshots/gitu__tests__reverse__reverse_staged_delta.snap b/src/tests/snapshots/gitu__tests__reverse__reverse_staged_delta.snap index e9ee8c69ab..6d6c878112 100644 --- a/src/tests/snapshots/gitu__tests__reverse__reverse_staged_delta.snap +++ b/src/tests/snapshots/gitu__tests__reverse__reverse_staged_delta.snap @@ -22,7 +22,7 @@ expression: out | ────────────────────────────────────────────────────────────────────────────────| $ git apply --reverse | -styles_hash: c3e27c3c64b57280 +styles_hash: feb0752ac6cf0f53 [file before] blahonga diff --git a/src/tests/snapshots/gitu__tests__reverse__reverse_staged_hunk.snap b/src/tests/snapshots/gitu__tests__reverse__reverse_staged_hunk.snap index 6b41ca2121..3e6f2676b6 100644 --- a/src/tests/snapshots/gitu__tests__reverse__reverse_staged_hunk.snap +++ b/src/tests/snapshots/gitu__tests__reverse__reverse_staged_hunk.snap @@ -22,7 +22,7 @@ expression: out BAZ | ────────────────────────────────────────────────────────────────────────────────| $ git apply --reverse | -styles_hash: a5e24bbded675128 +styles_hash: 647232b99f2807df [file before] blahonga diff --git a/src/tests/snapshots/gitu__tests__reverse__reverse_staged_line.snap b/src/tests/snapshots/gitu__tests__reverse__reverse_staged_line.snap index 02544defa9..7793e07e6d 100644 --- a/src/tests/snapshots/gitu__tests__reverse__reverse_staged_line.snap +++ b/src/tests/snapshots/gitu__tests__reverse__reverse_staged_line.snap @@ -22,7 +22,7 @@ expression: out BAZ | ────────────────────────────────────────────────────────────────────────────────| $ git apply --reverse --recount | -styles_hash: d8e20f905aae1d59 +styles_hash: 773df6bbbcd5f5ab [file before] blahonga diff --git a/src/tests/snapshots/gitu__tests__reverse__reverse_unstaged_delta.snap b/src/tests/snapshots/gitu__tests__reverse__reverse_unstaged_delta.snap index 5b2d5eca6c..aa11de333d 100644 --- a/src/tests/snapshots/gitu__tests__reverse__reverse_unstaged_delta.snap +++ b/src/tests/snapshots/gitu__tests__reverse__reverse_unstaged_delta.snap @@ -22,7 +22,7 @@ expression: out | ────────────────────────────────────────────────────────────────────────────────| $ git apply --reverse | -styles_hash: 127ac9ef0aee93e +styles_hash: e2df43c3a6393f68 [file before] blahonga diff --git a/src/tests/snapshots/gitu__tests__reverse__reverse_unstaged_hunk.snap b/src/tests/snapshots/gitu__tests__reverse__reverse_unstaged_hunk.snap index c8dece537d..b157ef4365 100644 --- a/src/tests/snapshots/gitu__tests__reverse__reverse_unstaged_hunk.snap +++ b/src/tests/snapshots/gitu__tests__reverse__reverse_unstaged_hunk.snap @@ -22,7 +22,7 @@ expression: out | ────────────────────────────────────────────────────────────────────────────────| $ git apply --reverse | -styles_hash: 80fde90219deddc2 +styles_hash: 96d36739f332031 [file before] blahonga diff --git a/src/tests/snapshots/gitu__tests__reverse__reverse_unstaged_line.snap b/src/tests/snapshots/gitu__tests__reverse__reverse_unstaged_line.snap index a074a58e27..c4f09c7598 100644 --- a/src/tests/snapshots/gitu__tests__reverse__reverse_unstaged_line.snap +++ b/src/tests/snapshots/gitu__tests__reverse__reverse_unstaged_line.snap @@ -22,7 +22,7 @@ expression: out | ────────────────────────────────────────────────────────────────────────────────| $ git apply --reverse --recount | -styles_hash: 8f5ab6e7fae3f786 +styles_hash: d8eeebb35b94d8e3 [file before] blahonga diff --git a/src/tests/snapshots/gitu__tests__revert_abort.snap b/src/tests/snapshots/gitu__tests__revert_abort.snap index 57fc9a5110..5a63de37d6 100644 --- a/src/tests/snapshots/gitu__tests__revert_abort.snap +++ b/src/tests/snapshots/gitu__tests__revert_abort.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git revert --abort | -styles_hash: 8d5b31c704dbb728 +styles_hash: 487a1d3b5b030afc diff --git a/src/tests/snapshots/gitu__tests__revert_commit.snap b/src/tests/snapshots/gitu__tests__revert_commit.snap index 1b28db109e..f4d05d4e30 100644 --- a/src/tests/snapshots/gitu__tests__revert_commit.snap +++ b/src/tests/snapshots/gitu__tests__revert_commit.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git revert --edit --no-edit main | -styles_hash: f99dcd1f9c3167f6 +styles_hash: ba25c067bfa23389 diff --git a/src/tests/snapshots/gitu__tests__revert_commit_prompt.snap b/src/tests/snapshots/gitu__tests__revert_commit_prompt.snap index 894fc91b5d..4921f21062 100644 --- a/src/tests/snapshots/gitu__tests__revert_commit_prompt.snap +++ b/src/tests/snapshots/gitu__tests__revert_commit_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Revert commit (default main): › █ | -styles_hash: 9f368d3eb37a4f1f +styles_hash: 9a9a7b67c0681857 diff --git a/src/tests/snapshots/gitu__tests__revert_conflict.snap b/src/tests/snapshots/gitu__tests__revert_conflict.snap index 119b9cba60..7114445165 100644 --- a/src/tests/snapshots/gitu__tests__revert_conflict.snap +++ b/src/tests/snapshots/gitu__tests__revert_conflict.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: ce1bcac7e4255e31 +styles_hash: 468505792b7ec211 diff --git a/src/tests/snapshots/gitu__tests__revert_menu.snap b/src/tests/snapshots/gitu__tests__revert_menu.snap index 60a36e955c..d291bf9031 100644 --- a/src/tests/snapshots/gitu__tests__revert_menu.snap +++ b/src/tests/snapshots/gitu__tests__revert_menu.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() c Continue -E Don't edit commit message (--no-edit) | V Revert commit(s) -s Add Signed-off-by lines (--signoff) | q/esc Quit/Close | -styles_hash: 64dda6a1259ae722 +styles_hash: 7112c073199b1f56 diff --git a/src/tests/snapshots/gitu__tests__show.snap b/src/tests/snapshots/gitu__tests__show.snap index 5d12863fc6..6c2667a64a 100644 --- a/src/tests/snapshots/gitu__tests__show.snap +++ b/src/tests/snapshots/gitu__tests__show.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: cbb15275b9e6a12b +styles_hash: a007f92b812f3b2c diff --git a/src/tests/snapshots/gitu__tests__show_refs__show_refs_at_local_branch.snap b/src/tests/snapshots/gitu__tests__show_refs__show_refs_at_local_branch.snap index de75ad4b41..748fdfd3ea 100644 --- a/src/tests/snapshots/gitu__tests__show_refs__show_refs_at_local_branch.snap +++ b/src/tests/snapshots/gitu__tests__show_refs__show_refs_at_local_branch.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 6814955082265cab +styles_hash: 2ce33495ebdcc656 diff --git a/src/tests/snapshots/gitu__tests__show_refs__show_refs_at_remote_branch.snap b/src/tests/snapshots/gitu__tests__show_refs__show_refs_at_remote_branch.snap index 225fa1db19..7a210ed326 100644 --- a/src/tests/snapshots/gitu__tests__show_refs__show_refs_at_remote_branch.snap +++ b/src/tests/snapshots/gitu__tests__show_refs__show_refs_at_remote_branch.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: c34389d771bd369f +styles_hash: 23e139cddc801205 diff --git a/src/tests/snapshots/gitu__tests__show_refs__show_refs_at_tag.snap b/src/tests/snapshots/gitu__tests__show_refs__show_refs_at_tag.snap index b4c796eb25..cb7496b4bc 100644 --- a/src/tests/snapshots/gitu__tests__show_refs__show_refs_at_tag.snap +++ b/src/tests/snapshots/gitu__tests__show_refs__show_refs_at_tag.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 6814955082265cab +styles_hash: 2ce33495ebdcc656 diff --git a/src/tests/snapshots/gitu__tests__show_stash.snap b/src/tests/snapshots/gitu__tests__show_stash.snap index 34fa8982c7..07fb67d40f 100644 --- a/src/tests/snapshots/gitu__tests__show_stash.snap +++ b/src/tests/snapshots/gitu__tests__show_stash.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() added untracked.txt | @@ -0,0 +1 @@ | +untracked | -styles_hash: 657c8e06e0c26076 +styles_hash: 836321733f1b4060 diff --git a/src/tests/snapshots/gitu__tests__stage__stage_added_line.snap b/src/tests/snapshots/gitu__tests__stage__stage_added_line.snap index 6e2538cd0a..a117b06048 100644 --- a/src/tests/snapshots/gitu__tests__stage__stage_added_line.snap +++ b/src/tests/snapshots/gitu__tests__stage__stage_added_line.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git apply --cached --recount | -styles_hash: dcae7b3f38b26bac +styles_hash: ab9fd97bf343786b diff --git a/src/tests/snapshots/gitu__tests__stage__stage_all_unstaged.snap b/src/tests/snapshots/gitu__tests__stage__stage_all_unstaged.snap index 9109d8eba0..9fe18e7f4c 100644 --- a/src/tests/snapshots/gitu__tests__stage__stage_all_unstaged.snap +++ b/src/tests/snapshots/gitu__tests__stage__stage_all_unstaged.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git add -u . | -styles_hash: a063500e9afe37d6 +styles_hash: 3df0aa726902e9ad diff --git a/src/tests/snapshots/gitu__tests__stage__stage_all_untracked.snap b/src/tests/snapshots/gitu__tests__stage__stage_all_untracked.snap index 7f76cf0f52..2d8dd4c7d2 100644 --- a/src/tests/snapshots/gitu__tests__stage__stage_all_untracked.snap +++ b/src/tests/snapshots/gitu__tests__stage__stage_all_untracked.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git add file-a file-b | -styles_hash: 93f1d2dc4e2c68b6 +styles_hash: 3a1c73d40e0d57d0 diff --git a/src/tests/snapshots/gitu__tests__stage__stage_changes_crlf.snap b/src/tests/snapshots/gitu__tests__stage__stage_changes_crlf.snap index b61b5c0078..6ca9ecd181 100644 --- a/src/tests/snapshots/gitu__tests__stage__stage_changes_crlf.snap +++ b/src/tests/snapshots/gitu__tests__stage__stage_changes_crlf.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 6e23db6ecca0d933 +styles_hash: ce9d7828718125e1 diff --git a/src/tests/snapshots/gitu__tests__stage__stage_deleted_executable_file.snap b/src/tests/snapshots/gitu__tests__stage__stage_deleted_executable_file.snap index dbc274feb7..8469dba813 100644 --- a/src/tests/snapshots/gitu__tests__stage__stage_deleted_executable_file.snap +++ b/src/tests/snapshots/gitu__tests__stage__stage_deleted_executable_file.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git add script.sh | -styles_hash: 904386f2bd8f8286 +styles_hash: 1873a4f8ed35670a diff --git a/src/tests/snapshots/gitu__tests__stage__stage_deleted_file.snap b/src/tests/snapshots/gitu__tests__stage__stage_deleted_file.snap index 22101f2618..5fbff9d96b 100644 --- a/src/tests/snapshots/gitu__tests__stage__stage_deleted_file.snap +++ b/src/tests/snapshots/gitu__tests__stage__stage_deleted_file.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git add to-delete | -styles_hash: 86c2e1d85f798b75 +styles_hash: cf57a6fd17d99b12 diff --git a/src/tests/snapshots/gitu__tests__stage__stage_file_with_spaces_in_name.snap b/src/tests/snapshots/gitu__tests__stage__stage_file_with_spaces_in_name.snap index 8670094c03..572d386706 100644 --- a/src/tests/snapshots/gitu__tests__stage__stage_file_with_spaces_in_name.snap +++ b/src/tests/snapshots/gitu__tests__stage__stage_file_with_spaces_in_name.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git add file with space.txt | -styles_hash: 5372e7d632c4cf90 +styles_hash: b5589f2e5b138e2b diff --git a/src/tests/snapshots/gitu__tests__stage__stage_removed_line.snap b/src/tests/snapshots/gitu__tests__stage__stage_removed_line.snap index f7f3948199..93961b3145 100644 --- a/src/tests/snapshots/gitu__tests__stage__stage_removed_line.snap +++ b/src/tests/snapshots/gitu__tests__stage__stage_removed_line.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() 223428c main add firstfile | ────────────────────────────────────────────────────────────────────────────────| $ git apply --cached --recount | -styles_hash: 3d0b28ed50247a08 +styles_hash: 8f07bb5498255060 diff --git a/src/tests/snapshots/gitu__tests__stage__staged_file.snap b/src/tests/snapshots/gitu__tests__stage__staged_file.snap index bfdc7b1d3a..706b22bd82 100644 --- a/src/tests/snapshots/gitu__tests__stage__staged_file.snap +++ b/src/tests/snapshots/gitu__tests__stage__staged_file.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: e95ba86e6653e5f8 +styles_hash: e4bf0a553da4097a diff --git a/src/tests/snapshots/gitu__tests__stage_last_hunk_of_first_delta.snap b/src/tests/snapshots/gitu__tests__stage_last_hunk_of_first_delta.snap index 09eb8ba383..34dc622283 100644 --- a/src/tests/snapshots/gitu__tests__stage_last_hunk_of_first_delta.snap +++ b/src/tests/snapshots/gitu__tests__stage_last_hunk_of_first_delta.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git apply --cached | -styles_hash: 188769995793700 +styles_hash: 7b6225633ca64544 diff --git a/src/tests/snapshots/gitu__tests__stash__stash.snap b/src/tests/snapshots/gitu__tests__stash__stash.snap index 1afdc768ff..cf036a9e6f 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git stash push --include-untracked --message test | Saved working directory and index state On main: test | -styles_hash: 5ce63d321da655e4 +styles_hash: 38fa64e4b2914d7a diff --git a/src/tests/snapshots/gitu__tests__stash__stash_apply.snap b/src/tests/snapshots/gitu__tests__stash__stash_apply.snap index 11cc5982a6..61c87006f1 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_apply.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_apply.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git stash apply -q 1 | -styles_hash: 6ff816bedee07b43 +styles_hash: 200cabb23831b52c diff --git a/src/tests/snapshots/gitu__tests__stash__stash_apply_default.snap b/src/tests/snapshots/gitu__tests__stash__stash_apply_default.snap index 775c88d107..3212b56f91 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_apply_default.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_apply_default.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git stash apply -q 0 | Already up to date. | -styles_hash: 9d03a36fae8a1392 +styles_hash: fe20d9472776be1c diff --git a/src/tests/snapshots/gitu__tests__stash__stash_apply_file_as_patch.snap b/src/tests/snapshots/gitu__tests__stash__stash_apply_file_as_patch.snap index e5182cf0bb..8a3979eb38 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_apply_file_as_patch.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_apply_file_as_patch.snap @@ -22,7 +22,7 @@ expression: out ▌ seven | ────────────────────────────────────────────────────────────────────────────────| $ git apply | -styles_hash: 92b47e5045c3f2a +styles_hash: f6bd41566dbaa80c [files before] --- file1.txt --- diff --git a/src/tests/snapshots/gitu__tests__stash__stash_apply_hunk_as_patch.snap b/src/tests/snapshots/gitu__tests__stash__stash_apply_hunk_as_patch.snap index 7a66471ea4..eebef67f3d 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_apply_hunk_as_patch.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_apply_hunk_as_patch.snap @@ -22,7 +22,7 @@ expression: out seven | ────────────────────────────────────────────────────────────────────────────────| $ git apply | -styles_hash: 2a88314975ff98fc +styles_hash: fa66b8d655c43403 [files before] --- file1.txt --- diff --git a/src/tests/snapshots/gitu__tests__stash__stash_apply_line_as_patch.snap b/src/tests/snapshots/gitu__tests__stash__stash_apply_line_as_patch.snap index 7f488031f3..78578eccd1 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_apply_line_as_patch.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_apply_line_as_patch.snap @@ -22,7 +22,7 @@ expression: out seven | ────────────────────────────────────────────────────────────────────────────────| $ git apply --recount | -styles_hash: 6bd2811f25dca59d +styles_hash: 404713b599d6187d [files before] --- file1.txt --- diff --git a/src/tests/snapshots/gitu__tests__stash__stash_apply_prompt.snap b/src/tests/snapshots/gitu__tests__stash__stash_apply_prompt.snap index 24113bac7b..e647be4a38 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_apply_prompt.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_apply_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Apply stash (default 0): › █ | -styles_hash: 216e8fc2f72a82c7 +styles_hash: 57707ad00ed829a4 diff --git a/src/tests/snapshots/gitu__tests__stash__stash_apply_selected.snap b/src/tests/snapshots/gitu__tests__stash__stash_apply_selected.snap index e4d1104fd8..b3d9c3c05d 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_apply_selected.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_apply_selected.snap @@ -22,7 +22,7 @@ expression: out ▌-ten | ────────────────────────────────────────────────────────────────────────────────| $ git stash apply -q stash@{0} | -styles_hash: ac8c9cc328d84585 +styles_hash: 43893a5c0c24829d [files before] --- file1.txt --- diff --git a/src/tests/snapshots/gitu__tests__stash__stash_drop.snap b/src/tests/snapshots/gitu__tests__stash__stash_drop.snap index c5353e428a..adbd717a5b 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_drop.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_drop.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git stash drop 1 | Dropped refs/stash@{1} (6e4ee08a012b0675b1f27465f158930aa1088b7a) | -styles_hash: 94c54afa40f5600a +styles_hash: b1759c31e1cf2e64 diff --git a/src/tests/snapshots/gitu__tests__stash__stash_drop_default.snap b/src/tests/snapshots/gitu__tests__stash__stash_drop_default.snap index 271d4cdf29..d71597253f 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_drop_default.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_drop_default.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git stash drop 0 | Dropped refs/stash@{0} (866ae6e6fb018bbc32c37e658e097d95dceee8c0) | -styles_hash: 94c54afa40f5600a +styles_hash: b1759c31e1cf2e64 diff --git a/src/tests/snapshots/gitu__tests__stash__stash_drop_prompt.snap b/src/tests/snapshots/gitu__tests__stash__stash_drop_prompt.snap index 31ef177bff..600a3a44a2 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_drop_prompt.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_drop_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Drop stash (default 0): › █ | -styles_hash: 6610d51b9ce82971 +styles_hash: 80440fb30c8c16c3 diff --git a/src/tests/snapshots/gitu__tests__stash__stash_index.snap b/src/tests/snapshots/gitu__tests__stash__stash_index.snap index 8409d1ef25..44c4581ee9 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_index.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_index.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git stash push --staged --message test | Saved working directory and index state On main: test | -styles_hash: 5fee4e9a17e73edf +styles_hash: 9f6c6a25872375b3 diff --git a/src/tests/snapshots/gitu__tests__stash__stash_index_prompt.snap b/src/tests/snapshots/gitu__tests__stash__stash_index_prompt.snap index 275932697b..79d83f7260 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_index_prompt.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_index_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Stash message: › █ | -styles_hash: 84962ae13e37fe04 +styles_hash: cf71f21e02e3f49d diff --git a/src/tests/snapshots/gitu__tests__stash__stash_keeping_index.snap b/src/tests/snapshots/gitu__tests__stash__stash_keeping_index.snap index 443fa518c1..a3403c58e0 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_keeping_index.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_keeping_index.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git stash push --keep-index --include-untracked --message test | Saved working directory and index state On main: test | -styles_hash: 306a2e516da70fe5 +styles_hash: 62b29f66c7e857c7 diff --git a/src/tests/snapshots/gitu__tests__stash__stash_keeping_index_prompt.snap b/src/tests/snapshots/gitu__tests__stash__stash_keeping_index_prompt.snap index 275932697b..79d83f7260 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_keeping_index_prompt.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_keeping_index_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Stash message: › █ | -styles_hash: 84962ae13e37fe04 +styles_hash: cf71f21e02e3f49d diff --git a/src/tests/snapshots/gitu__tests__stash__stash_menu.snap b/src/tests/snapshots/gitu__tests__stash__stash_menu.snap index 87c7961c50..93c0e9ca66 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_menu.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_menu.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() p pop | k drop | q/esc Quit/Close | -styles_hash: 4b344b24bf22a0ea +styles_hash: 2d1df45600e515ea diff --git a/src/tests/snapshots/gitu__tests__stash__stash_pop.snap b/src/tests/snapshots/gitu__tests__stash__stash_pop.snap index 84348b4b60..955342ecf7 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_pop.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_pop.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git stash pop -q 1 | -styles_hash: 2fddcabe20afecfe +styles_hash: 4e1df32c020cfc7 diff --git a/src/tests/snapshots/gitu__tests__stash__stash_pop_default.snap b/src/tests/snapshots/gitu__tests__stash__stash_pop_default.snap index 24b0094b38..5d4fb19c37 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_pop_default.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_pop_default.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git stash pop -q 0 | Already up to date. | -styles_hash: d0f94aafefcbeb56 +styles_hash: dc0dbeaba237d74a diff --git a/src/tests/snapshots/gitu__tests__stash__stash_pop_prompt.snap b/src/tests/snapshots/gitu__tests__stash__stash_pop_prompt.snap index 60bbdac495..15f0159dc1 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_pop_prompt.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_pop_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Pop stash (default 0): › █ | -styles_hash: f9d1a1a4d6ebc785 +styles_hash: d4ee762d695afc2 diff --git a/src/tests/snapshots/gitu__tests__stash__stash_prompt.snap b/src/tests/snapshots/gitu__tests__stash__stash_prompt.snap index 275932697b..79d83f7260 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_prompt.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Stash message: › █ | -styles_hash: 84962ae13e37fe04 +styles_hash: cf71f21e02e3f49d diff --git a/src/tests/snapshots/gitu__tests__stash__stash_working_tree.snap b/src/tests/snapshots/gitu__tests__stash__stash_working_tree.snap index 1f5219c370..9aa2e3673c 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_working_tree.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_working_tree.snap @@ -22,4 +22,4 @@ Saved working directory and index state WIP on main: b66a0bf add initial-file $ git stash push --include-untracked --message test | Saved working directory and index state On main: test | $ git stash pop -q 1 | -styles_hash: e26b4618f23a734 +styles_hash: 68515006e12f2317 diff --git a/src/tests/snapshots/gitu__tests__stash__stash_working_tree_prompt.snap b/src/tests/snapshots/gitu__tests__stash__stash_working_tree_prompt.snap index 275932697b..79d83f7260 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_working_tree_prompt.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_working_tree_prompt.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ? Stash message: › █ | -styles_hash: 84962ae13e37fe04 +styles_hash: cf71f21e02e3f49d diff --git a/src/tests/snapshots/gitu__tests__stash__stash_working_tree_when_everything_is_staged.snap b/src/tests/snapshots/gitu__tests__stash__stash_working_tree_when_everything_is_staged.snap index 0a884ba3f1..07591ba33c 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_working_tree_when_everything_is_staged.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_working_tree_when_everything_is_staged.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ! Cannot stash: working tree is empty | -styles_hash: 540759bc87855080 +styles_hash: afd809f8df8f4679 diff --git a/src/tests/snapshots/gitu__tests__stash__stash_working_tree_when_nothing_is_staged.snap b/src/tests/snapshots/gitu__tests__stash__stash_working_tree_when_nothing_is_staged.snap index 1afdc768ff..cf036a9e6f 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_working_tree_when_nothing_is_staged.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_working_tree_when_nothing_is_staged.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git stash push --include-untracked --message test | Saved working directory and index state On main: test | -styles_hash: 5ce63d321da655e4 +styles_hash: 38fa64e4b2914d7a diff --git a/src/tests/snapshots/gitu__tests__stash_list_with_limit.snap b/src/tests/snapshots/gitu__tests__stash_list_with_limit.snap index f39470ea1b..2dc8f42d18 100644 --- a/src/tests/snapshots/gitu__tests__stash_list_with_limit.snap +++ b/src/tests/snapshots/gitu__tests__stash_list_with_limit.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: d4182dc7cc4ac7f6 +styles_hash: e6394d1f97d1c740 diff --git a/src/tests/snapshots/gitu__tests__syntax_highlighted.snap b/src/tests/snapshots/gitu__tests__syntax_highlighted.snap index c6cb40f78a..ae3c1ff413 100644 --- a/src/tests/snapshots/gitu__tests__syntax_highlighted.snap +++ b/src/tests/snapshots/gitu__tests__syntax_highlighted.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 1b0c71337d9d805a +styles_hash: 6cb9c3325337796e diff --git a/src/tests/snapshots/gitu__tests__tab_diff.snap b/src/tests/snapshots/gitu__tests__tab_diff.snap index c6ae6c2b13..bc161454c3 100644 --- a/src/tests/snapshots/gitu__tests__tab_diff.snap +++ b/src/tests/snapshots/gitu__tests__tab_diff.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 4db1a6e61728c6f7 +styles_hash: 8e07e0435805fafd diff --git a/src/tests/snapshots/gitu__tests__unstage__unstage_added_file_with_spaces_in_name.snap b/src/tests/snapshots/gitu__tests__unstage__unstage_added_file_with_spaces_in_name.snap index 1d71d41f51..ad48e0eec6 100644 --- a/src/tests/snapshots/gitu__tests__unstage__unstage_added_file_with_spaces_in_name.snap +++ b/src/tests/snapshots/gitu__tests__unstage__unstage_added_file_with_spaces_in_name.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git restore --staged file with space.txt | -styles_hash: 4d31ee8109cfa98e +styles_hash: 2ccf6c2919834e diff --git a/src/tests/snapshots/gitu__tests__unstage__unstage_added_line.snap b/src/tests/snapshots/gitu__tests__unstage__unstage_added_line.snap index 3bbb180a59..2c9865b29d 100644 --- a/src/tests/snapshots/gitu__tests__unstage__unstage_added_line.snap +++ b/src/tests/snapshots/gitu__tests__unstage__unstage_added_line.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() 223428c main add firstfile | ────────────────────────────────────────────────────────────────────────────────| $ git apply --cached --reverse --recount | -styles_hash: 61980d64f9b4d1c2 +styles_hash: 94c81e31c9f7cd7c diff --git a/src/tests/snapshots/gitu__tests__unstage__unstage_all_staged.snap b/src/tests/snapshots/gitu__tests__unstage__unstage_all_staged.snap index 0fc77c1022..23b81ba50c 100644 --- a/src/tests/snapshots/gitu__tests__unstage__unstage_all_staged.snap +++ b/src/tests/snapshots/gitu__tests__unstage__unstage_all_staged.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git reset HEAD -- | -styles_hash: 9c970ab3eaa19c0b +styles_hash: 828d215dcad428cf diff --git a/src/tests/snapshots/gitu__tests__unstage__unstage_deleted_executable_file.snap b/src/tests/snapshots/gitu__tests__unstage__unstage_deleted_executable_file.snap index 59e7f53f6c..98d6987e4b 100644 --- a/src/tests/snapshots/gitu__tests__unstage__unstage_deleted_executable_file.snap +++ b/src/tests/snapshots/gitu__tests__unstage__unstage_deleted_executable_file.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git restore --staged script.sh | -styles_hash: b62fb270c2647e0a +styles_hash: 6c24691ba5576b20 diff --git a/src/tests/snapshots/gitu__tests__unstage__unstage_deleted_file.snap b/src/tests/snapshots/gitu__tests__unstage__unstage_deleted_file.snap index 271260f54f..cfce13dfa1 100644 --- a/src/tests/snapshots/gitu__tests__unstage__unstage_deleted_file.snap +++ b/src/tests/snapshots/gitu__tests__unstage__unstage_deleted_file.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git restore --staged to-delete | -styles_hash: c5bc1d29471d4f7b +styles_hash: f7c0e5a57ae9043f diff --git a/src/tests/snapshots/gitu__tests__unstage__unstage_removed_line.snap b/src/tests/snapshots/gitu__tests__unstage__unstage_removed_line.snap index c7f2f686ad..7d8e3cabc4 100644 --- a/src/tests/snapshots/gitu__tests__unstage__unstage_removed_line.snap +++ b/src/tests/snapshots/gitu__tests__unstage__unstage_removed_line.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git apply --cached --reverse --recount | -styles_hash: de7ca4b1de620dcc +styles_hash: cc22c3496d9b7af1 diff --git a/src/tests/snapshots/gitu__tests__unstaged_changes.snap b/src/tests/snapshots/gitu__tests__unstaged_changes.snap index 82e45f8fb6..b5be38b57e 100644 --- a/src/tests/snapshots/gitu__tests__unstaged_changes.snap +++ b/src/tests/snapshots/gitu__tests__unstaged_changes.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 6e23db6ecca0d933 +styles_hash: ce9d7828718125e1 diff --git a/src/tests/snapshots/gitu__tests__updated_externally.snap b/src/tests/snapshots/gitu__tests__updated_externally.snap index 7a9179b46a..d5dd23db0f 100644 --- a/src/tests/snapshots/gitu__tests__updated_externally.snap +++ b/src/tests/snapshots/gitu__tests__updated_externally.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: d61e94830ad618a5 +styles_hash: 44acd39fd75ac09a diff --git a/src/ui.rs b/src/ui.rs index aca4ddd9cc..b4f9f3ca28 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -4,12 +4,12 @@ use crate::Res; use crate::app::State; use crate::error::Error; use crate::screen; +use crate::style::Style; use crate::term::TermBackend; use crate::ui::layout::LayoutItem; use itertools::Itertools; use layout::LayoutTree; use layout::OPTS; -use ratatui::style::Style; use tui_prompts::State as _; use unicode_segmentation::UnicodeSegmentation; use unicode_width::UnicodeWidthStr; @@ -89,7 +89,7 @@ fn layout_prompt<'a>(layout: &mut UiTree<'a>, state: &'a State, width: usize) { repeat_chars(layout, width, DASHES, separator_style); layout.horizontal(None, OPTS, |layout| { - layout_span(layout, (prompt_symbol.content, prompt_symbol.style)); + layout_span(layout, (prompt_symbol.content, prompt_symbol.style.into())); layout_span(layout, (" ".into(), Style::new())); layout_span( layout, diff --git a/src/ui/cmd_log.rs b/src/ui/cmd_log.rs index bc8cc48b0a..ca29b4ee04 100644 --- a/src/ui/cmd_log.rs +++ b/src/ui/cmd_log.rs @@ -1,6 +1,6 @@ use std::sync::{Arc, RwLock}; -use ratatui::style::Style; +use crate::style::Style; use crate::cmd_log::{CmdLog, CmdLogEntry}; use crate::config::Config; diff --git a/src/ui/item.rs b/src/ui/item.rs index 71951427dc..19ce528322 100644 --- a/src/ui/item.rs +++ b/src/ui/item.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use ratatui::style::Style; +use crate::style::Style; use crate::config::Config; use crate::gitu_diff::Status; diff --git a/src/ui/menu.rs b/src/ui/menu.rs index 53845966c9..24deb527f5 100644 --- a/src/ui/menu.rs +++ b/src/ui/menu.rs @@ -1,12 +1,12 @@ use std::borrow::Cow; use crate::menu::arg::Arg; +use crate::style::Style; use crate::ui::item::layout_item; use crate::ui::layout::OPTS; use crate::ui::{self, UiTree, layout_line, layout_span, repeat_chars}; use crate::{app::State, config::Config, ops::Op}; use itertools::Itertools; -use ratatui::style::Style; use unicode_width::UnicodeWidthStr; /// The value column of a keybind table row. diff --git a/src/ui/picker.rs b/src/ui/picker.rs index f7618c0a93..3b91ea993e 100644 --- a/src/ui/picker.rs +++ b/src/ui/picker.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use ratatui::style::Style; +use crate::style::Style; use tui_prompts::State as _; use unicode_segmentation::UnicodeSegmentation; From bd42da9470fd4a7f7bde65072e53a64aea33de4d Mon Sep 17 00:00:00 2001 From: altsem Date: Sun, 26 Jul 2026 18:16:48 +0200 Subject: [PATCH 09/11] refactor: replace tui-prompts and remove ratatui dependency --- Cargo.lock | 135 +---------------------------- Cargo.toml | 4 +- src/app.rs | 12 +-- src/lib.rs | 1 + src/picker.rs | 9 +- src/prompt.rs | 10 +-- src/style.rs | 40 --------- src/text_input.rs | 215 ++++++++++++++++++++++++++++++++++++++++++++++ src/ui.rs | 47 ++++++++-- src/ui/picker.rs | 9 +- 10 files changed, 279 insertions(+), 203 deletions(-) create mode 100644 src/text_input.rs diff --git a/Cargo.lock b/Cargo.lock index 46a6630a69..5476fbf77b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -192,27 +192,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" -[[package]] -name = "cassowary" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" - [[package]] name = "cast" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" -[[package]] -name = "castaway" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" -dependencies = [ - "rustversion", -] - [[package]] name = "cc" version = "1.2.49" @@ -326,20 +311,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" -[[package]] -name = "compact_str" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" -dependencies = [ - "castaway", - "cfg-if", - "itoa", - "rustversion", - "ryu", - "static_assertions", -] - [[package]] name = "console" version = "0.15.11" @@ -696,7 +667,6 @@ dependencies = [ "nom", "notify", "pretty_assertions", - "ratatui", "regex", "serde", "simple-logging", @@ -729,9 +699,8 @@ dependencies = [ "tree-sitter-scala", "tree-sitter-toml-ng", "tree-sitter-typescript", - "tui-prompts", "unicode-segmentation", - "unicode-width 0.2.0", + "unicode-width", "url", ] @@ -921,15 +890,6 @@ dependencies = [ "hashbrown 0.16.1", ] -[[package]] -name = "indoc" -version = "2.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" -dependencies = [ - "rustversion", -] - [[package]] name = "inotify" version = "0.11.0" @@ -962,19 +922,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "instability" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6778b0196eefee7df739db78758e5cf9b37412268bfa5650bfeed028aed20d9c" -dependencies = [ - "darling", - "indoc", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -1114,15 +1061,6 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" -[[package]] -name = "lru" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" -dependencies = [ - "hashbrown 0.15.5", -] - [[package]] name = "memchr" version = "2.7.6" @@ -1307,12 +1245,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "percent-encoding" version = "2.3.2" @@ -1396,36 +1328,6 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" -[[package]] -name = "ratatui" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" -dependencies = [ - "bitflags 2.10.0", - "cassowary", - "compact_str", - "crossterm", - "indoc", - "instability", - "itertools 0.13.0", - "lru", - "paste", - "strum", - "unicode-segmentation", - "unicode-truncate", - "unicode-width 0.2.0", -] - -[[package]] -name = "ratatui-macros" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fef540f80dbe8a0773266fa6077788ceb65ef624cdbf36e131aaf90b4a52df4" -dependencies = [ - "ratatui", -] - [[package]] name = "rayon" version = "1.11.0" @@ -1667,12 +1569,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "stdext" version = "0.3.3" @@ -2101,18 +1997,6 @@ dependencies = [ "tree-sitter-language", ] -[[package]] -name = "tui-prompts" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2004019f7ce0b07e0760c02faadc0b31f0a5d68ce9bbf68c05cad1015b039a01" -dependencies = [ - "itertools 0.14.0", - "ratatui", - "ratatui-macros", - "unicode-width 0.2.0", -] - [[package]] name = "uncased" version = "0.9.10" @@ -2134,23 +2018,6 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" -[[package]] -name = "unicode-truncate" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" -dependencies = [ - "itertools 0.13.0", - "unicode-segmentation", - "unicode-width 0.1.14", -] - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - [[package]] name = "unicode-width" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 1e47bfb3bb..c361928a52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,10 +46,8 @@ log = "0.4.28" nom = "8.0.0" notify = "8.0.0" serde = { version = "1.0.225", features = ["derive"] } -ratatui = "0.29.0" simple-logging = "2.0.2" toml = "0.8.23" -tui-prompts = "0.5.2" tree-sitter = "=0.25.6" tree-sitter-highlight = "=0.25.6" tree-sitter-rust = "=0.24.0" @@ -75,7 +73,7 @@ regex = "1.12.2" strip-ansi-escapes = "0.2.1" unicode-segmentation = "1.12.0" cached = "0.56.0" -strum = { version = "0.26.3", features = ["strum_macros"] } +strum = { version = "0.26.3", features = ["derive"] } tinyvec = "1.10.0" smashquote = "0.1.2" imara-diff = { version = "0.2.0", default-features = false } diff --git a/src/app.rs b/src/app.rs index 395d32faca..c05a0cbb18 100644 --- a/src/app.rs +++ b/src/app.rs @@ -19,7 +19,6 @@ use crossterm::event::MouseButton; use crossterm::event::MouseEvent; use crossterm::event::MouseEventKind; use git2::Repository; -use tui_prompts::State as _; use crate::cli; use crate::cmd_log::CmdLog; @@ -37,6 +36,7 @@ use crate::prompt; use crate::screen; use crate::screen::Screen; use crate::term::Term; +use crate::text_input; use crate::ui; use super::Res; @@ -234,7 +234,7 @@ impl App { if self.state.picker.is_some() { self.handle_picker_input(key); - } else if self.state.prompt.state.is_focused() { + } else if self.state.prompt.state.focused { self.state.prompt.state.handle_key_event(key); } else { self.handle_key_input(term, key)?; @@ -586,9 +586,9 @@ impl App { let event = term.read_event()?; self.handle_event(term, event)?; - if self.state.prompt.state.status().is_done() { + if self.state.prompt.state.status == text_input::Status::Done { return get_prompt_result(params, self); - } else if self.state.prompt.state.status().is_aborted() { + } else if self.state.prompt.state.status == text_input::Status::Aborted { return Err(Error::PromptAborted); } @@ -616,7 +616,7 @@ impl App { let event = term.read_event()?; self.handle_event(term, event)?; - match self.state.prompt.state.value() { + match self.state.prompt.state.value.as_str() { "y" => { return Ok(()); } @@ -716,7 +716,7 @@ impl App { } fn get_prompt_result(params: &PromptParams, app: &mut App) -> Res { - let input = app.state.prompt.state.value(); + let input = app.state.prompt.state.value.as_str(); let default_value = (params.create_default_value)(app); let value = match (input, &default_value) { diff --git a/src/lib.rs b/src/lib.rs index 48b7d23f28..33d063716c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,6 +21,7 @@ mod syntax_parser; pub mod term; #[cfg(test)] mod tests; +mod text_input; mod ui; use bindings::Bindings; diff --git a/src/picker.rs b/src/picker.rs index b0c0c789d8..f01dbc0b6e 100644 --- a/src/picker.rs +++ b/src/picker.rs @@ -1,11 +1,10 @@ use fuzzy_matcher::FuzzyMatcher; use fuzzy_matcher::skim::SkimMatcherV2; use std::borrow::Cow; -use tui_prompts::State as _; -use tui_prompts::TextState; use crate::item_data::Ref; use crate::item_data::Rev; +use crate::text_input::TextInput; /// Data that can be selected in a picker #[derive(Debug, Clone, PartialEq)] @@ -69,7 +68,7 @@ pub struct PickerState { /// Current cursor position in filtered results cursor: usize, /// Current input pattern - pub input_state: TextState<'static>, + pub(crate) input_state: TextInput, /// Fuzzy matcher matcher: SkimMatcherV2, /// Prompt text to display @@ -101,7 +100,7 @@ impl PickerState { items: items.clone(), filtered_indices: Vec::new(), cursor: 0, - input_state: TextState::default(), + input_state: TextInput::default(), matcher: SkimMatcherV2::default(), prompt_text: prompt.into(), status: PickerStatus::Active, @@ -179,7 +178,7 @@ impl PickerState { /// Get current input pattern pub fn pattern(&self) -> &str { - self.input_state.value() + &self.input_state.value } /// Update the filter based on current input pattern diff --git a/src/prompt.rs b/src/prompt.rs index b32def6aac..837a85aedf 100644 --- a/src/prompt.rs +++ b/src/prompt.rs @@ -1,5 +1,5 @@ +use crate::text_input::TextInput; use std::borrow::Cow; -use tui_prompts::{State, TextState}; pub(crate) struct PromptData { pub(crate) prompt_text: Cow<'static, str>, @@ -7,24 +7,24 @@ pub(crate) struct PromptData { pub(crate) struct Prompt { pub(crate) data: Option, - pub(crate) state: TextState<'static>, + pub(crate) state: TextInput, } impl Prompt { pub(crate) fn new() -> Self { Prompt { data: None, - state: TextState::new(), + state: TextInput::default(), } } pub(crate) fn set(&mut self, data: PromptData) { self.data = Some(data); - self.state.focus(); + self.state.focused = true; } pub(crate) fn reset(&mut self) { self.data = None; - self.state = TextState::new(); + self.state = TextInput::default(); } } diff --git a/src/style.rs b/src/style.rs index 8a93a6dbf1..8d698751e0 100644 --- a/src/style.rs +++ b/src/style.rs @@ -33,18 +33,6 @@ impl Style { } } -/// The prompt symbols come out of tui-prompts as ratatui spans. -impl From for Style { - fn from(style: ratatui::style::Style) -> Self { - Style { - fg: style.fg.map(Color::from), - bg: style.bg.map(Color::from), - add_modifier: Modifier(style.add_modifier.bits()), - sub_modifier: Modifier(style.sub_modifier.bits()), - } - } -} - #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] pub enum Color { #[default] @@ -95,34 +83,6 @@ impl From for crossterm::style::Color { } } -impl From for Color { - fn from(color: ratatui::style::Color) -> Self { - use ratatui::style::Color as R; - - match color { - R::Reset => Self::Reset, - R::Black => Self::Black, - R::Red => Self::Red, - R::Green => Self::Green, - R::Yellow => Self::Yellow, - R::Blue => Self::Blue, - R::Magenta => Self::Magenta, - R::Cyan => Self::Cyan, - R::Gray => Self::Gray, - R::DarkGray => Self::DarkGray, - R::LightRed => Self::LightRed, - R::LightGreen => Self::LightGreen, - R::LightYellow => Self::LightYellow, - R::LightBlue => Self::LightBlue, - R::LightMagenta => Self::LightMagenta, - R::LightCyan => Self::LightCyan, - R::White => Self::White, - R::Rgb(r, g, b) => Self::Rgb(r, g, b), - R::Indexed(i) => Self::Indexed(i), - } - } -} - impl FromStr for Color { type Err = ParseColorError; diff --git a/src/text_input.rs b/src/text_input.rs new file mode 100644 index 0000000000..35e105ea24 --- /dev/null +++ b/src/text_input.rs @@ -0,0 +1,215 @@ +use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers}; + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +pub(crate) enum Status { + #[default] + Pending, + Aborted, + Done, +} + +#[derive(Debug, Default, Clone, PartialEq, Eq)] +pub(crate) struct TextInput { + pub(crate) value: String, + /// Counted in chars, not bytes. + position: usize, + pub(crate) status: Status, + pub(crate) focused: bool, +} + +impl TextInput { + /// Splits the value around the char the cursor is on, so it can be drawn + /// as a cursor rather than the cursor taking up a column of its own. That + /// char is empty with the cursor at the end of the value. + pub(crate) fn split_at_cursor(&self) -> (&str, &str, &str) { + let byte_at = |position| { + self.value + .char_indices() + .nth(position) + .map_or(self.value.len(), |(byte, _)| byte) + }; + + let start = byte_at(self.position); + let end = byte_at(self.position + 1); + + ( + &self.value[..start], + &self.value[start..end], + &self.value[end..], + ) + } + + pub(crate) fn handle_key_event(&mut self, key: KeyEvent) { + if key.kind == KeyEventKind::Release { + return; + } + + match (key.code, key.modifiers) { + (KeyCode::Enter, _) => self.status = Status::Done, + (KeyCode::Esc, _) | (KeyCode::Char('c'), KeyModifiers::CONTROL) => { + self.status = Status::Aborted; + } + (KeyCode::Left, _) | (KeyCode::Char('b'), KeyModifiers::CONTROL) => { + self.position = self.position.saturating_sub(1); + } + (KeyCode::Right, _) | (KeyCode::Char('f'), KeyModifiers::CONTROL) => { + self.position = self.position.saturating_add(1).min(self.len()); + } + (KeyCode::Home, _) | (KeyCode::Char('a'), KeyModifiers::CONTROL) => self.position = 0, + (KeyCode::End, _) | (KeyCode::Char('e'), KeyModifiers::CONTROL) => { + self.position = self.len(); + } + (KeyCode::Backspace, _) | (KeyCode::Char('h'), KeyModifiers::CONTROL) => { + if self.position > 0 { + self.remove(self.position - 1); + self.position -= 1; + } + } + (KeyCode::Delete, _) | (KeyCode::Char('d'), KeyModifiers::CONTROL) => { + if self.position < self.len() { + self.remove(self.position); + } + } + (KeyCode::Char('k'), KeyModifiers::CONTROL) => { + self.value = self.value.chars().take(self.position).collect(); + } + (KeyCode::Char('u'), KeyModifiers::CONTROL) => { + self.value.clear(); + self.position = 0; + } + (KeyCode::Char(c), KeyModifiers::NONE | KeyModifiers::SHIFT) => { + self.insert(c); + self.position += 1; + } + _ => (), + } + } + + fn len(&self) -> usize { + self.value.chars().count() + } + + /// Editing goes via chars, as `String`'s own byte-indexed methods would + /// split multi-byte ones. + fn remove(&mut self, position: usize) { + self.value = self + .value + .chars() + .take(position) + .chain(self.value.chars().skip(position + 1)) + .collect(); + } + + fn insert(&mut self, c: char) { + if self.position == self.len() { + self.value.push(c); + return; + } + + self.value = self + .value + .chars() + .take(self.position) + .chain(std::iter::once(c)) + .chain(self.value.chars().skip(self.position)) + .collect(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn press(input: &mut TextInput, code: KeyCode) { + input.handle_key_event(KeyEvent::new(code, KeyModifiers::empty())); + } + + fn ctrl(input: &mut TextInput, c: char) { + input.handle_key_event(KeyEvent::new(KeyCode::Char(c), KeyModifiers::CONTROL)); + } + + fn typed(text: &str) -> TextInput { + let mut input = TextInput::default(); + for c in text.chars() { + press(&mut input, KeyCode::Char(c)); + } + input + } + + #[test] + fn types_and_edits() { + let mut input = typed("abc"); + assert_eq!(input.value, "abc"); + + press(&mut input, KeyCode::Backspace); + assert_eq!(input.value, "ab"); + + press(&mut input, KeyCode::Left); + press(&mut input, KeyCode::Char('x')); + assert_eq!(input.value, "axb"); + + press(&mut input, KeyCode::Delete); + assert_eq!(input.value, "ax"); + } + + #[test] + fn edits_multibyte_chars() { + let mut input = typed("åäö"); + + press(&mut input, KeyCode::Backspace); + assert_eq!(input.value, "åä"); + + press(&mut input, KeyCode::Home); + press(&mut input, KeyCode::Delete); + assert_eq!(input.value, "ä"); + + press(&mut input, KeyCode::Char('ö')); + assert_eq!(input.value, "öä"); + } + + #[test] + fn moves_within_bounds() { + let mut input = typed("ab"); + + press(&mut input, KeyCode::Right); + press(&mut input, KeyCode::Right); + press(&mut input, KeyCode::Char('c')); + assert_eq!(input.value, "abc"); + + press(&mut input, KeyCode::Home); + press(&mut input, KeyCode::Left); + press(&mut input, KeyCode::Char('x')); + assert_eq!(input.value, "xabc"); + } + + #[test] + fn kills_and_truncates() { + let mut input = typed("abcd"); + press(&mut input, KeyCode::Left); + ctrl(&mut input, 'k'); + assert_eq!(input.value, "abc"); + + ctrl(&mut input, 'u'); + assert_eq!(input.value, ""); + + press(&mut input, KeyCode::Char('e')); + assert_eq!(input.value, "e"); + } + + #[test] + fn tracks_status() { + let mut input = TextInput::default(); + assert_eq!(input.status, Status::Pending); + + press(&mut input, KeyCode::Enter); + assert_eq!(input.status, Status::Done); + + let mut input = TextInput::default(); + press(&mut input, KeyCode::Esc); + assert_eq!(input.status, Status::Aborted); + + let mut input = TextInput::default(); + ctrl(&mut input, 'c'); + assert_eq!(input.status, Status::Aborted); + } +} diff --git a/src/ui.rs b/src/ui.rs index b4f9f3ca28..5c0891c758 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -4,13 +4,13 @@ use crate::Res; use crate::app::State; use crate::error::Error; use crate::screen; -use crate::style::Style; +use crate::style::{Color, Modifier, Style}; use crate::term::TermBackend; +use crate::text_input::Status; use crate::ui::layout::LayoutItem; use itertools::Itertools; use layout::LayoutTree; use layout::OPTS; -use tui_prompts::State as _; use unicode_segmentation::UnicodeSegmentation; use unicode_width::UnicodeWidthStr; @@ -83,24 +83,59 @@ fn layout_prompt<'a>(layout: &mut UiTree<'a>, state: &'a State, width: usize) { return; }; - let prompt_symbol = state.prompt.state.status().symbol(); + let (symbol, symbol_color) = match state.prompt.state.status { + Status::Pending => ("?", Color::Cyan), + Status::Aborted => ("✘", Color::Red), + Status::Done => ("✔", Color::Green), + }; + let separator_style = Style::from(&state.config.style.separator); let prompt_style = Style::from(&state.config.style.prompt); repeat_chars(layout, width, DASHES, separator_style); layout.horizontal(None, OPTS, |layout| { - layout_span(layout, (prompt_symbol.content, prompt_symbol.style.into())); + layout_span( + layout, + ( + symbol.into(), + Style { + fg: Some(symbol_color), + ..Style::new() + }, + ), + ); layout_span(layout, (" ".into(), Style::new())); layout_span( layout, (prompt_data.prompt_text.as_ref().into(), prompt_style), ); layout_span(layout, (" › ".into(), prompt_style)); - layout_span(layout, (state.prompt.state.value().into(), Style::new())); - layout_span(layout, (CARET.into(), Style::new())); + let (before, at_cursor, after) = state.prompt.state.split_at_cursor(); + layout_span(layout, (before.into(), Style::new())); + layout_cursor(layout, at_cursor); + layout_span(layout, (after.into(), Style::new())); }); } +/// Draws the cursor over the char it's on, so that it takes up no width of its +/// own. Past the end of the value there's nothing to draw it over. +pub(crate) fn layout_cursor<'a>(layout: &mut UiTree<'a>, at_cursor: &'a str) { + if at_cursor.is_empty() { + layout_span(layout, (CARET.into(), Style::new())); + } else { + layout_span( + layout, + ( + at_cursor.into(), + Style { + add_modifier: Modifier::REVERSED, + ..Style::new() + }, + ), + ); + } +} + fn layout_picker<'a>(layout: &mut UiTree<'a>, state: &'a State, width: usize) { if let Some(ref picker_state) = state.picker { picker::layout_picker(layout, picker_state, &state.config, width); diff --git a/src/ui/picker.rs b/src/ui/picker.rs index 3b91ea993e..d616fde7b9 100644 --- a/src/ui/picker.rs +++ b/src/ui/picker.rs @@ -1,13 +1,12 @@ use std::borrow::Cow; use crate::style::Style; -use tui_prompts::State as _; use unicode_segmentation::UnicodeSegmentation; use crate::config::Config; use crate::picker::PickerState; use crate::ui::layout::OPTS; -use crate::ui::{CARET, DASHES, UiTree, layout_span, repeat_chars}; +use crate::ui::{DASHES, UiTree, layout_cursor, layout_span, repeat_chars}; const MAX_ITEMS_DISPLAY: usize = 10; @@ -31,8 +30,10 @@ pub(crate) fn layout_picker<'a>( // Prompt with separator (like regular prompt) layout_span(layout, (state.prompt_text.as_ref().into(), prompt_style)); layout_span(layout, (" › ".into(), prompt_style)); - layout_span(layout, (state.input_state.value().into(), Style::new())); - layout_span(layout, (CARET.into(), Style::new())); + let (before, at_cursor, after) = state.input_state.split_at_cursor(); + layout_span(layout, (before.into(), Style::new())); + layout_cursor(layout, at_cursor); + layout_span(layout, (after.into(), Style::new())); }); // Calculate visible items range (scroll window) From 45265f0f3997f40495fde5da160ea5cd81356674 Mon Sep 17 00:00:00 2001 From: altsem Date: Sun, 26 Jul 2026 20:38:16 +0200 Subject: [PATCH 10/11] change assert to debug_assert in screen mod --- src/screen/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/screen/mod.rs b/src/screen/mod.rs index 770dda013a..9c313e4140 100644 --- a/src/screen/mod.rs +++ b/src/screen/mod.rs @@ -271,7 +271,7 @@ impl Screen { pub(crate) fn update_indices(&mut self) -> Res<()> { self.update_item_heights(); - assert_eq!( + debug_assert_eq!( self.items.len(), self.item_heights.len(), "items and item_heights should have equal len" From 63c8ea59d01f3b91cfac7e101983ff4102501da2 Mon Sep 17 00:00:00 2001 From: altsem Date: Sun, 26 Jul 2026 21:25:06 +0200 Subject: [PATCH 11/11] test: make test-terminal more wide where remote (a file path) is visible CI would break since this path would be longer there --- src/tests/helpers/ui.rs | 17 +- src/tests/mod.rs | 2 +- src/tests/pull.rs | 158 +++++++++--------- src/tests/push.rs | 4 +- .../snapshots/gitu__tests__fetch_all.snap | 40 ++--- .../gitu__tests__pull__pull_push_remote.snap | 40 ++--- .../gitu__tests__pull__pull_upstream.snap | 40 ++--- .../gitu__tests__push__force_push.snap | 40 ++--- .../gitu__tests__push__push_upstream.snap | 40 ++--- 9 files changed, 198 insertions(+), 183 deletions(-) diff --git a/src/tests/helpers/ui.rs b/src/tests/helpers/ui.rs index 7c3b5ceb2a..ecc17016a5 100644 --- a/src/tests/helpers/ui.rs +++ b/src/tests/helpers/ui.rs @@ -40,9 +40,24 @@ macro_rules! setup_clone { () => {{ TestContext::setup_clone(function_name!()) }}; } +#[macro_export] +macro_rules! setup_clone_wide { + () => {{ TestContext::setup_clone_wide(function_name!()) }}; +} + impl TestContext { pub fn setup_clone(test_name: &str) -> Self { - let size = (80, 20); + Self::setup_clone_sized(test_name, (80, 20)) + } + + /// For tests whose output carries the remote's path. At 80 columns that + /// wraps on a longer checkout, which shifts every row of the frame and + /// leaves the path visible past what [`Self::redact_buffer`] blanks. + pub fn setup_clone_wide(test_name: &str) -> Self { + Self::setup_clone_sized(test_name, (120, 20)) + } + + fn setup_clone_sized(test_name: &str, size: (u16, u16)) -> Self { let term = TermBackend::Test { buffer: TestBuffer::new(size.0, size.1), events: vec![], diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 66b972f37f..e5a66ac7a4 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -327,7 +327,7 @@ fn new_commit() { #[test] fn fetch_all() { - let ctx = setup_clone!(); + let ctx = setup_clone_wide!(); clone_and_commit(&ctx.remote_dir, "remote-file", "hello"); snapshot!(ctx, "fa"); } diff --git a/src/tests/pull.rs b/src/tests/pull.rs index 3167f3b150..d52db03c4a 100644 --- a/src/tests/pull.rs +++ b/src/tests/pull.rs @@ -1,79 +1,79 @@ -use super::*; - -#[test] -fn pull_menu_no_remote_or_upstream_set() { - let ctx = setup_clone!(); - run(&ctx.dir, &["git", "branch", "--unset-upstream"]); - snapshot!(ctx, "F"); -} - -#[test] -fn pull_menu_existing_push_remote_and_upstream() { - let ctx = setup_clone!(); - run( - &ctx.dir, - &["git", "config", "branch.main.pushRemote", "origin"], - ); - snapshot!(ctx, "F"); -} - -#[test] -fn pull_upstream() { - let ctx = setup_clone!(); - clone_and_commit(&ctx.remote_dir, "remote-file", "hello"); - snapshot!(ctx, "Fu"); -} - -#[test] -fn pull_push_remote() { - let ctx = setup_clone!(); - run( - &ctx.dir, - &["git", "config", "branch.main.pushRemote", "origin"], - ); - - snapshot!(ctx, "Fp"); -} - -#[test] -fn pull_upstream_prompt() { - let ctx = setup_clone!(); - run(&ctx.dir, &["git", "branch", "--unset-upstream"]); - snapshot!(ctx, "Fu"); -} - -#[test] -fn pull_push_remote_prompt() { - let ctx = setup_clone!(); - snapshot!(ctx, "Fp"); -} - -#[test] -fn pull_setup_upstream() { - let ctx = setup_clone!(); - run(&ctx.dir, &["git", "checkout", "-b", "new-branch"]); - snapshot!(ctx, "FumainF"); -} - -#[test] -fn pull_setup_upstream_same_as_head() { - let ctx = setup_clone!(); - run(&ctx.dir, &["git", "checkout", "-b", "new-branch"]); - snapshot!(ctx, "Funew-branch"); -} - -#[test] -fn pull_setup_push_remote() { - let ctx = setup_clone!(); - snapshot!(ctx, "FporiginF"); -} - -#[test] -fn pull_from_elsewhere_prompt() { - snapshot!(setup_clone!(), "Fe"); -} - -#[test] -fn pull_from_elsewhere() { - snapshot!(setup_clone!(), "Feorigin"); -} +use super::*; + +#[test] +fn pull_menu_no_remote_or_upstream_set() { + let ctx = setup_clone!(); + run(&ctx.dir, &["git", "branch", "--unset-upstream"]); + snapshot!(ctx, "F"); +} + +#[test] +fn pull_menu_existing_push_remote_and_upstream() { + let ctx = setup_clone!(); + run( + &ctx.dir, + &["git", "config", "branch.main.pushRemote", "origin"], + ); + snapshot!(ctx, "F"); +} + +#[test] +fn pull_upstream() { + let ctx = setup_clone_wide!(); + clone_and_commit(&ctx.remote_dir, "remote-file", "hello"); + snapshot!(ctx, "Fu"); +} + +#[test] +fn pull_push_remote() { + let ctx = setup_clone_wide!(); + run( + &ctx.dir, + &["git", "config", "branch.main.pushRemote", "origin"], + ); + + snapshot!(ctx, "Fp"); +} + +#[test] +fn pull_upstream_prompt() { + let ctx = setup_clone!(); + run(&ctx.dir, &["git", "branch", "--unset-upstream"]); + snapshot!(ctx, "Fu"); +} + +#[test] +fn pull_push_remote_prompt() { + let ctx = setup_clone!(); + snapshot!(ctx, "Fp"); +} + +#[test] +fn pull_setup_upstream() { + let ctx = setup_clone!(); + run(&ctx.dir, &["git", "checkout", "-b", "new-branch"]); + snapshot!(ctx, "FumainF"); +} + +#[test] +fn pull_setup_upstream_same_as_head() { + let ctx = setup_clone!(); + run(&ctx.dir, &["git", "checkout", "-b", "new-branch"]); + snapshot!(ctx, "Funew-branch"); +} + +#[test] +fn pull_setup_push_remote() { + let ctx = setup_clone!(); + snapshot!(ctx, "FporiginF"); +} + +#[test] +fn pull_from_elsewhere_prompt() { + snapshot!(setup_clone!(), "Fe"); +} + +#[test] +fn pull_from_elsewhere() { + snapshot!(setup_clone!(), "Feorigin"); +} diff --git a/src/tests/push.rs b/src/tests/push.rs index cb81890de4..31ce2f6dc1 100644 --- a/src/tests/push.rs +++ b/src/tests/push.rs @@ -19,7 +19,7 @@ fn push_menu_existing_push_remote_and_upstream() { #[test] fn push_upstream() { - let ctx = setup_clone!(); + let ctx = setup_clone_wide!(); commit(&ctx.dir, "new-file", ""); snapshot!(ctx, "Pu"); } @@ -73,7 +73,7 @@ fn push_setup_push_remote() { #[test] fn force_push() { - let ctx = setup_clone!(); + let ctx = setup_clone_wide!(); commit(&ctx.dir, "new-file", ""); snapshot!(ctx, "P-fu"); } diff --git a/src/tests/snapshots/gitu__tests__fetch_all.snap b/src/tests/snapshots/gitu__tests__fetch_all.snap index 79f6050c0c..9cdd373dd5 100644 --- a/src/tests/snapshots/gitu__tests__fetch_all.snap +++ b/src/tests/snapshots/gitu__tests__fetch_all.snap @@ -2,24 +2,24 @@ source: src/tests/mod.rs expression: ctx.redact_buffer() --- -▌On branch main | -▌Your branch is behind 'origin/main' by 1 commit(s). | - | - Recent commits | - b66a0bf main add initial-file | - | - | - | - | - | - | - | - | - | - | - | -────────────────────────────────────────────────────────────────────────────────| -$ git fetch --all --jobs 10 | -From file:// - b66a0bf..d07f2d3 main -> origin/main | +▌On branch main | +▌Your branch is behind 'origin/main' by 1 commit(s). | + | + Recent commits | + b66a0bf main add initial-file | + | + | + | + | + | + | + | + | + | + | + | +────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────| +$ git fetch --all --jobs 10 | +From file:// + b66a0bf..d07f2d3 main -> origin/main | styles_hash: 8a8e7ce3455f812c diff --git a/src/tests/snapshots/gitu__tests__pull__pull_push_remote.snap b/src/tests/snapshots/gitu__tests__pull__pull_push_remote.snap index 9207db6ad5..965e73a79c 100644 --- a/src/tests/snapshots/gitu__tests__pull__pull_push_remote.snap +++ b/src/tests/snapshots/gitu__tests__pull__pull_push_remote.snap @@ -2,24 +2,24 @@ source: src/tests/pull.rs expression: ctx.redact_buffer() --- -▌On branch main | -▌Your branch is up to date with 'origin/main'. | - | - Recent commits | - b66a0bf main origin/main add initial-file | - | - | - | - | - | - | - | - | - | - | -────────────────────────────────────────────────────────────────────────────────| -$ git pull origin refs/heads/main | -From file:// - * branch main -> FETCH_HEAD | -Already up to date. | +▌On branch main | +▌Your branch is up to date with 'origin/main'. | + | + Recent commits | + b66a0bf main origin/main add initial-file | + | + | + | + | + | + | + | + | + | + | +────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────| +$ git pull origin refs/heads/main | +From file:// + * branch main -> FETCH_HEAD | +Already up to date. | styles_hash: cd9783096eb47a06 diff --git a/src/tests/snapshots/gitu__tests__pull__pull_upstream.snap b/src/tests/snapshots/gitu__tests__pull__pull_upstream.snap index f2a44301cc..dcaf2aa2a0 100644 --- a/src/tests/snapshots/gitu__tests__pull__pull_upstream.snap +++ b/src/tests/snapshots/gitu__tests__pull__pull_upstream.snap @@ -2,24 +2,24 @@ source: src/tests/pull.rs expression: ctx.redact_buffer() --- -▌On branch main | -▌Your branch is up to date with 'origin/main'. | - | - Recent commits | - d07f2d3 main origin/main add remote-file | - b66a0bf add initial-file | - | - | - | - | -────────────────────────────────────────────────────────────────────────────────| -$ git pull origin refs/heads/main | -From file:// - * branch main -> FETCH_HEAD | - b66a0bf..d07f2d3 main -> origin/main | -Updating b66a0bf..d07f2d3 | -Fast-forward | - remote-file | 1 + | - 1 file changed, 1 insertion(+) | - create mode 100644 remote-file | +▌On branch main | +▌Your branch is up to date with 'origin/main'. | + | + Recent commits | + d07f2d3 main origin/main add remote-file | + b66a0bf add initial-file | + | + | + | + | +────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────| +$ git pull origin refs/heads/main | +From file:// + * branch main -> FETCH_HEAD | + b66a0bf..d07f2d3 main -> origin/main | +Updating b66a0bf..d07f2d3 | +Fast-forward | + remote-file | 1 + | + 1 file changed, 1 insertion(+) | + create mode 100644 remote-file | styles_hash: b6ce47a26557253d diff --git a/src/tests/snapshots/gitu__tests__push__force_push.snap b/src/tests/snapshots/gitu__tests__push__force_push.snap index 1a944177ad..5d91e79edc 100644 --- a/src/tests/snapshots/gitu__tests__push__force_push.snap +++ b/src/tests/snapshots/gitu__tests__push__force_push.snap @@ -2,24 +2,24 @@ source: src/tests/push.rs expression: ctx.redact_buffer() --- -▌On branch main | -▌Your branch is up to date with 'origin/main'. | - | - Recent commits | - e7eb2bd main origin/main add new-file | - b66a0bf add initial-file | - | - | - | - | - | - | - | - | - | - | -────────────────────────────────────────────────────────────────────────────────| -$ git push --force-with-lease origin refs/heads/main:refs/heads/main | -To file:// - b66a0bf..e7eb2bd main -> main | +▌On branch main | +▌Your branch is up to date with 'origin/main'. | + | + Recent commits | + e7eb2bd main origin/main add new-file | + b66a0bf add initial-file | + | + | + | + | + | + | + | + | + | + | +────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────| +$ git push --force-with-lease origin refs/heads/main:refs/heads/main | +To file:// + b66a0bf..e7eb2bd main -> main | styles_hash: b915bcc23d3116ec diff --git a/src/tests/snapshots/gitu__tests__push__push_upstream.snap b/src/tests/snapshots/gitu__tests__push__push_upstream.snap index ea9457da35..83d9661259 100644 --- a/src/tests/snapshots/gitu__tests__push__push_upstream.snap +++ b/src/tests/snapshots/gitu__tests__push__push_upstream.snap @@ -2,24 +2,24 @@ source: src/tests/push.rs expression: ctx.redact_buffer() --- -▌On branch main | -▌Your branch is up to date with 'origin/main'. | - | - Recent commits | - e7eb2bd main origin/main add new-file | - b66a0bf add initial-file | - | - | - | - | - | - | - | - | - | - | -────────────────────────────────────────────────────────────────────────────────| -$ git push origin refs/heads/main:refs/heads/main | -To file:// - b66a0bf..e7eb2bd main -> main | +▌On branch main | +▌Your branch is up to date with 'origin/main'. | + | + Recent commits | + e7eb2bd main origin/main add new-file | + b66a0bf add initial-file | + | + | + | + | + | + | + | + | + | + | +────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────| +$ git push origin refs/heads/main:refs/heads/main | +To file:// + b66a0bf..e7eb2bd main -> main | styles_hash: 86d7176114348d55