From 6456d53e2b3ee173ccbaa5ebbac592e340117358 Mon Sep 17 00:00:00 2001 From: altsem Date: Mon, 29 Sep 2025 21:31:09 +0200 Subject: [PATCH] refactor: new LayoutTree module to improve on ui headaches This is another attempt at introducing a ui that is more easy to work with. It is now composable via functions, and simplifies the UI code to just: ```rust layout.clear(); layout.stacked(OPTS, |layout| { screen::layout_screen( layout, frame.area().as_size(), state.screens.last().unwrap(), ); layout.vertical(OPTS.align_end(), |layout| { menu::layout_menu(layout, state); layout_command_log(layout, state); layout_prompt(layout, state); }); }); layout.compute([frame.area().width, frame.area().height]); for span in layout.iter() { let area = Rect { x: span.pos[0], y: span.pos[1], width: span.size[0], height: span.size[1], }; frame.render_widget(span.data, area); } ``` - Implementing wrapping of text is now closer. - The tui_prompt dependency should be easier to get rid of now. --- src/app.rs | 1 + src/items.rs | 34 +- src/screen/mod.rs | 140 ++-- .../snapshots/gitu__tests__binary_file.snap | 2 +- .../gitu__tests__branch__branch_menu.snap | 2 +- ...u__tests__branch__checkout_new_branch.snap | 2 +- ...u__tests__branch__delete_branch_empty.snap | 2 +- ...u__tests__branch__delete_branch_input.snap | 2 +- ...tests__branch__delete_branch_selected.snap | 2 +- ...tests__branch__delete_unmerged_branch.snap | 2 +- .../gitu__tests__branch__spinoff_branch.snap | 2 +- ..._spinoff_branch_with_unmerged_commits.snap | 2 +- ...ests__branch__spinoff_existing_branch.snap | 2 +- ...u__tests__branch__switch_branch_input.snap | 2 +- ...tests__branch__switch_branch_selected.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 | 4 +- ...iscard__discard_branch_confirm_prompt.snap | 4 +- ...tu__tests__discard__discard_branch_no.snap | 2 +- ...u__tests__discard__discard_branch_yes.snap | 2 +- ...tu__tests__discard__discard_file_move.snap | 2 +- ...__tests__discard__discard_staged_file.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 | 4 +- ...__editor__exit_from_prompt_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_prompt_from_menu.snap | 4 +- .../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 | 4 +- .../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 +- .../gitu__tests__log__grep_prompt.snap | 6 +- .../gitu__tests__log__grep_set_example.snap | 2 +- .../gitu__tests__log__limit_invalid.snap | 2 +- .../gitu__tests__log__limit_prompt.snap | 6 +- .../gitu__tests__log__limit_set_10.snap | 2 +- .../gitu__tests__log__log_other_invalid.snap | 2 +- .../gitu__tests__log__log_other_prompt.snap | 4 +- .../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_prompt.snap | 4 +- .../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 +- ...itu__tests__pull__pull_from_elsewhere.snap | 2 +- ...sts__pull__pull_from_elsewhere_prompt.snap | 4 +- ...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 | 4 +- ...__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 | 4 +- .../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 | 4 +- ...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 | 4 +- ...__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 | 4 +- .../gitu__tests__quit__confirm_quit.snap | 2 +- ...itu__tests__quit__confirm_quit_prompt.snap | 4 +- .../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 | 4 +- .../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 | 4 +- ..._tests__remote__add_remote_url_prompt.snap | 4 +- .../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 | 4 +- ...remote__rename_remote_new_name_prompt.snap | 4 +- .../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 | 4 +- .../snapshots/gitu__tests__revert_abort.snap | 2 +- .../snapshots/gitu__tests__revert_commit.snap | 2 +- .../gitu__tests__revert_commit_prompt.snap | 4 +- .../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 +- ...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 +- ...itu__tests__stash__stash_apply_prompt.snap | 4 +- .../gitu__tests__stash__stash_drop.snap | 2 +- ...itu__tests__stash__stash_drop_default.snap | 2 +- ...gitu__tests__stash__stash_drop_prompt.snap | 4 +- .../gitu__tests__stash__stash_index.snap | 2 +- ...itu__tests__stash__stash_index_prompt.snap | 4 +- ...tu__tests__stash__stash_keeping_index.snap | 2 +- ...ts__stash__stash_keeping_index_prompt.snap | 4 +- .../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 | 4 +- .../gitu__tests__stash__stash_prompt.snap | 4 +- ...itu__tests__stash__stash_working_tree.snap | 2 +- ...sts__stash__stash_working_tree_prompt.snap | 4 +- ...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 +- ...u__tests__unstage__unstage_added_line.snap | 2 +- ...u__tests__unstage__unstage_all_staged.snap | 2 +- ..._tests__unstage__unstage_removed_line.snap | 2 +- .../gitu__tests__unstaged_changes.snap | 2 +- .../gitu__tests__updated_externally.snap | 2 +- src/ui.rs | 186 +++-- src/ui/layout/direction.rs | 16 + src/ui/layout/mod.rs | 715 ++++++++++++++++++ src/ui/layout/node.rs | 55 ++ ...gitu__ui__layout__tests__align_bottom.snap | 7 + .../gitu__ui__layout__tests__align_right.snap | 5 + .../gitu__ui__layout__tests__gitu_mockup.snap | 29 + .../gitu__ui__layout__tests__grow.snap | 7 + ...tu__ui__layout__tests__horizontal_gap.snap | 5 + ..._ui__layout__tests__horizontal_layout.snap | 5 + ...tu__ui__layout__tests__nested_layouts.snap | 6 + ...yout__tests__out_of_bounds_horizontal.snap | 6 + ...s__out_of_bounds_horizontal_align_end.snap | 6 + ...layout__tests__out_of_bounds_vertical.snap | 6 + ...sts__out_of_bounds_vertical_align_end.snap | 6 + .../gitu__ui__layout__tests__overflow.snap | 5 + .../gitu__ui__layout__tests__shrink.snap | 6 + .../gitu__ui__layout__tests__single_text.snap | 6 + .../gitu__ui__layout__tests__stacked.snap | 5 + ...gitu__ui__layout__tests__vertical_gap.snap | 7 + ...u__ui__layout__tests__vertical_layout.snap | 7 + .../layzer__tests__align_bottom.snap | 7 + .../snapshots/layzer__tests__align_right.snap | 5 + .../snapshots/layzer__tests__gitu_mockup.snap | 34 + .../layzer__tests__horizontal_gap.snap | 5 + .../layzer__tests__horizontal_layout.snap | 5 + .../layzer__tests__nested_layouts.snap | 6 + ...yzer__tests__out_of_bounds_horizontal.snap | 6 + ...s__out_of_bounds_horizontal_align_end.snap | 6 + ...layzer__tests__out_of_bounds_vertical.snap | 6 + ...sts__out_of_bounds_vertical_align_end.snap | 6 + .../snapshots/layzer__tests__single_text.snap | 6 + .../snapshots/layzer__tests__stacked.snap | 5 + .../layzer__tests__vertical_gap.snap | 7 + .../layzer__tests__vertical_layout.snap | 7 + src/ui/layout/vec2.rs | 119 +++ src/ui/menu.rs | 306 ++++---- 208 files changed, 1708 insertions(+), 499 deletions(-) create mode 100644 src/ui/layout/direction.rs create mode 100644 src/ui/layout/mod.rs create mode 100644 src/ui/layout/node.rs create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__align_bottom.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__align_right.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__gitu_mockup.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__grow.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__horizontal_gap.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__horizontal_layout.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__nested_layouts.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_horizontal.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_horizontal_align_end.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_vertical.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_vertical_align_end.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__overflow.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__shrink.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__single_text.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__stacked.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__vertical_gap.snap create mode 100644 src/ui/layout/snapshots/gitu__ui__layout__tests__vertical_layout.snap create mode 100644 src/ui/layout/snapshots/layzer__tests__align_bottom.snap create mode 100644 src/ui/layout/snapshots/layzer__tests__align_right.snap create mode 100644 src/ui/layout/snapshots/layzer__tests__gitu_mockup.snap create mode 100644 src/ui/layout/snapshots/layzer__tests__horizontal_gap.snap create mode 100644 src/ui/layout/snapshots/layzer__tests__horizontal_layout.snap create mode 100644 src/ui/layout/snapshots/layzer__tests__nested_layouts.snap create mode 100644 src/ui/layout/snapshots/layzer__tests__out_of_bounds_horizontal.snap create mode 100644 src/ui/layout/snapshots/layzer__tests__out_of_bounds_horizontal_align_end.snap create mode 100644 src/ui/layout/snapshots/layzer__tests__out_of_bounds_vertical.snap create mode 100644 src/ui/layout/snapshots/layzer__tests__out_of_bounds_vertical_align_end.snap create mode 100644 src/ui/layout/snapshots/layzer__tests__single_text.snap create mode 100644 src/ui/layout/snapshots/layzer__tests__stacked.snap create mode 100644 src/ui/layout/snapshots/layzer__tests__vertical_gap.snap create mode 100644 src/ui/layout/snapshots/layzer__tests__vertical_layout.snap create mode 100644 src/ui/layout/vec2.rs diff --git a/src/app.rs b/src/app.rs index 015d5df55f..9c328707bc 100644 --- a/src/app.rs +++ b/src/app.rs @@ -398,6 +398,7 @@ impl App { cmd.stderr(Stdio::piped()); let log_entry = self.state.current_cmd_log.push_cmd(&cmd); + term.draw(|frame| ui::ui(frame, &mut self.state)) .map_err(Error::Term)?; diff --git a/src/items.rs b/src/items.rs index 6e4f668ba7..9acc427304 100644 --- a/src/items.rs +++ b/src/items.rs @@ -32,8 +32,8 @@ pub(crate) struct Item { } impl Item { - pub fn to_line<'a>(&'a self, config: Arc) -> Line<'a> { - match &self.data { + pub fn to_line(&'_ self, config: Arc) -> 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), @@ -53,7 +53,7 @@ impl Item { RefKind::Remote(remote) => (remote, &config.style.remote), }; - Line::from(vec![Span::raw(*prefix), Span::styled(reference, style)]) + Line::from(vec![Span::raw(prefix), Span::styled(reference, style)]) } ItemData::Commit { short_id, @@ -64,7 +64,7 @@ impl Item { iter::once(Span::styled(short_id, &config.style.hash)) .chain( associated_references - .iter() + .into_iter() .map(|reference| match reference { RefKind::Tag(tag) => Span::styled(tag, &config.style.tag), RefKind::Branch(branch) => { @@ -78,9 +78,12 @@ impl Item { .chain([Span::raw(summary)]), Span::raw(" "), )), - ItemData::File(path) => Line::styled(path.to_string_lossy(), &config.style.file_header), + ItemData::File(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 file_diff = &diff.file_diffs[file_i]; let content = format!( "{:8} {}", @@ -105,12 +108,11 @@ impl Item { file_i, hunk_i, } => { - let file_diff = &diff.file_diffs[*file_i]; - let hunk = &file_diff.hunks[*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, &config.style.hunk_header) + Line::styled(content.to_string(), &config.style.hunk_header) } ItemData::HunkLine { diff, @@ -120,12 +122,12 @@ impl Item { line_i, } => { let hunk_highlights = - highlight::highlight_hunk(self.id, &config, &Rc::clone(diff), *file_i, *hunk_i); + 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_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); + let line_highlights = hunk_highlights.get_line_highlights(line_i); Line::from_iter(line_highlights.iter().map(|(highlight_range, style)| { Span::styled( @@ -156,11 +158,11 @@ impl Item { Line::styled(content, &config.style.section_header) } ItemData::BranchStatus(upstream, ahead, behind) => { - let content = if *ahead == 0 && *behind == 0 { + let content = if ahead == 0 && behind == 0 { format!("Your branch is up to date with '{upstream}'.") - } else if *ahead > 0 && *behind == 0 { + } else if ahead > 0 && behind == 0 { format!("Your branch is ahead of '{upstream}' by {ahead} commit(s).",) - } else if *ahead == 0 && *behind > 0 { + } else if ahead == 0 && behind > 0 { format!("Your branch is behind '{upstream}' by {behind} commit(s).",) } else { format!( diff --git a/src/screen/mod.rs b/src/screen/mod.rs index b226fad362..2e1e15fc50 100644 --- a/src/screen/mod.rs +++ b/src/screen/mod.rs @@ -1,15 +1,16 @@ -use crate::item_data::ItemData; -use ratatui::{ - buffer::Buffer, - layout::{Rect, Size}, - text::Line, - widgets::Widget, -}; +use crate::config::StyleConfig; +use crate::ui::layout::OPTS; +use crate::ui::{UiTree, layout_span}; +use crate::{item_data::ItemData, ui}; +use ratatui::{layout::Size, style::Style, text::Line}; +use unicode_segmentation::UnicodeSegmentation; use crate::{Res, config::Config, items::hash}; use super::Item; -use std::{collections::HashSet, sync::Arc}; +use std::borrow::Cow; +use std::collections::HashSet; +use std::sync::Arc; pub(crate) mod log; pub(crate) mod show; @@ -338,7 +339,7 @@ impl Screen { self.nav_filter(target_line_i, NavMode::IncludeHunkLines) } - fn line_views(&self, area: Size) -> impl Iterator> { + fn line_views(&'_ self, area: Size) -> impl Iterator> { let scan_start = self.scroll.min(self.cursor); let scan_end = (self.scroll + area.height as usize).min(self.line_index.len()); let scan_highlight_range = scan_start..(scan_end); @@ -357,7 +358,6 @@ impl Screen { Some(LineView { item_index: *item_index, - item, display, highlighted: highlight_depth.is_some(), }) @@ -368,54 +368,102 @@ impl Screen { struct LineView<'a> { item_index: usize, - item: &'a Item, display: Line<'a>, highlighted: bool, } -impl Widget for &Screen { - fn render(self, area: Rect, buf: &mut Buffer) { - let style = &self.config.style; +const SPACES: &str = " "; - for (line_index, line) in self.line_views(area.as_size()).enumerate() { - let line_area = Rect { - x: 0, - y: line_index as u16, - width: buf.area.width, - height: 1, - }; +pub(crate) fn layout_screen<'a>(layout: &mut UiTree<'a>, size: Size, screen: &'a Screen) { + let style = &screen.config.style; - let indented_line_area = Rect { x: 1, ..line_area }; + layout.vertical(None, OPTS, |layout| { + for line in screen.line_views(size) { + layout.horizontal(None, OPTS, |layout| { + let is_line_sel = screen.line_index[screen.cursor] == line.item_index; + let area_sel = area_selection_highlight(style, &line); + let line_sel = line_selection_highlight(style, &line, is_line_sel); + let bg = area_sel.patch(line_sel); - if line.highlighted { - buf.set_style(line_area, &style.selection_area); - - if self.line_index[self.cursor] == line.item_index { - buf.set_style(line_area, &style.selection_line); + let mut line_end = 1; + let gutter_char = if line.highlighted { + gutter_char(style, is_line_sel, bg) } else { - buf[(0, line_index as u16)] - .set_char(style.selection_bar.symbol) - .set_style(&style.selection_bar); - } - } + (" ".into(), Style::new()) + }; - let line_width = line.display.width(); + layout_span(layout, gutter_char); + + line.display.spans.into_iter().for_each(|span| { + let style = bg.patch(line.display.style).patch(span.style); + + let span_width = span.content.graphemes(true).count(); + + if line_end + span_width >= size.width as usize { + // Truncate the span and insert an ellipsis to indicate overflow + let overflow = line_end + span_width - size.width as usize; + line_end = size.width as usize; + ui::layout_span( + layout, + ( + span.content + .graphemes(true) + .take(span_width.saturating_sub(overflow + 1)) + .collect::() + .into(), + style, + ), + ); + layout_span(layout, ("…".into(), bg)); + } else { + // Insert the span as normal + line_end += span_width; + ui::layout_span(layout, (span.content, style)); + } + }); + + // Add ellipsis indicator for collapsed sections + let item = &screen.items[line.item_index]; + if screen.is_collapsed(item) { + line_end += 1; + layout_span(layout, ("…".into(), bg)); + } - line.display.render(indented_line_area, buf); - let overflow = line_width > line_area.width as usize; + // Style the rest of the line's empty space + let style = if is_line_sel { line_sel } else { area_sel }; + let padding_width = (size.width as usize).saturating_sub(line_end); + ui::repeat_chars(layout, padding_width, SPACES, style); + }); + } + }); +} - let line_width = line_width as u16; +fn gutter_char<'a>(style: &'a StyleConfig, is_line_sel: bool, bg: Style) -> (Cow<'a, str>, Style) { + if is_line_sel { + ( + style.cursor.symbol.to_string().into(), + bg.patch(Style::from(&style.cursor)), + ) + } else { + ( + style.selection_bar.symbol.to_string().into(), + bg.patch(Style::from(&style.selection_bar)), + ) + } +} - if self.is_collapsed(line.item) && line_width > 0 || overflow { - let line_end = (indented_line_area.x + line_width).min(area.width - 1); - buf[(line_end, line_index as u16)].set_char('…'); - } +fn line_selection_highlight(style: &StyleConfig, line: &LineView, selected_line: bool) -> Style { + if line.highlighted && selected_line { + Style::from(&style.selection_line) + } else { + Style::new() + } +} - if self.line_index[self.cursor] == line.item_index { - buf[(0, line_index as u16)] - .set_char(style.cursor.symbol) - .set_style(&style.cursor); - } - } +fn area_selection_highlight(style: &StyleConfig, line: &LineView) -> Style { + if line.highlighted { + Style::from(&style.selection_area) + } else { + Style::new() } } diff --git a/src/tests/snapshots/gitu__tests__binary_file.snap b/src/tests/snapshots/gitu__tests__binary_file.snap index 69ba7dfd28..fe595300a4 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: 19b472560e249866 +styles_hash: 2ac73f967fc59190 diff --git a/src/tests/snapshots/gitu__tests__branch__branch_menu.snap b/src/tests/snapshots/gitu__tests__branch__branch_menu.snap index 924463486d..e7ba9d8424 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 @@ c Checkout new branch s Spinoff branch | K Delete branch | q/esc Quit/Close | -styles_hash: c58acfa46b8729d2 +styles_hash: 756dd5d606fd74c1 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 ccea8a67ac..337a060b45 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: c7925dfc1f0f00cd +styles_hash: a1f628b74611cf6 diff --git a/src/tests/snapshots/gitu__tests__branch__delete_branch_empty.snap b/src/tests/snapshots/gitu__tests__branch__delete_branch_empty.snap index baba21d692..4ebce2908f 100644 --- a/src/tests/snapshots/gitu__tests__branch__delete_branch_empty.snap +++ b/src/tests/snapshots/gitu__tests__branch__delete_branch_empty.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| ! Branch name required | -styles_hash: 9d05aa77b6eb9bc0 +styles_hash: 43caca969d2bfad0 diff --git a/src/tests/snapshots/gitu__tests__branch__delete_branch_input.snap b/src/tests/snapshots/gitu__tests__branch__delete_branch_input.snap index b7ff5fd7a8..d85c776321 100644 --- a/src/tests/snapshots/gitu__tests__branch__delete_branch_input.snap +++ b/src/tests/snapshots/gitu__tests__branch__delete_branch_input.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git branch -d merged | Deleted branch merged (was b66a0bf). | -styles_hash: fe4eba566a31096 +styles_hash: d9bb74cb0cca9527 diff --git a/src/tests/snapshots/gitu__tests__branch__delete_branch_selected.snap b/src/tests/snapshots/gitu__tests__branch__delete_branch_selected.snap index 906e63dad5..96f66526c8 100644 --- a/src/tests/snapshots/gitu__tests__branch__delete_branch_selected.snap +++ b/src/tests/snapshots/gitu__tests__branch__delete_branch_selected.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git branch -d merged | Deleted branch merged (was b66a0bf). | -styles_hash: 653adde7e95e076f +styles_hash: 8bfe9aef11191d75 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 8ef62b5473..04a3ae4e32 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 unmerged | Deleted branch unmerged (was c84f226). | -styles_hash: 7de97cab1939df6c +styles_hash: 284c7054a6c675b diff --git a/src/tests/snapshots/gitu__tests__branch__spinoff_branch.snap b/src/tests/snapshots/gitu__tests__branch__spinoff_branch.snap index 29b109c6f9..64af435db2 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: 45f8ee0a90f99b49 +styles_hash: 91e8574c96c70aa2 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 03f3d0a789..9e1ab0acfa 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 @@ $ git checkout -b new Switched to a new branch 'new' | $ git update-ref -m "reset: moving to b66a0bf82020d6a386e94d0fceedec1f817d20c7" | > Branch main was reset to b66a0bf82020d6a386e94d0fceedec1f817d20c7 | -styles_hash: d3d6e4d4bf225b45 +styles_hash: 95e2ce64ed89e43a 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 9eca25271b..3929bf2c45 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 unmerged. It already exists | -styles_hash: 9aed6daf88137469 +styles_hash: 43caca969d2bfad0 diff --git a/src/tests/snapshots/gitu__tests__branch__switch_branch_input.snap b/src/tests/snapshots/gitu__tests__branch__switch_branch_input.snap index 2d2bd0dbe1..d9ac89b31b 100644 --- a/src/tests/snapshots/gitu__tests__branch__switch_branch_input.snap +++ b/src/tests/snapshots/gitu__tests__branch__switch_branch_input.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git checkout merged | Switched to branch 'merged' | -styles_hash: a0f9f5f991757004 +styles_hash: 55d0ea0fc3a2ff71 diff --git a/src/tests/snapshots/gitu__tests__branch__switch_branch_selected.snap b/src/tests/snapshots/gitu__tests__branch__switch_branch_selected.snap index b32f2c4f83..b3f5ac1948 100644 --- a/src/tests/snapshots/gitu__tests__branch__switch_branch_selected.snap +++ b/src/tests/snapshots/gitu__tests__branch__switch_branch_selected.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() ────────────────────────────────────────────────────────────────────────────────| $ git checkout merged | Switched to branch 'merged' | -styles_hash: 3e20cbd7891bb3eb +styles_hash: dddf48e40dd31d6d diff --git a/src/tests/snapshots/gitu__tests__collapsed_sections_config.snap b/src/tests/snapshots/gitu__tests__collapsed_sections_config.snap index 7f01ec6f1a..15b40a2097 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: cbfd7594a526d60d +styles_hash: 887fd7e89f337304 diff --git a/src/tests/snapshots/gitu__tests__commit__commit_extend.snap b/src/tests/snapshots/gitu__tests__commit__commit_extend.snap index 945b0cd19e..c4c18b6e68 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 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git commit --amend --no-edit | -styles_hash: c98cd4a568aa98f0 +styles_hash: e30dda22040580a6 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 aa938f787e..d75b7e6c99 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 Author: Author Name | 1 file changed, 1 insertion(+), 1 deletion(-) | $ git rebase -i -q --autostash --keep-empty --autosquash efc77f3bea683ce4ea27f2e| -styles_hash: c2c1aca698ebd0d3 +styles_hash: 3dc9c05b82d675ea 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 1542495586..2f2858d864 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 commit --fixup efc77f3bea683ce4ea27f2e9d7d1bdf04c91a57f $ git rebase -i -q --autostash --keep-empty --autosquash efc77f3bea683ce4ea27f2e| Applied autostash. | Created autostash: d682ced | -styles_hash: 9261bcce695e4986 +styles_hash: d6b46e6ec2892e8b diff --git a/src/tests/snapshots/gitu__tests__commit__commit_menu.snap b/src/tests/snapshots/gitu__tests__commit__commit_menu.snap index 559f09c2ec..817ffdcac8 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 @@ e extend -n Disable hooks (--no-verify) 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: 41104da05d2a0c8c +styles_hash: b7834279d4aa5e1 diff --git a/src/tests/snapshots/gitu__tests__copied_file.snap b/src/tests/snapshots/gitu__tests__copied_file.snap index a28b50a1ef..5d775ea390 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: d5894e8f6f6a0a44 +styles_hash: 2bb10d15c578771b diff --git a/src/tests/snapshots/gitu__tests__crlf_diff.snap b/src/tests/snapshots/gitu__tests__crlf_diff.snap index 72c2926834..c5207c326b 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: 75c0c0779835909d +styles_hash: b0d01159a2674933 diff --git a/src/tests/snapshots/gitu__tests__deleted_file.snap b/src/tests/snapshots/gitu__tests__deleted_file.snap index 693b6ceebd..85f25ae16a 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: d5894e8f6f6a0a44 +styles_hash: badf8c339aba8de6 diff --git a/src/tests/snapshots/gitu__tests__discard__branch_selected.snap b/src/tests/snapshots/gitu__tests__discard__branch_selected.snap index 94db0854e6..87f4346e5e 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: 653adde7e95e076f +styles_hash: 8bfe9aef11191d75 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 4811175eb9..51395ac4cc 100644 --- a/src/tests/snapshots/gitu__tests__discard__branch_selected_confirm.snap +++ b/src/tests/snapshots/gitu__tests__discard__branch_selected_confirm.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Really discard? (y or n) › | -styles_hash: 3747660fef599652 +? Really discard? (y or n) › █ | +styles_hash: 67e0f1857fe702bb 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 3df48e0f3c..a23ed734b6 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 @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Really discard? (y or n) › | -styles_hash: e802436b24fbcb24 +? Really discard? (y or n) › █ | +styles_hash: c2658d4c1ac2535f 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 83f3fafb9f..2b1e66507e 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: 8aeb733dddf67818 +styles_hash: 25b2be4c9a1311be 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 1a9188e767..f9c143cc48 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: 32a139704e30d56a +styles_hash: bfc1ee08b76f94ad 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 a7d5d8db34..f323699e9f 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 mv --force moved-file new-file | -styles_hash: 696d0b50bd2c76de +styles_hash: eb6a652a52e5107d diff --git a/src/tests/snapshots/gitu__tests__discard__discard_staged_file.snap b/src/tests/snapshots/gitu__tests__discard__discard_staged_file.snap index 9c435b3e50..0df8c71ac1 100644 --- a/src/tests/snapshots/gitu__tests__discard__discard_staged_file.snap +++ b/src/tests/snapshots/gitu__tests__discard__discard_staged_file.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | ────────────────────────────────────────────────────────────────────────────────| $ git checkout HEAD -- file-one | -styles_hash: 19cf9a9796ec3951 +styles_hash: eb6a652a52e5107d 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 9c435b3e50..0df8c71ac1 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 checkout HEAD -- file-one | -styles_hash: 19cf9a9796ec3951 +styles_hash: eb6a652a52e5107d 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 7a590223e4..2359d835f5 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 | -styles_hash: eb4fd0eabfab208e +styles_hash: 14a075b7241f95c4 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 6e8858e301..2ce57f74ec 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: b29a924207accd5c +styles_hash: f86988cc26cd1ad3 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 6c057ee4d6..a062a4bf97 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: ad9bddbf35584d2f +styles_hash: 83ef0215d59acb6b 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 9c7f050f60..e7dea35b91 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 rm --force some-file | rm 'some-file' | -styles_hash: e6476ccfeefe9515 +styles_hash: 83ef0215d59acb6b 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 3560ebb084..7f350bcc33 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: b48d6931973c1aad +styles_hash: 2f7a000147177f9e 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 beea173bc3..94a3a4b322 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 @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Branch is not fully merged. Really delete? (y or n) › | -styles_hash: 9e4e7fa9d6fc799b +? Branch is not fully merged. Really delete? (y or n) › █ | +styles_hash: f59511b6a326efea diff --git a/src/tests/snapshots/gitu__tests__editor__exit_from_prompt_exits_menu.snap b/src/tests/snapshots/gitu__tests__editor__exit_from_prompt_exits_menu.snap index ecb4075879..d03704f938 100644 --- a/src/tests/snapshots/gitu__tests__editor__exit_from_prompt_exits_menu.snap +++ b/src/tests/snapshots/gitu__tests__editor__exit_from_prompt_exits_menu.snap @@ -22,4 +22,4 @@ expression: ctx.redact_buffer() | | | -styles_hash: 59b42b473ea2086a +styles_hash: f47a6512af0aca26 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 859094401d..1d8ad20985 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: 9ece290a1413a1cc +styles_hash: 8b4a7c91283b4dc 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 111a787bef..c626588d62 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: fc17643854723800 +styles_hash: 77349537e5766256 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 38603352f7..04af938cb2 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: 706a4e3dc9f00a8e +styles_hash: b8977a09f6b87dab diff --git a/src/tests/snapshots/gitu__tests__editor__re_enter_prompt_from_menu.snap b/src/tests/snapshots/gitu__tests__editor__re_enter_prompt_from_menu.snap index e3f7d4a08d..96364e613e 100644 --- a/src/tests/snapshots/gitu__tests__editor__re_enter_prompt_from_menu.snap +++ b/src/tests/snapshots/gitu__tests__editor__re_enter_prompt_from_menu.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Checkout: › | -styles_hash: c00cd874d0dc3947 +? Checkout: › █ | +styles_hash: 2faf803a0bc2afc0 diff --git a/src/tests/snapshots/gitu__tests__editor__scroll_down.snap b/src/tests/snapshots/gitu__tests__editor__scroll_down.snap index 845b67207c..ab0131ee6d 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: ac102dc28a09e63c +styles_hash: ee3d46c497e041fa 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 ac0a08bf98..220ba90af6 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 15 (file-2) | ▌+line 16 (file-2) | ▌+line 17 (file-2) | -styles_hash: 7c4bdf91930d826e +styles_hash: ae0fb0ed74b80538 diff --git a/src/tests/snapshots/gitu__tests__ext_diff.snap b/src/tests/snapshots/gitu__tests__ext_diff.snap index a587c7fcd7..25b00167a5 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: cc3c122bd1c34f20 +styles_hash: 78d73e0b179ed03a 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 51d1140fbc..ba87ef3cbd 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: b6d8677bf94d7533 +styles_hash: 70a67250e5c8bb24 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 1905e1db65..df658dd674 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 @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Select remote: › | -styles_hash: a2a72e20bfcc2997 +? Select remote: › █ | +styles_hash: b7603d8a82add7a diff --git a/src/tests/snapshots/gitu__tests__fetch_all.snap b/src/tests/snapshots/gitu__tests__fetch_all.snap index fda902cf74..508744d929 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: 362e47f9c483be51 +styles_hash: afb6ffa56adcff20 diff --git a/src/tests/snapshots/gitu__tests__fresh_init.snap b/src/tests/snapshots/gitu__tests__fresh_init.snap index c13150937b..202c4ecc04 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: bc670d3bb6a7cf9a +styles_hash: 8c6c6826d7047b9a 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 49d4ea6a6b..2955cde860 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: 4467194ddc2b2796 +styles_hash: ced58bcec150cda1 diff --git a/src/tests/snapshots/gitu__tests__help_menu.snap b/src/tests/snapshots/gitu__tests__help_menu.snap index 6df98b7269..280166c611 100644 --- a/src/tests/snapshots/gitu__tests__help_menu.snap +++ b/src/tests/snapshots/gitu__tests__help_menu.snap @@ -22,4 +22,4 @@ ctrl+u Half page up r Rebase ctrl+d Half page down X Reset | g Refresh V Revert | q/esc Quit/Close z Stash | -styles_hash: 5d3d73f836cc425b +styles_hash: 1948c1c151c3789 diff --git a/src/tests/snapshots/gitu__tests__hide_untracked.snap b/src/tests/snapshots/gitu__tests__hide_untracked.snap index 9b87cbfacd..2f484aa8d3 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: 59b42b473ea2086a +styles_hash: f47a6512af0aca26 diff --git a/src/tests/snapshots/gitu__tests__inside_submodule.snap b/src/tests/snapshots/gitu__tests__inside_submodule.snap index 9b87cbfacd..2f484aa8d3 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: 59b42b473ea2086a +styles_hash: f47a6512af0aca26 diff --git a/src/tests/snapshots/gitu__tests__log__grep_prompt.snap b/src/tests/snapshots/gitu__tests__log__grep_prompt.snap index 1fa5c6c737..3bb9d79e8b 100644 --- a/src/tests/snapshots/gitu__tests__log__grep_prompt.snap +++ b/src/tests/snapshots/gitu__tests__log__grep_prompt.snap @@ -16,10 +16,10 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Search messages: › | -────────────────────────────────────────────────────────────────────────────────| Log Arguments | l current -F Search messages (--grep) | o other -n Limit number of commits (-n=256) | q/esc Quit/Close | -styles_hash: 3fc7870144b77995 +────────────────────────────────────────────────────────────────────────────────| +? Search messages: › █ | +styles_hash: 12b20bb85685238e 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 fca77b0fd4..54d7e0231d 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 @@ Log Arguments l current -F Search messages (--grep=example) | o other -n Limit number of commits (-n=256) | q/esc Quit/Close | -styles_hash: 6d2c59bd2997ef60 +styles_hash: ec43c46bd8c19f7b diff --git a/src/tests/snapshots/gitu__tests__log__limit_invalid.snap b/src/tests/snapshots/gitu__tests__log__limit_invalid.snap index 283fc902ca..040eeb4d8a 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: 88c1d63d53e162a6 +styles_hash: 9cb7ad0f8cbe91e4 diff --git a/src/tests/snapshots/gitu__tests__log__limit_prompt.snap b/src/tests/snapshots/gitu__tests__log__limit_prompt.snap index bd26edf328..be5291ecf3 100644 --- a/src/tests/snapshots/gitu__tests__log__limit_prompt.snap +++ b/src/tests/snapshots/gitu__tests__log__limit_prompt.snap @@ -16,10 +16,10 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Limit number of commits (default 256): › | -────────────────────────────────────────────────────────────────────────────────| Log Arguments | l current -F Search messages (--grep) | o other -n Limit number of commits (-n) | q/esc Quit/Close | -styles_hash: b8b44a43e075d8ef +────────────────────────────────────────────────────────────────────────────────| +? Limit number of commits (default 256): › █ | +styles_hash: 53d776a580bfc344 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 f8fe12679c..93726595ab 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 @@ Log Arguments l current -F Search messages (--grep) | o other -n Limit number of commits (-n=10) | q/esc Quit/Close | -styles_hash: 504c06534b64018d +styles_hash: 8fce59f78927d9d8 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 21e293bdf4..153f5d4bd8 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 patte| -styles_hash: ffc8b90af65e99f9 +styles_hash: 9cb7ad0f8cbe91e4 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 d14ca16557..1999e540af 100644 --- a/src/tests/snapshots/gitu__tests__log__log_other_prompt.snap +++ b/src/tests/snapshots/gitu__tests__log__log_other_prompt.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Log rev (default 6c08cf78a4544ae4dda8e6161a61070867c60246): › | -styles_hash: b9fd13286ebd29fe +? Log rev (default 6c08cf78a4544ae4dda8e6161a61070867c60246): › █ | +styles_hash: 97b0fe4b8b1ae83b 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 d2528bc369..b7979c316f 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: 6a2769c2ca1e8994 +styles_hash: 164920bbc1c4bd1c diff --git a/src/tests/snapshots/gitu__tests__merge__merge_menu.snap b/src/tests/snapshots/gitu__tests__merge__merge_menu.snap index 093aa91e38..e1d7d77e0a 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 @@ m merge -f Fast-forward only (--ff-only) a abort -n No fast-forward (--no-ff) | c continue | q/ Quit/Close | -styles_hash: 218a5930a2320238 +styles_hash: d6eec1a5c7502309 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 bc50757f17..51deb1adc5 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: b5c08b1a2d972251 +styles_hash: 249aedfcf7d744b8 diff --git a/src/tests/snapshots/gitu__tests__merge__merge_prompt.snap b/src/tests/snapshots/gitu__tests__merge__merge_prompt.snap index 78d9eb19f8..ae86f2a7cb 100644 --- a/src/tests/snapshots/gitu__tests__merge__merge_prompt.snap +++ b/src/tests/snapshots/gitu__tests__merge__merge_prompt.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Merge: › | -styles_hash: 8c45ef481d078f38 +? Merge: › █ | +styles_hash: 3bbca79e1586dba9 diff --git a/src/tests/snapshots/gitu__tests__merge_conflict.snap b/src/tests/snapshots/gitu__tests__merge_conflict.snap index fecd26d7de..b909fe8ca1 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: 3dd0cab59ed8fc86 +styles_hash: f80e04421a39123 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 b5a98ed3e8..962de5e541 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: 60ab1900920b4419 +styles_hash: 9e60da5cf26728a4 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 a540aea9aa..85379f83b6 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: 13c1889f9a21c5e3 +styles_hash: 96cd3159bc3b002 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 a540aea9aa..85379f83b6 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: 13c1889f9a21c5e3 +styles_hash: 96cd3159bc3b002 diff --git a/src/tests/snapshots/gitu__tests__mouse_select_item.snap b/src/tests/snapshots/gitu__tests__mouse_select_item.snap index 0c37f6e71f..62a5aab872 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: 8f9c8d4f4dd18d1d +styles_hash: 47dabecbf8cc26c3 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 c95b13a427..57b1ee67ee 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: f009f3df6e96b387 +styles_hash: 756a2316769a9390 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 c95b13a427..57b1ee67ee 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: f009f3df6e96b387 +styles_hash: 756a2316769a9390 diff --git a/src/tests/snapshots/gitu__tests__mouse_show_item.snap b/src/tests/snapshots/gitu__tests__mouse_show_item.snap index f426e1ea73..644bd38836 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: 3185110292c06b5 +styles_hash: aa867385650c4035 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 566681b910..84fcd17ed9 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: 7e3ac79a4b170e10 +styles_hash: ad7a877442acc5a7 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 f96249b73e..b375c732a7 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: 568f3653bfca7d79 +styles_hash: 581a108fde4c40fe 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 19b2173b4b..af7fc1c057 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: f4a20c3f7a22b228 +styles_hash: f0f5b789b0d8de8f diff --git a/src/tests/snapshots/gitu__tests__moved_file.snap b/src/tests/snapshots/gitu__tests__moved_file.snap index 95f6295abb..4f1b217b41 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: 855dd9b18dffce0b +styles_hash: 43a9ff7990a714d diff --git a/src/tests/snapshots/gitu__tests__new_commit.snap b/src/tests/snapshots/gitu__tests__new_commit.snap index e0837cea63..d65de6c990 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: d40283e3b99b6eb1 +styles_hash: e010edc5475641a diff --git a/src/tests/snapshots/gitu__tests__new_file.snap b/src/tests/snapshots/gitu__tests__new_file.snap index 92f335c7d7..4af855dd26 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: 3149240f1bb20502 +styles_hash: 303d1d0cfdc63762 diff --git a/src/tests/snapshots/gitu__tests__non_ascii_filename.snap b/src/tests/snapshots/gitu__tests__non_ascii_filename.snap index e87c8e8134..588ab7a999 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: bb9ed5a655f91028 +styles_hash: e79b629595dfd37f 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 241be74135..e2c0f0679e 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: baa329f6340fcc8b +styles_hash: d9bb74cb0cca9527 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 82561e9ed8..3038a069bb 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 @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Select remote: › | -styles_hash: a2a72e20bfcc2997 +? Select remote: › █ | +styles_hash: b7603d8a82add7a 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 2d610f01ca..41270eb00a 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 @@ p from origin -r Rebase local commits (--rebase) u from origin/main | e from elsewhere | q/esc Quit/Close | -styles_hash: 6224ed56a73be11f +styles_hash: 3027cb042fe9a1d0 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 a64e67ff85..d7b188f346 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 @@ p pushRemote, setting that -r Rebase local commits (--rebase) u upstream, setting that | e from elsewhere | q/esc Quit/Close | -styles_hash: 9ca8480d57b593bd +styles_hash: 6a144bb31128aeb1 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 2f8cf2cc6d..0a6bd9c360 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: a7f12e4c3c38781e +styles_hash: f9d189937faea4eb 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 af099fc425..5ae567395f 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 @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Set pushRemote then pull: › | -styles_hash: e0d524e635f78ab7 +? Set pushRemote then pull: › █ | +styles_hash: 5828014e9fd4808 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 2d610f01ca..41270eb00a 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 @@ p from origin -r Rebase local commits (--rebase) u from origin/main | e from elsewhere | q/esc Quit/Close | -styles_hash: 6224ed56a73be11f +styles_hash: 3027cb042fe9a1d0 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 164aa959a9..63a70134ac 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 @@ p pushRemote, setting that -r Rebase local commits (--rebase) u from main | e from elsewhere | q/esc Quit/Close | -styles_hash: bef082d2a2b28eea +styles_hash: 6020718096514b1e 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 3a05dda5e3..7b522b8b6d 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 @@ q/esc Quit/Close ────────────────────────────────────────────────────────────────────────────────| $ git branch --set-upstream-to new-branch | warning: not setting branch 'new-branch' as its own upstream | -styles_hash: d752193435beaf2d +styles_hash: e439852a8290f159 diff --git a/src/tests/snapshots/gitu__tests__pull__pull_upstream.snap b/src/tests/snapshots/gitu__tests__pull__pull_upstream.snap index 1582b8d492..173f8bef9e 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: 5cab1b81bd346c16 +styles_hash: 3a87960c5cb761f7 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 f50de6b495..feef0170fb 100644 --- a/src/tests/snapshots/gitu__tests__pull__pull_upstream_prompt.snap +++ b/src/tests/snapshots/gitu__tests__pull__pull_upstream_prompt.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Set upstream then pull: › | -styles_hash: 6165a658809718f7 +? Set upstream then pull: › █ | +styles_hash: d201a131f3b0935e diff --git a/src/tests/snapshots/gitu__tests__push__force_push.snap b/src/tests/snapshots/gitu__tests__push__force_push.snap index 5d2f5e6bbd..73ad7528d8 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: 346b2eb0e6fdb3f3 +styles_hash: d5b0d5a9c89ccdad 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 4ce3eb0e1e..929d0a049b 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 @@ p pushRemote, setting that -n Dry run (--dry-run) 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: 89f47c06e2e70e6e +styles_hash: 6d9e628a7afa6aca diff --git a/src/tests/snapshots/gitu__tests__push__push_elsewhere.snap b/src/tests/snapshots/gitu__tests__push__push_elsewhere.snap index a9ee81f9aa..bec0e1cc62 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: baa329f6340fcc8b +styles_hash: d9bb74cb0cca9527 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 e9e3310455..411b1f018f 100644 --- a/src/tests/snapshots/gitu__tests__push__push_elsewhere_prompt.snap +++ b/src/tests/snapshots/gitu__tests__push__push_elsewhere_prompt.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Select remote: › | -styles_hash: a2a72e20bfcc2997 +? Select remote: › █ | +styles_hash: b7603d8a82add7a 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 93ed3ea734..b8481ce453 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 @@ p to origin -n Dry run (--dry-run) 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: a32372d5cf9b0266 +styles_hash: 6ec7de5764acacd0 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 7c823d2588..a30931f2bd 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: c7567d04a81a5d8e +styles_hash: 9b3c7e4618819d11 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 eb2535b3f7..aacdae209b 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 @@ p pushRemote, setting that -n Dry run (--dry-run) 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: bf6efdfac4691f2c +styles_hash: 2c842d9c3cd6a103 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 639f3a5ff2..45645fc9d3 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: 8edd5c1754c00b3 +styles_hash: d9bb74cb0cca9527 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 5d20cb0c67..45fe8197e1 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 @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Set pushRemote then push: › | -styles_hash: 3978d3bb613672e +? Set pushRemote then push: › █ | +styles_hash: 9977843ef82f44ad 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 93ed3ea734..b8481ce453 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 @@ p to origin -n Dry run (--dry-run) 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: a32372d5cf9b0266 +styles_hash: 6ec7de5764acacd0 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 686b1bc2ff..95331cddc6 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 @@ p pushRemote, setting that -n Dry run (--dry-run) 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: 584d39e44699aa20 +styles_hash: 9ad82f6349fe2faa 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 0231387f4c..3cbe2d5ad9 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 @@ q/esc Quit/Close -h Disable hooks (--no-verify) ────────────────────────────────────────────────────────────────────────────────| $ git branch --set-upstream-to new-branch | warning: not setting branch 'new-branch' as its own upstream | -styles_hash: 87c187e06393231b +styles_hash: f2be455641044708 diff --git a/src/tests/snapshots/gitu__tests__push__push_upstream.snap b/src/tests/snapshots/gitu__tests__push__push_upstream.snap index c63c430487..6efa63fc2f 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: 4281674f50fbf56f +styles_hash: d5b0d5a9c89ccdad 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 1bc356fccc..0eef73aa1c 100644 --- a/src/tests/snapshots/gitu__tests__push__push_upstream_prompt.snap +++ b/src/tests/snapshots/gitu__tests__push__push_upstream_prompt.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Set upstream then push: › | -styles_hash: 6165a658809718f7 +? Set upstream then push: › █ | +styles_hash: d201a131f3b0935e diff --git a/src/tests/snapshots/gitu__tests__quit__confirm_quit.snap b/src/tests/snapshots/gitu__tests__quit__confirm_quit.snap index 6b903b5197..ab37e51ce0 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: 59b42b473ea2086a +styles_hash: f47a6512af0aca26 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 481d9458ce..67eb1655a6 100644 --- a/src/tests/snapshots/gitu__tests__quit__confirm_quit_prompt.snap +++ b/src/tests/snapshots/gitu__tests__quit__confirm_quit_prompt.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Really quit? (y or n) › | -styles_hash: fb6e2cdae8db6fc7 +? Really quit? (y or n) › █ | +styles_hash: c44975cc30a257c2 diff --git a/src/tests/snapshots/gitu__tests__quit__quit.snap b/src/tests/snapshots/gitu__tests__quit__quit.snap index 6b903b5197..ab37e51ce0 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: 59b42b473ea2086a +styles_hash: f47a6512af0aca26 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 6b903b5197..ab37e51ce0 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: 59b42b473ea2086a +styles_hash: f47a6512af0aca26 diff --git a/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere.snap b/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere.snap index 66eb5d2802..769a3fb85a 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: b7a28b018f24d4c7 +styles_hash: f558896d8243eec6 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 5b44efd4f6..c06dbf09d6 100644 --- a/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere_prompt.snap +++ b/src/tests/snapshots/gitu__tests__rebase__rebase_elsewhere_prompt.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Rebase onto: › | -styles_hash: ecb6e3980ac15247 +? Rebase onto: › █ | +styles_hash: 42ebf8ceab01de42 diff --git a/src/tests/snapshots/gitu__tests__rebase__rebase_menu.snap b/src/tests/snapshots/gitu__tests__rebase__rebase_menu.snap index b6a8303933..0593b7a96b 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 @@ q/esc Quit/Close -i Interactive (--interactive) -k Keep empty commits (--keep-empty) | -h Disable hooks (--no-verify) | -p Preserve merges (--preserve-merges) | -styles_hash: 571d8ea0d3ed08fa +styles_hash: 7891169c73fa64db diff --git a/src/tests/snapshots/gitu__tests__rebase_conflict.snap b/src/tests/snapshots/gitu__tests__rebase_conflict.snap index 5fba7b009c..63ae632b76 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: 14c8af588de8e27f +styles_hash: c444654cc76064bb 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 b010f6cf51..8b4bf0f4a4 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: 960194502264d5c0 +styles_hash: 4ff6b6bda1dfee35 diff --git a/src/tests/snapshots/gitu__tests__remote__add_remote.snap b/src/tests/snapshots/gitu__tests__remote__add_remote.snap index 3d7892ca72..851832f343 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: 7dd9a7306bc36098 +styles_hash: 70a67250e5c8bb24 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 a6845888c8..678c083bf2 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 @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Remote name: › | -styles_hash: 8f9bd9076e31127d +? Remote name: › █ | +styles_hash: df76e143d585df7f 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 223c45f5da..e2a35519f0 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 @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Remote url: › | -styles_hash: f34a849ca65fbdc8 +? Remote url: › █ | +styles_hash: ca14f6a6d46efb93 diff --git a/src/tests/snapshots/gitu__tests__remote__remote_menu.snap b/src/tests/snapshots/gitu__tests__remote__remote_menu.snap index cd6c88937c..df654a9c67 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 @@ a add remote K remove remote | r rename remote | q/esc Quit/Close | -styles_hash: c98599cbfe770e6 +styles_hash: 4591081cbd0c4c1c diff --git a/src/tests/snapshots/gitu__tests__remote__remove_remote.snap b/src/tests/snapshots/gitu__tests__remote__remove_remote.snap index 3daebc3560..137773de53 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: 5e18bafa3d84ff48 +styles_hash: c0c7b7ab92e41f28 diff --git a/src/tests/snapshots/gitu__tests__remote__rename_remote.snap b/src/tests/snapshots/gitu__tests__remote__rename_remote.snap index 85cd03c5a4..0c6476ec71 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: b8f048b49ddbac3f +styles_hash: 2326b8c7f666716 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 c1906b4816..45ff9c218f 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 @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Rename remote: › | -styles_hash: a2a72e20bfcc2997 +? Rename remote: › █ | +styles_hash: b7603d8a82add7a 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 18dc980a43..ad540c689c 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 @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Rename to: › | -styles_hash: 2723afb20d7e3ef0 +? Rename to: › █ | +styles_hash: 8502d7aed78c2353 diff --git a/src/tests/snapshots/gitu__tests__reset__reset_hard.snap b/src/tests/snapshots/gitu__tests__reset__reset_hard.snap index bceaf27258..8c9687079b 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: 59b42b473ea2086a +styles_hash: f47a6512af0aca26 diff --git a/src/tests/snapshots/gitu__tests__reset__reset_menu.snap b/src/tests/snapshots/gitu__tests__reset__reset_menu.snap index 40d46e60f3..53ac29e7f7 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 @@ s soft m mixed | h hard | q/esc Quit/Close | -styles_hash: cb2a2fb9e1ff99bd +styles_hash: 3c73d8c180901c8b diff --git a/src/tests/snapshots/gitu__tests__reset__reset_mixed.snap b/src/tests/snapshots/gitu__tests__reset__reset_mixed.snap index e7cee8e80f..a8a44d6470 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: 3149240f1bb20502 +styles_hash: 4738e02f19882d7d diff --git a/src/tests/snapshots/gitu__tests__reset__reset_soft.snap b/src/tests/snapshots/gitu__tests__reset__reset_soft.snap index 8c0e4c58b9..ecafabdce9 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: 30afab145e7cf548 +styles_hash: fef12cfe8789d4e2 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 f834ae3bfa..9016af568c 100644 --- a/src/tests/snapshots/gitu__tests__reset__reset_soft_prompt.snap +++ b/src/tests/snapshots/gitu__tests__reset__reset_soft_prompt.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Soft reset to (default b66a0bf82020d6a386e94d0fceedec1f817d20c7): › q | -styles_hash: 174798f428e40bd6 +? Soft reset to (default b66a0bf82020d6a386e94d0fceedec1f817d20c7): › q█ | +styles_hash: 98151016956b3b09 diff --git a/src/tests/snapshots/gitu__tests__revert_abort.snap b/src/tests/snapshots/gitu__tests__revert_abort.snap index 84a4d93d65..e417106421 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: 8a22cddba91f2be +styles_hash: 49d2be3918e808a2 diff --git a/src/tests/snapshots/gitu__tests__revert_commit.snap b/src/tests/snapshots/gitu__tests__revert_commit.snap index 2552c8c41b..51cb41871b 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 b66a0bf82020d6a386e94d0fceedec1f817d20c7 | -styles_hash: 9fae57feca90a6d2 +styles_hash: 5af553d45a099796 diff --git a/src/tests/snapshots/gitu__tests__revert_commit_prompt.snap b/src/tests/snapshots/gitu__tests__revert_commit_prompt.snap index bedc282d19..35edbfcb5c 100644 --- a/src/tests/snapshots/gitu__tests__revert_commit_prompt.snap +++ b/src/tests/snapshots/gitu__tests__revert_commit_prompt.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Revert commit (default b66a0bf82020d6a386e94d0fceedec1f817d20c7): › | -styles_hash: 78116180725b01d8 +? Revert commit (default b66a0bf82020d6a386e94d0fceedec1f817d20c7): › █ | +styles_hash: 1b3bd1bc54def860 diff --git a/src/tests/snapshots/gitu__tests__revert_conflict.snap b/src/tests/snapshots/gitu__tests__revert_conflict.snap index 39f697ff1f..119b9cba60 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: 14c8af588de8e27f +styles_hash: ce1bcac7e4255e31 diff --git a/src/tests/snapshots/gitu__tests__revert_menu.snap b/src/tests/snapshots/gitu__tests__revert_menu.snap index dbe6647a86..45c89df267 100644 --- a/src/tests/snapshots/gitu__tests__revert_menu.snap +++ b/src/tests/snapshots/gitu__tests__revert_menu.snap @@ -22,4 +22,4 @@ a Abort -e Edit commit message (--edit) 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: 67778fc6d28e9915 +styles_hash: eeaa856ddc6c6827 diff --git a/src/tests/snapshots/gitu__tests__show.snap b/src/tests/snapshots/gitu__tests__show.snap index 24aaaba40a..5d12863fc6 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: 4f7a8fcd217ee770 +styles_hash: cbb15275b9e6a12b 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 64acbb06a4..de75ad4b41 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: fd8cb7fb62be808a +styles_hash: 6814955082265cab 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 73283b4d4d..225fa1db19 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: 76eeb3af62854e8 +styles_hash: c34389d771bd369f 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 3fa7382e8a..b4c796eb25 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: fd8cb7fb62be808a +styles_hash: 6814955082265cab diff --git a/src/tests/snapshots/gitu__tests__show_stash.snap b/src/tests/snapshots/gitu__tests__show_stash.snap index 0c53e3788c..349b11be5f 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() | | | -styles_hash: 15f81f0e4dd370bc +styles_hash: 21974436519d24b8 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 45d9227784..748d649068 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: a66d38a1027e36cc +styles_hash: 8f33976e58360b2 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 66b1b4f042..2f55dab811 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: 14ecc9c042c43798 +styles_hash: c0dabf2567795f89 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 59a36175ae..a8a379901e 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: 248ff882c842b9ec +styles_hash: c31f24a08945591f 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 944150cb04..b61b5c0078 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: a4f6cab1c185980d +styles_hash: 6e23db6ecca0d933 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 a1e9061c77..687aa4d358 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: 88290640815df291 +styles_hash: 68d401347cf4027c diff --git a/src/tests/snapshots/gitu__tests__stage__staged_file.snap b/src/tests/snapshots/gitu__tests__stage__staged_file.snap index 5a7e9f4cd8..bfdc7b1d3a 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: 30afab145e7cf548 +styles_hash: e95ba86e6653e5f8 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 5583ec0c30..89060822e0 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: 7fc6db2fc4baba25 +styles_hash: 935b2d670a800431 diff --git a/src/tests/snapshots/gitu__tests__stash__stash.snap b/src/tests/snapshots/gitu__tests__stash__stash.snap index 96a03efbf7..b5dec35f53 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: a21f2b277eae9406 +styles_hash: 64b7b1b4e5d072b3 diff --git a/src/tests/snapshots/gitu__tests__stash__stash_apply.snap b/src/tests/snapshots/gitu__tests__stash__stash_apply.snap index d442f433d4..8ca251dd91 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: 5f6c840650f2861 +styles_hash: 5513120a2b004bfb 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 e00ab23a85..02c19b9a46 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: 3fed1151179f36db +styles_hash: e798e433d6f3685a 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 b75e7a52e2..2d286ff76c 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_apply_prompt.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_apply_prompt.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Apply stash (default 0): › | -styles_hash: 3e6073d833eb8d18 +? Apply stash (default 0): › █ | +styles_hash: ffc0b16e73958522 diff --git a/src/tests/snapshots/gitu__tests__stash__stash_drop.snap b/src/tests/snapshots/gitu__tests__stash__stash_drop.snap index 8b83d8fe0e..08c8e90363 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: dfd2a495b8602e3f +styles_hash: 64b7b1b4e5d072b3 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 cb0e99f4b6..25ebe7f13e 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: dfd2a495b8602e3f +styles_hash: 64b7b1b4e5d072b3 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 7d3f51f927..2f320e132f 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_drop_prompt.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_drop_prompt.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Drop stash (default 0): › | -styles_hash: 287ea763ee9469c8 +? Drop stash (default 0): › █ | +styles_hash: 58ddaedd485d843a diff --git a/src/tests/snapshots/gitu__tests__stash__stash_index.snap b/src/tests/snapshots/gitu__tests__stash__stash_index.snap index b37d19d16f..3f2b05c11a 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: 1d8668271ca8912a +styles_hash: b7ab65dc1bdc1391 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 cd580392c0..d2690c6bd1 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_index_prompt.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_index_prompt.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Stash message: › | -styles_hash: 5ffb39001f9b126a +? Stash message: › █ | +styles_hash: 13c0fe61177c7d7a 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 3c18a4b77a..dcc692837d 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: 47b6f234256a56ab +styles_hash: 6dc541318b02a92c 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 cd580392c0..d2690c6bd1 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 @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Stash message: › | -styles_hash: 5ffb39001f9b126a +? Stash message: › █ | +styles_hash: 13c0fe61177c7d7a diff --git a/src/tests/snapshots/gitu__tests__stash__stash_menu.snap b/src/tests/snapshots/gitu__tests__stash__stash_menu.snap index b84aed3505..1af1de33d7 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 @@ x keeping index p pop | k drop | q/esc Quit/Close | -styles_hash: bd7d338934b4927 +styles_hash: 49f08ee1bb15ee78 diff --git a/src/tests/snapshots/gitu__tests__stash__stash_pop.snap b/src/tests/snapshots/gitu__tests__stash__stash_pop.snap index 257a11baf9..d257fe26ee 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: fd87490bbbf7d065 +styles_hash: 28cfeb6aac16c0d6 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 dda9bcb480..70358fdc8a 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: 331238665090bd8c +styles_hash: b7ab65dc1bdc1391 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 f7057e553f..3dbf539992 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_pop_prompt.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_pop_prompt.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Pop stash (default 0): › | -styles_hash: fdfb8ed36c86fc3a +? Pop stash (default 0): › █ | +styles_hash: ab14f94e0e2a2d9c diff --git a/src/tests/snapshots/gitu__tests__stash__stash_prompt.snap b/src/tests/snapshots/gitu__tests__stash__stash_prompt.snap index cd580392c0..d2690c6bd1 100644 --- a/src/tests/snapshots/gitu__tests__stash__stash_prompt.snap +++ b/src/tests/snapshots/gitu__tests__stash__stash_prompt.snap @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Stash message: › | -styles_hash: 5ffb39001f9b126a +? Stash message: › █ | +styles_hash: 13c0fe61177c7d7a 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 8f9702e3f8..68439cf527 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: 6973fd54b1052e05 +styles_hash: 4d8bdf73e41baee1 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 cd580392c0..d2690c6bd1 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 @@ -21,5 +21,5 @@ expression: ctx.redact_buffer() | | ────────────────────────────────────────────────────────────────────────────────| -? Stash message: › | -styles_hash: 5ffb39001f9b126a +? Stash message: › █ | +styles_hash: 13c0fe61177c7d7a 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 04be9840b0..78133b8188 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: 63b511dc3e3d43c1 +styles_hash: 1a2f49bd66d76e0a 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 96a03efbf7..b5dec35f53 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: a21f2b277eae9406 +styles_hash: 64b7b1b4e5d072b3 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 ab4f88469c..f39470ea1b 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: be60d6ae62d5558f +styles_hash: d4182dc7cc4ac7f6 diff --git a/src/tests/snapshots/gitu__tests__syntax_highlighted.snap b/src/tests/snapshots/gitu__tests__syntax_highlighted.snap index 209d71dbd9..c6cb40f78a 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: a795097b9c1e11f1 +styles_hash: 1b0c71337d9d805a diff --git a/src/tests/snapshots/gitu__tests__tab_diff.snap b/src/tests/snapshots/gitu__tests__tab_diff.snap index a60ac73386..c6ae6c2b13 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: b244c3166dabf67c +styles_hash: 4db1a6e61728c6f7 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 b8344f398a..e25c7008bb 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: 6603406d0ed9d8ed +styles_hash: 84c84973f043dd86 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 644295430a..3b7ef4363a 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: b7defc366cd4e381 +styles_hash: 3abc64b3780ed793 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 751da997ee..d4189c8675 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: 17e7c36bfddddbc8 +styles_hash: 38184b23b962c7f9 diff --git a/src/tests/snapshots/gitu__tests__unstaged_changes.snap b/src/tests/snapshots/gitu__tests__unstaged_changes.snap index efe87d17ec..82e45f8fb6 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: a4f6cab1c185980d +styles_hash: 6e23db6ecca0d933 diff --git a/src/tests/snapshots/gitu__tests__updated_externally.snap b/src/tests/snapshots/gitu__tests__updated_externally.snap index 82efd259e6..7a9179b46a 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: 7b4df661210d46 +styles_hash: d61e94830ad618a5 diff --git a/src/ui.rs b/src/ui.rs index a7227c8315..5ea5be773c 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,106 +1,140 @@ +use std::borrow::Cow; + use crate::app::State; +use crate::screen; +use crate::ui::layout::LayoutItem; +use itertools::Itertools; +use layout::LayoutTree; +use layout::OPTS; use ratatui::Frame; use ratatui::prelude::*; use ratatui::style::Stylize; -use ratatui::widgets::*; -use std::sync::Arc; use tui_prompts::State as _; -use tui_prompts::TextPrompt; +use unicode_segmentation::UnicodeSegmentation; +pub(crate) mod layout; mod menu; -pub(crate) struct SizedWidget { - height: u16, - widget: W, +const CARET: &str = "\u{2588}"; +const DASHES: &str = "────────────────────────────────────────────────────────────────"; +const STYLE: Style = Style { + fg: None, + bg: None, + underline_color: None, + add_modifier: Modifier::DIM, + sub_modifier: Modifier::empty(), +}; + +pub(crate) type UiTree<'a> = LayoutTree<(Cow<'a, str>, Style)>; + +pub(crate) fn ui(frame: &mut Frame, state: &mut State) { + let size = frame.area().as_size(); + let mut layout = UiTree::new(); + + layout.vertical(None, OPTS, |layout| { + layout.vertical(None, OPTS.grow(), |layout| { + screen::layout_screen(layout, size, state.screens.last().unwrap()); + }); + + layout.vertical(None, OPTS, |layout| { + menu::layout_menu(layout, state, size.width as usize); + layout_command_log(layout, state, size.width as usize); + layout_prompt(layout, state, size.width as usize); + }); + }); + + layout.compute([frame.area().width, frame.area().height]); + + for item in layout.iter() { + let LayoutItem { data, pos, size } = item; + let area = Rect::new(pos[0], pos[1], size[0], size[1]); + let (text, style) = data; + frame.render_widget(SpanRef(text, *style), area); + } + + layout.clear(); + + state.screens.last_mut().unwrap().size = frame.area().as_size(); } -impl Widget for SizedWidget { +struct SpanRef<'a>(&'a Cow<'a, str>, Style); + +impl<'a> Widget for SpanRef<'a> { fn render(self, area: Rect, buf: &mut Buffer) { - self.widget.render(area, buf); + let SpanRef(text, style) = self; + buf.set_string(area.x, area.y, text, style); } } -impl StatefulWidget for SizedWidget { - type State = W::State; - - fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) { - self.widget.render(area, buf, state); +fn layout_command_log<'a>(layout: &mut UiTree<'a>, state: &State, width: usize) { + if !state.current_cmd_log.is_empty() { + repeat_chars(layout, width, DASHES, STYLE); + layout_text(layout, state.current_cmd_log.format_log(&state.config)); } } -pub(crate) fn ui(frame: &mut Frame, state: &mut State) { - let maybe_log = if !state.current_cmd_log.is_empty() { - let text: Text = state.current_cmd_log.format_log(&state.config); - - Some(SizedWidget { - widget: Paragraph::new(text.clone()).block(popup_block()), - height: 1 + text.lines.len() as u16, - }) - } else { - None +fn layout_prompt<'a>(layout: &mut UiTree<'a>, state: &'a State, width: usize) { + let Some(ref prompt_data) = state.prompt.data else { + return; }; - let maybe_prompt = state.prompt.data.as_ref().map(|prompt_data| SizedWidget { - height: 2, - widget: TextPrompt::new(prompt_data.prompt_text.clone()).with_block(popup_block()), + let prompt_symbol = state.prompt.state.status().symbol(); + + repeat_chars(layout, width, DASHES, STYLE); + layout.horizontal(None, OPTS, |layout| { + layout_span(layout, (prompt_symbol.content, prompt_symbol.style)); + layout_span(layout, (" ".into(), Style::new())); + layout_span( + layout, + (prompt_data.prompt_text.as_ref().into(), Style::new()), + ); + layout_span(layout, (" › ".into(), Style::new().cyan().dim())); + layout_span(layout, (state.prompt.state.value().into(), Style::new())); + layout_span(layout, (CARET.into(), Style::new())); }); +} - let maybe_menu = state.pending_menu.as_ref().and_then(|menu| { - if menu.is_hidden { - None - } else { - Some(menu::MenuWidget::new( - Arc::clone(&state.config), - menu, - state.screens.last().unwrap().get_selected_item(), - state, - )) +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); } }); - - let layout = Layout::new( - Direction::Vertical, - [ - Constraint::Min(1), - widget_height(&maybe_prompt), - widget_height(&maybe_menu), - widget_height(&maybe_log), - ], - ) - .split(frame.area()); - - frame.render_widget(state.screens.last().unwrap(), layout[0]); - - maybe_render(maybe_menu, frame, layout[2]); - maybe_render(maybe_log, frame, layout[3]); - - if let Some(prompt) = maybe_prompt { - frame.render_stateful_widget(prompt, layout[1], &mut state.prompt.state); - let (cx, cy) = state.prompt.state.cursor(); - frame.set_cursor_position((cx, cy)); - } - - state.screens.last_mut().unwrap().size = layout[0].as_size(); } -fn popup_block() -> Block<'static> { - Block::new() - .borders(Borders::TOP) - .border_style(Style::new().dim()) - .border_type(ratatui::widgets::BorderType::Plain) +pub(crate) fn layout_line<'a>(layout: &mut UiTree<'a>, line: Line<'a>) { + layout.horizontal(None, OPTS, |layout| { + for span in line { + layout_span(layout, (span.content, span.style)); + } + }); } -fn widget_height(maybe_prompt: &Option>) -> Constraint { - Constraint::Length( - maybe_prompt - .as_ref() - .map(|widget| widget.height) - .unwrap_or(0), - ) +pub(crate) fn layout_span<'a>(layout: &mut UiTree<'a>, span: (Cow<'a, str>, Style)) { + let width = span.0.graphemes(true).count() as u16; + layout.leaf_with_size(span, [width, 1]); } -fn maybe_render(maybe_menu: Option>, frame: &mut Frame, area: Rect) { - if let Some(menu) = maybe_menu { - frame.render_widget(menu, area); - } +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; + let partial = count % grapheme_count; + + layout.horizontal(None, OPTS, |layout| { + for _ in 0..full { + layout_span(layout, (chars.into(), style)); + } + + if partial > 0 { + let end = chars + .grapheme_indices(true) + .tuple_windows() + .take(partial) + .last() + .map(|((_, _), (end, _))| end) + .unwrap_or(chars.len()); + + layout_span(layout, (chars[..end].into(), style)); + } + }); } diff --git a/src/ui/layout/direction.rs b/src/ui/layout/direction.rs new file mode 100644 index 0000000000..a83991be78 --- /dev/null +++ b/src/ui/layout/direction.rs @@ -0,0 +1,16 @@ +use super::vec2::Vec2; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Direction { + Horizontal, + Vertical, +} + +impl Direction { + pub(crate) fn axis(&self) -> Vec2 { + match self { + Direction::Horizontal => Vec2(1, 0), + Direction::Vertical => Vec2(0, 1), + } + } +} diff --git a/src/ui/layout/mod.rs b/src/ui/layout/mod.rs new file mode 100644 index 0000000000..ee9fe67b0d --- /dev/null +++ b/src/ui/layout/mod.rs @@ -0,0 +1,715 @@ +mod direction; +mod node; +mod vec2; + +use std::iter; + +use unicode_segmentation::UnicodeSegmentation; + +use direction::Direction; +use node::*; +use vec2::Vec2; + +pub use node::OPTS; + +const ROOT_INDEX: usize = usize::MAX; + +#[derive(Debug)] +pub struct LayoutTree { + data: Vec>, + index: TreeIndex, +} + +#[derive(Debug)] +pub(crate) struct TreeIndex { + parents: Vec, + current_parent: usize, +} + +impl TreeIndex { + pub(crate) fn new() -> Self { + TreeIndex { + parents: Vec::new(), + current_parent: ROOT_INDEX, + } + } + + pub(crate) fn iter_roots(&self) -> impl Iterator { + self.parents + .first() + .map(|_node| 0) + .into_iter() + .chain(self.iter_siblings_after(0)) + } + + pub(crate) fn iter(&self) -> impl Iterator { + 0..self.parents.len() + } + + pub(crate) fn iter_siblings_after(&self, index: usize) -> impl Iterator { + let start = index + 1; + let parent_index = self.parents[index]; + + self.parents[start..] + .iter() + .take_while(move |&&parent| parent >= parent_index) + .enumerate() + .filter(move |&(_i, &parent)| parent == parent_index) + .map(move |(i, _depth)| start + i) + } + + pub(crate) fn iter_children(&self, index: usize) -> impl Iterator { + let start = index + 1; + + self.parents[start..] + .iter() + .take_while(move |&&parent| parent >= index) + .enumerate() + .filter(move |&(_i, &parent)| parent == index) + .map(move |(i, _depth)| start + i) + } + + #[allow(dead_code)] + pub(crate) fn iter_all_children(&self, index: usize) -> impl Iterator { + let start = index + 1; + + self.parents[start..] + .iter() + .take_while(move |&&parent| parent >= index) + .enumerate() + .map(move |(i, _depth)| start + i) + } +} + +impl LayoutTree { + pub fn new() -> Self { + LayoutTree { + data: Vec::new(), + index: TreeIndex::new(), + } + } + + pub fn clear(&mut self) { + self.data.clear(); + self.index.parents.clear(); + self.index.current_parent = ROOT_INDEX; + } + + pub(crate) fn add(&mut self, data: Node) { + self.data.push(data); + self.index.parents.push(self.index.current_parent); + } + + pub(crate) fn add_with_children(&mut self, data: Node, insert_fn: F) { + self.add(data); + let our_parent = self.index.current_parent; + self.index.current_parent = self.index.parents.len() - 1; + + insert_fn(self); + + self.index.current_parent = our_parent; + } +} + +impl Default for LayoutTree { + fn default() -> Self { + Self::new() + } +} + +impl LayoutTree<&'static str> { + /// Add a text leaf, calculating size based on string length + #[allow(dead_code)] + pub fn text(&mut self, text: &'static str) -> &mut Self { + let width = text.graphemes(true).count(); + self.leaf_with_size(text, [width as u16, 1]); + self + } +} + +impl LayoutTree { + pub fn horizontal)>( + &mut self, + data: Option, + opts: Opts, + layout_fn: F, + ) -> &mut Self { + { + let ode = node::Node { + data, + opts: Opts { + dir: Direction::Horizontal, + ..opts + }, + size: Vec2(0, 0), + pos: None, + }; + + self.add_with_children(ode, layout_fn); + self + } + } + + pub fn vertical)>( + &mut self, + data: Option, + opts: Opts, + layout_fn: F, + ) -> &mut Self { + { + let node = node::Node { + data, + opts: Opts { + dir: Direction::Vertical, + ..opts + }, + size: Vec2(0, 0), + pos: None, + }; + + self.add_with_children(node, layout_fn); + self + } + } + + #[allow(dead_code)] + pub fn leaf(&mut self, data: T) -> &mut Self { + self.leaf_with_size(data, [1, 1]) + } + + pub fn leaf_with_size(&mut self, data: T, size: [u16; 2]) -> &mut Self { + self.add(node::Node { + data: Some(data), + opts: OPTS, + size: size.into(), + pos: None, + }); + + self + } + + pub fn compute(&mut self, avail_size: [u16; 2]) { + let Some(root) = self.index.iter_roots().next() else { + panic!("no root"); + }; + + let size = Vec2::from(avail_size); + self.compute_subtree(root, Vec2(0, 0), size, Vec2(0, 0), Sizing::Fit); + + let grow = Vec2::from(avail_size).saturating_sub(self.data[root].size); + self.compute_subtree(root, Vec2(0, 0), avail_size.into(), grow, Sizing::Flex); + } + + fn compute_subtree( + &mut self, + parent: usize, + start: Vec2, + avail_size: Vec2, + parent_grow: Vec2, + pass: Sizing, + ) { + let Some(child) = self.index.iter_children(parent).next() else { + return; + }; + + let Opts { + dir, gap, sizing, .. + } = self.data[parent].opts; + + let mut current_child = Some(child); + let mut cursor = Vec2(0, 0); + let mut size = Vec2(0, 0); + let mut grow_iter = self.iter_distribute_size(parent, parent_grow, dir); + + while let Some(child) = current_child { + let child_grow = grow_iter.next().unwrap(); + let child_avail_size = + if pass == Sizing::Flex && self.data[child].opts.sizing == Sizing::Flex { + self.data[child].size + child_grow + } else { + avail_size.saturating_sub(cursor) + }; + + self.compute_subtree(child, start + cursor, child_avail_size, child_grow, pass); + + let child_data = &mut self.data[child]; + + if (cursor + child_data.size).fits(avail_size) { + child_data.pos = Some(start + cursor); + } else { + // Child doesn't fit where cursor currently is + // TODO Uncomment to include wrapping (tests below) + // // Try wrapping to next line/column first + // let next_line = size * dir.axis().flip(); + + // if (next_line + child_data.size).fits(avail_size) { + // // Fits completely on next line + // cursor = next_line; + // child_data.pos = Some(start + cursor); + // } else + + if (cursor + Vec2(1, 1)).fits(avail_size) { + // Can't wrap, but we can fit at least one cell where the cursor currently is + child_data.pos = Some(start + cursor); + child_data.size = child_data.size.min(avail_size.saturating_sub(cursor)); + } else { + // There's absolutely no room left anywhere + child_data.pos = None; + } + } + + size = size.max(cursor + child_data.size); + cursor += dir.axis() * (Vec2(gap, gap) + child_data.size); + + current_child = self.index.iter_siblings_after(child).next(); + } + + if pass == Sizing::Flex && sizing == Sizing::Flex { + self.data[parent].size += parent_grow; + } else if pass == Sizing::Fit && sizing == Sizing::Flex { + // Zero-out the axis that is supposed to grow + self.data[parent].size = size * dir.axis().flip(); + } else { + self.data[parent].size = size; + } + } + + fn iter_distribute_size( + &self, + parent: usize, + size_to_distribute: Vec2, + dir: Direction, + ) -> impl Iterator + use { + let along_axis = size_to_distribute * dir.axis(); + let div = if along_axis != Vec2(0, 0) { + self.index + .iter_children(parent) + .filter(|&child| self.data[child].opts.sizing == Sizing::Flex) + .count() + .max(1) as u16 + } else { + 1 + }; + + let quot = along_axis / Vec2(div, div); + let rem = along_axis % Vec2(div, div); + let off_axis_amount = size_to_distribute * dir.axis().flip(); + iter::once(quot + rem + off_axis_amount).chain(iter::once(quot + off_axis_amount).cycle()) + } + + pub fn iter(&self) -> impl Iterator> { + self.index.iter().filter_map(|index| { + let Node { + data: Some(data), + opts: _, + size, + pos, + } = &self.data[index] + else { + return None; + }; + + Some(LayoutItem { + data, + pos: (*pos)?.into(), + size: (*size).into(), + }) + }) + } +} + +#[derive(Debug)] +pub struct LayoutItem { + pub data: T, + pub pos: [u16; 2], + pub size: [u16; 2], +} + +#[cfg(test)] +mod tests { + use itertools::Itertools; + + use super::*; + + /// Render the layout to a string for testing purposes. + /// Note: ASCII only — does not support Unicode beyond single-byte chars. + fn render_to_string(layout: LayoutTree<&'static str>) -> String { + let Some(root) = layout.index.iter_roots().next() else { + panic!("no root"); + }; + + let node = &layout.data[root]; + let width = node.size.0 as usize; + let height = node.size.1 as usize; + + let mut grid = vec![' '; height * width]; + + for LayoutItem { data, pos, size } in layout.iter() { + let x0 = pos[0] as usize; + let y0 = pos[1] as usize; + let item_width = size[0] as usize; + + for (i, c) in data.chars().take(item_width).enumerate() { + grid[y0 * width + (x0 + i)] = c; + } + } + + grid.chunks(width) + .map(|row| row.iter().collect::().trim_end().to_string()) + .join("\n") + } + + #[test] + fn single_text() { + let mut layout = LayoutTree::new(); + + layout.vertical(None, OPTS, |layout| { + layout.text("Hello"); + layout.text("lol"); + }); + + layout.compute([5, 2]); + insta::assert_snapshot!(render_to_string(layout)); + } + + #[test] + fn horizontal_layout() { + let mut layout = LayoutTree::new(); + + layout.horizontal(None, OPTS, |layout| { + layout.text("A"); + layout.text("BB"); + layout.text("CCC"); + }); + + layout.compute([6, 1]); + insta::assert_snapshot!(render_to_string(layout)); + } + + #[test] + fn vertical_layout() { + let mut layout = LayoutTree::new(); + + layout.vertical(None, OPTS, |layout| { + layout.text("First"); + layout.text("Second"); + layout.text("Third"); + }); + + layout.compute([6, 3]); + insta::assert_snapshot!(render_to_string(layout)); + } + + #[test] + fn nested_layouts() { + let mut layout = LayoutTree::new(); + + layout.horizontal(None, OPTS, |layout| { + // 0 + layout.vertical(None, OPTS, |layout| { + // 1 + layout.text("A"); // 2 + layout.text("B"); // 3 + }); + layout.vertical(None, OPTS, |layout| { + // 4 + layout.text("C"); // 5 + layout.text("D"); // 6 + }); + }); + + layout.compute([2, 2]); + insta::assert_snapshot!(render_to_string(layout)); + } + + #[test] + fn clear_layout() { + let mut layout = LayoutTree::new(); + + layout.text("Test"); + + layout.clear(); + assert_eq!(layout.iter().count(), 0); + } + + #[test] + fn out_of_bounds_horizontal() { + let mut layout = LayoutTree::new(); + + layout.vertical(None, OPTS, |layout| { + layout.horizontal(None, OPTS, |layout| { + layout.text("12345"); + layout.text("The very start of this will be visible (a T)"); + }); + layout.horizontal(None, OPTS, |layout| { + layout.text("123456"); + layout.text("This is completely outside of the layout and ignored"); + }); + }); + + layout.compute([6, 4]); + insta::assert_snapshot!(render_to_string(layout)); + } + + // TODO wrapping test (code commented above) + // #[test] + // fn test_horizontal_wrap() { + // let mut layout = LayoutTree::new(); + + // layout.horizontal(None, OPTS, |layout| { + // layout.text("AAA"); + // layout.text("BBB"); + // layout.text("CCC"); + // }); + + // layout.compute([6, 2]); + // let result = render_to_string(layout); + // println!("Result:\n{}", result); + // // Should wrap: "AAABBB" on first line, "CCC" on second line + // assert_eq!(result, "AAABBB\nCCC"); + // } + + // TODO wrapping test (code commented above) + // #[test] + // fn test_wrap_before_truncate() { + // let mut layout = LayoutTree::new(); + + // layout.horizontal(None, OPTS, |layout| { + // layout.text("AAAA"); + // layout.text("BBBB"); + // }); + + // layout.compute([6, 2]); + // let result = render_to_string(layout); + // println!("Result:\n{}", result); + // // With 6 chars width and 2 rows: + // // "AAAA" fits (4 chars), then "BBBB" doesn't fit in remaining 2 chars + // // Should wrap "BBBB" to next line rather than truncating to "BB" + // assert_eq!(result, "AAAA\nBBBB"); + // } + + #[test] + fn test_no_trailing_newline() { + let mut layout = LayoutTree::new(); + + layout.vertical(None, OPTS, |layout| { + layout.text("Line 1"); + layout.text("Line 2"); + }); + + layout.compute([10, 2]); + let result = render_to_string(layout); + println!("Result bytes: {:?}", result.as_bytes()); + println!("Result repr: {:?}", result); + // Should not have trailing newline + assert!(!result.ends_with('\n'), "Should not have trailing newline"); + assert_eq!(result, "Line 1\nLine 2"); + } + + #[test] + fn out_of_bounds_vertical() { + let mut layout = LayoutTree::new(); + + layout.horizontal(None, OPTS, |layout| { + layout.vertical(None, OPTS, |layout| { + layout.text("1"); + layout.text("2"); + }); + layout.vertical(None, OPTS, |layout| { + layout.text("1"); + layout.text("2"); + layout.text("X"); + }); + }); + + layout.compute([2, 2]); + insta::assert_snapshot!(render_to_string(layout)); + } + + #[test] + fn unicode_text_width() { + let mut layout = LayoutTree::new(); + + layout.horizontal(None, OPTS, |layout| { + layout.text("café").text("naïve"); + }); + + layout.compute([10, 1]); + let items: Vec<_> = layout.iter().collect(); + assert_eq!(items[0].size, [4, 1]); // café has 4 graphemes + } + + #[test] + fn horizontal_gap() { + let mut layout = LayoutTree::new(); + + layout.horizontal(None, OPTS.gap(2), |layout| { + layout.text("one"); + layout.text("two"); + }); + + layout.compute([8, 1]); + insta::assert_snapshot!(render_to_string(layout)); + } + + #[test] + fn vertical_gap() { + let mut layout = LayoutTree::new(); + + layout.vertical(None, OPTS.gap(1), |layout| { + layout.text("one"); + layout.text("two"); + }); + + layout.compute([3, 3]); + insta::assert_snapshot!(render_to_string(layout)); + } + + #[test] + fn grow() { + let mut layout = LayoutTree::new(); + + layout.vertical(None, OPTS, |layout| { + layout.vertical(None, OPTS.grow(), |layout| { + layout.text("flex"); + }); + layout.text("actual"); + }); + + layout.compute([8, 3]); + insta::assert_snapshot!(render_to_string(layout)); + } + + #[test] + fn overflow() { + let mut layout = LayoutTree::new(); + + layout.vertical(None, OPTS, |layout| { + layout.text("one"); + layout.text("twoooo"); + }); + + layout.compute([20, 1]); + insta::assert_snapshot!(render_to_string(layout)); + } + + #[test] + fn shrink() { + let mut layout = LayoutTree::new(); + + layout.vertical(None, OPTS, |layout| { + layout.vertical(None, OPTS.grow(), |layout| { + layout.text("flex 1"); + layout.text("flex 2"); + }); + layout.text("actual"); + }); + + layout.compute([20, 2]); + insta::assert_snapshot!(render_to_string(layout)); + } + + #[test] + fn gitu_mockup() { + let mut layout = LayoutTree::new(); + + layout.vertical(None, OPTS, |layout| { + layout.vertical(None, OPTS.grow().gap(1), |layout| { + layout.vertical(None, OPTS, |layout| { + layout.text("On branch master"); + layout.vertical(None, OPTS, |layout| { + layout.text("Your branch is up to date with 'origin/master'"); + }); + }); + + layout.vertical(None, OPTS, |layout| { + layout.text("Recent commits"); + layout.vertical(None, OPTS, |layout| { + layout.text( + "9eb6a63 refactor/ui origin/refactor/ui fix more rendering issues", + ); + layout.text("b5fffd4 fix styling issues in Screen"); + layout.text("61e6c1b refactor: extract type of LayoutTree"); + layout.text("df3bcb5 get rid of frequent clone() in LayoutTree"); + layout.text("9864859 refactor(ui): less allocs"); + layout.text( + "aa2811e refactor: new LayoutTree module to improve on ui headaches", + ); + layout.text("5374ab3 master origin/master test: add file:// in clone_and_commit fn as well"); + layout.text("7a66235 test: get rid of setup_init, and try fix test-repo assertion"); + layout.text("75463c8 test/fix-ci test: forgot to create testfiles/ when running tests"); + }); + }); + }); + + layout.vertical(None, OPTS, |layout| { + layout.text("───────────────────────────────────────────────────────────────"); + + layout.horizontal(None, OPTS.gap(2), |layout| { + layout.vertical(None, OPTS, |layout| { + layout.text("Help"); + layout.text("Y Show Refs"); + layout.text(" Toggle section"); + layout.text("k/ Up "); + layout.text("j/ Down"); + layout.text("/ Up line"); + layout.text("/ Down line"); + layout.text("/ Prev section"); + layout.text("/ Next section"); + layout.text("/ Parent section"); + layout.text(" Half page up"); + layout.text(" Half page down"); + layout.text("g Refresh"); + layout.text("q/ Quit/Close"); + }); + layout.vertical(None, OPTS, |layout| { + layout.text("Submenu"); + layout.text("b Branch"); + layout.text("c Commit"); + layout.text("f Fetch"); + layout.text("h/? Help"); + layout.text("l Log"); + layout.text("M Remote"); + layout.text("F Pull"); + layout.text("P Push"); + layout.text("r Rebase"); + layout.text("X Reset"); + layout.text("V Revert"); + layout.text("z Stash"); + layout.text(""); + }); + layout.vertical(None, OPTS, |layout| { + layout.text("@@ -271,7 +271,7"); + layout.text("s Stage"); + layout.text("u Unstage"); + layout.text(" Show"); + layout.text("K Discard"); + layout.text(""); + layout.text(""); + layout.text(""); + layout.text(""); + layout.text(""); + layout.text(""); + layout.text(""); + layout.text(""); + layout.text(""); + }); + }); + }); + }); + + layout.compute([80, 25]); + let root = layout.index.iter_roots().next().unwrap(); + let root_size = layout.data[root].size; + eprintln!("Root size: {:?}", root_size); + let result = render_to_string(layout); + eprintln!("Result has {} lines", result.lines().count()); + eprintln!("Result ends with newline: {}", result.ends_with('\n')); + eprintln!("Result len: {}", result.len()); + eprintln!( + "Last 3 bytes: {:?}", + &result.as_bytes()[result.len().saturating_sub(3)..] + ); + insta::assert_snapshot!(result); + } +} diff --git a/src/ui/layout/node.rs b/src/ui/layout/node.rs new file mode 100644 index 0000000000..6453ebe07e --- /dev/null +++ b/src/ui/layout/node.rs @@ -0,0 +1,55 @@ +use super::vec2::Vec2; + +use super::direction::Direction; + +#[derive(Debug, PartialEq, Copy, Clone)] +pub enum Sizing { + Fit, + Flex, +} + +pub const OPTS: Opts = Opts { + dir: Direction::Horizontal, + gap: 0, + sizing: Sizing::Fit, +}; + +#[derive(Debug, Copy, Clone)] +pub struct Opts { + /// Layout direction for children of this node. + pub(crate) dir: Direction, + /// The space between each direct child of this node. + pub(crate) gap: u16, + pub(crate) sizing: Sizing, +} + +impl Default for Opts { + fn default() -> Self { + OPTS + } +} + +impl Opts { + pub fn gap(self, gap: u16) -> Self { + Self { gap, ..self } + } + + pub fn grow(self) -> Opts { + Self { + sizing: Sizing::Flex, + ..self + } + } +} + +#[derive(Debug)] +pub(crate) struct Node { + pub(crate) data: Option, + /// layout options + pub(crate) opts: Opts, + /// space actually occupied by this node, updated as nodes are added + pub(crate) size: Vec2, + /// Offset from parent's top-left corner, updated as nodes are added. + /// This will remain `None` if there's no valid position for the element. + pub(crate) pos: Option, +} diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__align_bottom.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__align_bottom.snap new file mode 100644 index 0000000000..ad05c79146 --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__align_bottom.snap @@ -0,0 +1,7 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- +Stack 1 + +Stack 2, bottom aligned diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__align_right.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__align_right.snap new file mode 100644 index 0000000000..be6d930fa4 --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__align_right.snap @@ -0,0 +1,5 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- + Aligned to the right diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__gitu_mockup.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__gitu_mockup.snap new file mode 100644 index 0000000000..3fd6f3cf24 --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__gitu_mockup.snap @@ -0,0 +1,29 @@ +--- +source: src/ui/layout/mod.rs +expression: result +--- +On branch master +Your branch is up to date with 'origin/master' + +Recent commits +9eb6a63 refactor/ui origin/refactor/ui fix more rendering issues +b5fffd4 fix styling issues in Screen +61e6c1b refactor: extract type of LayoutTree +df3bcb5 get rid of frequent clone() in LayoutTree +9864859 refactor(ui): less allocs +aa2811e refactor: new LayoutTree module to improve on ui headaches +─────────────────────────────────────────────────────────────── +Help Submenu @@ -271,7 +271,7 +Y Show Refs b Branch s Stage + Toggle section c Commit u Unstage +k/ Up f Fetch Show +j/ Down h/? Help K Discard +/ Up line l Log +/ Down line M Remote +/ Prev section F Pull +/ Next section P Push +/ Parent section r Rebase + Half page up X Reset + Half page down V Revert +g Refresh z Stash +q/ Quit/Close diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__grow.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__grow.snap new file mode 100644 index 0000000000..7b02ef6464 --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__grow.snap @@ -0,0 +1,7 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- +flex + +actual diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__horizontal_gap.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__horizontal_gap.snap new file mode 100644 index 0000000000..1d0a14bb7f --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__horizontal_gap.snap @@ -0,0 +1,5 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- +one two diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__horizontal_layout.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__horizontal_layout.snap new file mode 100644 index 0000000000..e7a68144fd --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__horizontal_layout.snap @@ -0,0 +1,5 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- +ABBCCC diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__nested_layouts.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__nested_layouts.snap new file mode 100644 index 0000000000..dd3a098c13 --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__nested_layouts.snap @@ -0,0 +1,6 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- +AC +BD diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_horizontal.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_horizontal.snap new file mode 100644 index 0000000000..2b5b1ebf1f --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_horizontal.snap @@ -0,0 +1,6 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- +12345T +123456 diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_horizontal_align_end.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_horizontal_align_end.snap new file mode 100644 index 0000000000..2b5b1ebf1f --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_horizontal_align_end.snap @@ -0,0 +1,6 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- +12345T +123456 diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_vertical.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_vertical.snap new file mode 100644 index 0000000000..1664321387 --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_vertical.snap @@ -0,0 +1,6 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- +11 +22 diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_vertical_align_end.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_vertical_align_end.snap new file mode 100644 index 0000000000..57ef6dbc11 --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__out_of_bounds_vertical_align_end.snap @@ -0,0 +1,6 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- +1 +2 diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__overflow.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__overflow.snap new file mode 100644 index 0000000000..7c57e88979 --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__overflow.snap @@ -0,0 +1,5 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- +one diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__shrink.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__shrink.snap new file mode 100644 index 0000000000..198c749b76 --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__shrink.snap @@ -0,0 +1,6 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- +flex 1 +actual diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__single_text.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__single_text.snap new file mode 100644 index 0000000000..012b79d553 --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__single_text.snap @@ -0,0 +1,6 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- +Hello +lol diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__stacked.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__stacked.snap new file mode 100644 index 0000000000..1d60b94344 --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__stacked.snap @@ -0,0 +1,5 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- +This is on top (leftovers here) diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__vertical_gap.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__vertical_gap.snap new file mode 100644 index 0000000000..06745729b5 --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__vertical_gap.snap @@ -0,0 +1,7 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- +one + +two diff --git a/src/ui/layout/snapshots/gitu__ui__layout__tests__vertical_layout.snap b/src/ui/layout/snapshots/gitu__ui__layout__tests__vertical_layout.snap new file mode 100644 index 0000000000..e8849ef2ff --- /dev/null +++ b/src/ui/layout/snapshots/gitu__ui__layout__tests__vertical_layout.snap @@ -0,0 +1,7 @@ +--- +source: src/ui/layout/mod.rs +expression: render_to_string(layout) +--- +First +Second +Third diff --git a/src/ui/layout/snapshots/layzer__tests__align_bottom.snap b/src/ui/layout/snapshots/layzer__tests__align_bottom.snap new file mode 100644 index 0000000000..edb54814c5 --- /dev/null +++ b/src/ui/layout/snapshots/layzer__tests__align_bottom.snap @@ -0,0 +1,7 @@ +--- +source: src/lib.rs +expression: render_to_string(layout) +--- +Stack 1 + +Stack 2, bottom aligned diff --git a/src/ui/layout/snapshots/layzer__tests__align_right.snap b/src/ui/layout/snapshots/layzer__tests__align_right.snap new file mode 100644 index 0000000000..2c6933403e --- /dev/null +++ b/src/ui/layout/snapshots/layzer__tests__align_right.snap @@ -0,0 +1,5 @@ +--- +source: src/lib.rs +expression: layout.render_to_string() +--- + Aligned to the right diff --git a/src/ui/layout/snapshots/layzer__tests__gitu_mockup.snap b/src/ui/layout/snapshots/layzer__tests__gitu_mockup.snap new file mode 100644 index 0000000000..261d0c16e2 --- /dev/null +++ b/src/ui/layout/snapshots/layzer__tests__gitu_mockup.snap @@ -0,0 +1,34 @@ +--- +source: src/lib.rs +expression: render_to_string(layout) +--- +On branch master +Your branch is up to date with 'origin/master' + +Recent commits +b3492a8 master origin/master chore: update dependencies +013844c refactor: appease linter +5536ea3 feat: Show the diff on the stash detail screen + + + + + + + + +─────────────────────────────────────────────────────────────── +Help Submenu @@ -271,7 +271,7 +Y Show Refs b Branch s Stage + Toggle section c Commit u Unstage +k/ Up f Fetch Show +j/ Down h/? Help K Discard +/ Up line l Log +/ Down line M Remote +/ Prev section F Pull +/ Next section P Push +/ Parent section r Rebase + Half page up X Reset + Half page down V Revert +g Refresh z Stash +q/ Quit/Close diff --git a/src/ui/layout/snapshots/layzer__tests__horizontal_gap.snap b/src/ui/layout/snapshots/layzer__tests__horizontal_gap.snap new file mode 100644 index 0000000000..b59f3563aa --- /dev/null +++ b/src/ui/layout/snapshots/layzer__tests__horizontal_gap.snap @@ -0,0 +1,5 @@ +--- +source: src/lib.rs +expression: layout.render_to_string() +--- +one two diff --git a/src/ui/layout/snapshots/layzer__tests__horizontal_layout.snap b/src/ui/layout/snapshots/layzer__tests__horizontal_layout.snap new file mode 100644 index 0000000000..044ce64164 --- /dev/null +++ b/src/ui/layout/snapshots/layzer__tests__horizontal_layout.snap @@ -0,0 +1,5 @@ +--- +source: src/lib.rs +expression: layout.render_to_string() +--- +ABBCCC diff --git a/src/ui/layout/snapshots/layzer__tests__nested_layouts.snap b/src/ui/layout/snapshots/layzer__tests__nested_layouts.snap new file mode 100644 index 0000000000..3be4426c4d --- /dev/null +++ b/src/ui/layout/snapshots/layzer__tests__nested_layouts.snap @@ -0,0 +1,6 @@ +--- +source: src/lib.rs +expression: layout.render_to_string() +--- +AC +BD diff --git a/src/ui/layout/snapshots/layzer__tests__out_of_bounds_horizontal.snap b/src/ui/layout/snapshots/layzer__tests__out_of_bounds_horizontal.snap new file mode 100644 index 0000000000..3041a245e8 --- /dev/null +++ b/src/ui/layout/snapshots/layzer__tests__out_of_bounds_horizontal.snap @@ -0,0 +1,6 @@ +--- +source: src/lib.rs +expression: render_to_string(layout) +--- +12345T +123456 diff --git a/src/ui/layout/snapshots/layzer__tests__out_of_bounds_horizontal_align_end.snap b/src/ui/layout/snapshots/layzer__tests__out_of_bounds_horizontal_align_end.snap new file mode 100644 index 0000000000..3041a245e8 --- /dev/null +++ b/src/ui/layout/snapshots/layzer__tests__out_of_bounds_horizontal_align_end.snap @@ -0,0 +1,6 @@ +--- +source: src/lib.rs +expression: render_to_string(layout) +--- +12345T +123456 diff --git a/src/ui/layout/snapshots/layzer__tests__out_of_bounds_vertical.snap b/src/ui/layout/snapshots/layzer__tests__out_of_bounds_vertical.snap new file mode 100644 index 0000000000..0965fe7deb --- /dev/null +++ b/src/ui/layout/snapshots/layzer__tests__out_of_bounds_vertical.snap @@ -0,0 +1,6 @@ +--- +source: src/lib.rs +expression: render_to_string(layout) +--- +11 +22 diff --git a/src/ui/layout/snapshots/layzer__tests__out_of_bounds_vertical_align_end.snap b/src/ui/layout/snapshots/layzer__tests__out_of_bounds_vertical_align_end.snap new file mode 100644 index 0000000000..c087e04691 --- /dev/null +++ b/src/ui/layout/snapshots/layzer__tests__out_of_bounds_vertical_align_end.snap @@ -0,0 +1,6 @@ +--- +source: src/lib.rs +expression: render_to_string(layout) +--- +1 +2 diff --git a/src/ui/layout/snapshots/layzer__tests__single_text.snap b/src/ui/layout/snapshots/layzer__tests__single_text.snap new file mode 100644 index 0000000000..078f18babb --- /dev/null +++ b/src/ui/layout/snapshots/layzer__tests__single_text.snap @@ -0,0 +1,6 @@ +--- +source: src/lib.rs +expression: render_to_string(layout) +--- +Hello +lol diff --git a/src/ui/layout/snapshots/layzer__tests__stacked.snap b/src/ui/layout/snapshots/layzer__tests__stacked.snap new file mode 100644 index 0000000000..d824f46d8a --- /dev/null +++ b/src/ui/layout/snapshots/layzer__tests__stacked.snap @@ -0,0 +1,5 @@ +--- +source: src/lib.rs +expression: layout.render_to_string() +--- +This is on top (leftovers here) diff --git a/src/ui/layout/snapshots/layzer__tests__vertical_gap.snap b/src/ui/layout/snapshots/layzer__tests__vertical_gap.snap new file mode 100644 index 0000000000..8d59ebc8aa --- /dev/null +++ b/src/ui/layout/snapshots/layzer__tests__vertical_gap.snap @@ -0,0 +1,7 @@ +--- +source: src/lib.rs +expression: layout.render_to_string() +--- +one + +two diff --git a/src/ui/layout/snapshots/layzer__tests__vertical_layout.snap b/src/ui/layout/snapshots/layzer__tests__vertical_layout.snap new file mode 100644 index 0000000000..916de116de --- /dev/null +++ b/src/ui/layout/snapshots/layzer__tests__vertical_layout.snap @@ -0,0 +1,7 @@ +--- +source: src/lib.rs +expression: layout.render_to_string() +--- +First +Second +Third diff --git a/src/ui/layout/vec2.rs b/src/ui/layout/vec2.rs new file mode 100644 index 0000000000..f7768cc955 --- /dev/null +++ b/src/ui/layout/vec2.rs @@ -0,0 +1,119 @@ +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign}; + +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub(crate) struct Vec2(pub(crate) u16, pub(crate) u16); + +impl std::fmt::Debug for Vec2 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_fmt(format_args!("Vec2({}, {})", self.0, self.1)) + } +} + +impl From<[u16; 2]> for Vec2 { + fn from([x, y]: [u16; 2]) -> Self { + Self(x, y) + } +} + +impl From for [u16; 2] { + fn from(Vec2(x, y): Vec2) -> Self { + [x, y] + } +} + +impl Add for Vec2 { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0, self.1 + rhs.1) + } +} + +impl Sub for Vec2 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0, self.1 - rhs.1) + } +} + +impl Mul for Vec2 { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + Self(self.0 * rhs.0, self.1 * rhs.1) + } +} + +impl Div for Vec2 { + type Output = Self; + + fn div(self, rhs: Self) -> Self::Output { + Self(self.0 / rhs.0, self.1 / rhs.1) + } +} + +impl Rem for Vec2 { + type Output = Self; + + fn rem(self, rhs: Self) -> Self::Output { + Self(self.0 % rhs.0, self.1 % rhs.1) + } +} + +impl AddAssign for Vec2 { + fn add_assign(&mut self, rhs: Self) { + self.0 += rhs.0; + self.1 += rhs.1; + } +} + +impl SubAssign for Vec2 { + fn sub_assign(&mut self, rhs: Self) { + self.0 -= rhs.0; + self.1 -= rhs.1; + } +} + +impl MulAssign for Vec2 { + fn mul_assign(&mut self, rhs: Self) { + self.0 *= rhs.0; + self.1 *= rhs.1; + } +} + +impl DivAssign for Vec2 { + fn div_assign(&mut self, rhs: Self) { + self.0 /= rhs.0; + self.1 /= rhs.1; + } +} + +impl RemAssign for Vec2 { + fn rem_assign(&mut self, rhs: Self) { + self.0 %= rhs.0; + self.1 %= rhs.1; + } +} + +impl Vec2 { + pub(crate) fn max(self, rhs: Self) -> Self { + Self(self.0.max(rhs.0), self.1.max(rhs.1)) + } + + pub(crate) fn min(self, rhs: Self) -> Self { + Self(self.0.min(rhs.0), self.1.min(rhs.1)) + } + + pub(crate) fn fits(&self, other: Self) -> bool { + self.0 <= other.0 && self.1 <= other.1 + } + + pub(crate) fn flip(&self) -> Self { + Self(self.1, self.0) + } + + pub(crate) fn saturating_sub(&self, other: Vec2) -> Vec2 { + *self - self.min(other) + } +} diff --git a/src/ui/menu.rs b/src/ui/menu.rs index f60f1d698a..62a08cb20b 100644 --- a/src/ui/menu.rs +++ b/src/ui/menu.rs @@ -1,174 +1,158 @@ use std::sync::Arc; -use super::SizedWidget; -use crate::{app::State, config::Config, items::Item, menu::PendingMenu, ops::Op}; +use crate::ui::layout::OPTS; +use crate::ui::{self, UiTree}; +use crate::{app::State, ops::Op, ui::layout_line}; use itertools::Itertools; use ratatui::{ - buffer::Buffer, - layout::{Constraint, Rect}, style::Style, text::{Line, Span}, - widgets::{Row, Table, Widget}, }; -pub(crate) struct MenuWidget<'a> { - table: Table<'a>, -} - -impl<'a> MenuWidget<'a> { - pub fn new( - config: Arc, - pending: &'a PendingMenu, - item: &'a Item, - state: &'a State, - ) -> SizedWidget { - let style = &config.style; - - let arg_binds = config.bindings.arg_list(pending).collect::>(); - - let non_target_binds = config - .bindings - .list(&pending.menu) - .filter(|keybind| !keybind.op.clone().implementation().is_target_op()) - .collect::>(); - - let mut pending_binds_column = vec![]; - pending_binds_column.push(Line::styled(format!("{}", pending.menu), &style.command)); - for (op, binds) in non_target_binds - .iter() - .chunk_by(|bind| &bind.op) - .into_iter() - .filter(|(op, _binds)| !matches!(op, Op::OpenMenu(_))) - { - pending_binds_column.push(Line::from(vec![ - Span::styled( - binds.into_iter().map(|bind| &bind.raw).join("/"), - &style.hotkey, - ), - Span::styled( - format!(" {}", op.clone().implementation().display(state)), - Style::new(), - ), - ])); - } - - let menus = non_target_binds - .iter() - .filter(|bind| matches!(bind.op, Op::OpenMenu(_))) - .collect::>(); - - let mut menu_binds_column = vec![]; - if !menus.is_empty() { - menu_binds_column.push(Line::styled("Submenu", &style.command)); - } - for (op, binds) in menus.iter().chunk_by(|bind| &bind.op).into_iter() { - let Op::OpenMenu(menu) = op else { - unreachable!(); - }; - - menu_binds_column.push(Line::from(vec![ - Span::styled( - binds.into_iter().map(|bind| &bind.raw).join("/"), - &style.hotkey, - ), - Span::styled(format!(" {menu}"), Style::new()), - ])); - } - - let mut right_column = vec![]; - let target_binds = config - .bindings - .list(&pending.menu) - .filter(|keybind| keybind.op.clone().implementation().is_target_op()) - .filter(|keybind| { - keybind - .op - .clone() - .implementation() - .get_action(&item.data) - .is_some() - }) - .collect::>(); - - if !target_binds.is_empty() { - right_column.push(item.to_line(Arc::clone(&config))); - } - - for bind in target_binds { - right_column.push(Line::from(vec![ - Span::styled(bind.raw.clone(), &style.hotkey), - Span::styled( - format!(" {}", bind.op.clone().implementation().display(state)), - Style::new(), - ), - ])); - } - - if !arg_binds.is_empty() { - right_column.push(Line::styled("Arguments", &style.command)); - } - - for bind in arg_binds { - let Op::ToggleArg(name) = &bind.op else { - unreachable!(); - }; - - let arg = pending.args.get(name.as_str()).unwrap(); - - right_column.push(Line::from(vec![ - Span::styled(bind.raw.clone(), &style.hotkey), - Span::raw(" "), - Span::raw(arg.display), - Span::raw(" ("), - Span::styled( - arg.get_cli_token().to_string(), - if arg.is_active() { - Style::from(&style.active_arg) - } else { - Style::new() - }, - ), - Span::raw(")"), - ])); - } - - let widths = [ - col_width(&pending_binds_column), - col_width(&menu_binds_column), - Constraint::Fill(1), - ]; - - let columns = [pending_binds_column, menu_binds_column, right_column]; - - let max_rows = columns.iter().map(Vec::len).max().unwrap_or(0); - let rows = (0..(max_rows)).map(|i| { - Row::new( - columns - .iter() - .map(|col| col.get(i).cloned().unwrap_or(Line::raw(""))), - ) - }); +pub(crate) fn layout_menu<'a>(layout: &mut UiTree<'a>, state: &'a State, width: usize) { + let Some(ref pending) = state.pending_menu else { + return; + }; - let (lines, table) = (rows.len(), Table::new(rows, widths).column_spacing(3)); - - SizedWidget { - height: 1 + lines as u16, - widget: MenuWidget { - table: table.block(super::popup_block()), - }, - } + if pending.is_hidden { + return; } -} -fn col_width(column: &[Line<'_>]) -> Constraint { - Constraint::Length(column.iter().map(|line| line.width()).max().unwrap_or(0) as u16) -} + ui::repeat_chars(layout, width, ui::DASHES, ui::STYLE); + + let config = Arc::clone(&state.config); + let item = state.screens.last().unwrap().get_selected_item(); + let style = &config.style; + + let arg_binds = config.bindings.arg_list(pending).collect::>(); + + let non_target_binds = config + .bindings + .list(&pending.menu) + .filter(|keybind| !keybind.op.clone().implementation().is_target_op()) + .collect::>(); + + let menus = non_target_binds + .iter() + .filter(|bind| matches!(bind.op, Op::OpenMenu(_))) + .collect::>(); + + let target_binds = config + .bindings + .list(&pending.menu) + .filter(|keybind| keybind.op.clone().implementation().is_target_op()) + .filter(|keybind| { + keybind + .op + .clone() + .implementation() + .get_action(&item.data) + .is_some() + }) + .collect::>(); + + let line = item.to_line(Arc::clone(&config)); + + layout.horizontal(None, OPTS.gap(3), |layout| { + layout.vertical(None, OPTS, |layout| { + layout_line( + layout, + Line::styled(format!("{}", pending.menu), &style.command), + ); + + for (op, binds) in non_target_binds + .iter() + .chunk_by(|bind| &bind.op) + .into_iter() + .filter(|(op, _binds)| !matches!(op, Op::OpenMenu(_))) + { + super::layout_line( + layout, + Line::from(vec![ + Span::styled( + binds.into_iter().map(|bind| &bind.raw).join("/"), + &style.hotkey, + ), + Span::styled( + format!(" {}", op.clone().implementation().display(state)), + Style::new(), + ), + ]), + ); + } + }); -impl Widget for MenuWidget<'_> { - fn render(self, area: Rect, buf: &mut Buffer) - where - Self: Sized, - { - Widget::render(self.table, area, buf) - } + layout.vertical(None, OPTS, |layout| { + if !menus.is_empty() { + super::layout_line(layout, Line::styled("Submenu", &style.command)); + } + + for (op, binds) in menus.iter().chunk_by(|bind| &bind.op).into_iter() { + let Op::OpenMenu(menu) = op else { + unreachable!(); + }; + + super::layout_line( + layout, + Line::from(vec![ + Span::styled( + binds.into_iter().map(|bind| &bind.raw).join("/"), + &style.hotkey, + ), + Span::styled(format!(" {menu}"), Style::new()), + ]), + ); + } + }); + + layout.vertical(None, OPTS, |layout| { + if !target_binds.is_empty() { + super::layout_line(layout, line); + } + + for bind in target_binds { + super::layout_line( + layout, + Line::from(vec![ + Span::styled(bind.raw.clone(), &style.hotkey), + Span::styled( + format!(" {}", bind.op.clone().implementation().display(state)), + Style::new(), + ), + ]), + ); + } + + if !arg_binds.is_empty() { + super::layout_line(layout, Line::styled("Arguments", &style.command)); + } + + for bind in arg_binds { + let Op::ToggleArg(name) = &bind.op else { + unreachable!(); + }; + + let arg = pending.args.get(name.as_str()).unwrap(); + + super::layout_line( + layout, + Line::from(vec![ + Span::styled(bind.raw.clone(), &style.hotkey), + Span::raw(" "), + Span::raw(arg.display), + Span::raw(" ("), + Span::styled( + arg.get_cli_token().to_string(), + if arg.is_active() { + Style::from(&style.active_arg) + } else { + Style::new() + }, + ), + Span::raw(")"), + ]), + ); + } + }); + }); }