Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ Bugfix followup release - check `0.22.0` notes for more infos!
* switch focus to index after staging last file ([#1169](https://github.com/extrawurst/gitui/pull/1169))
* fix stashlist multi marking not updated after dropping ([#1207](https://github.com/extrawurst/gitui/pull/1207))
* exact matches have a higher priority and are placed to the top of the list when fuzzily finding files ([#1183](https://github.com/extrawurst/gitui/pull/1183))
* support horizontal scrolling in diff view ([#1017](https://github.com/extrawurst/gitui/issues/1017))

### Changed
* minimum supported rust version bumped to 1.60 ([#1279](https://github.com/extrawurst/gitui/pull/1279))
Expand Down
1 change: 1 addition & 0 deletions src/components/blame_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ impl DrawableComponent for BlameFileComponent {
//
// https://github.com/fdehau/tui-rs/issues/448
table_state.selected().unwrap_or(0),
ui::Orientation::Vertical,
);

self.table_state.set(table_state);
Expand Down
3 changes: 2 additions & 1 deletion src/components/commitlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
queue::{InternalEvent, Queue},
strings::{self, symbol},
ui::style::{SharedTheme, Theme},
ui::{calc_scroll_top, draw_scrollbar},
ui::{calc_scroll_top, draw_scrollbar, Orientation},
};
use anyhow::Result;
use asyncgit::sync::{BranchInfo, CommitId, Tags};
Expand Down Expand Up @@ -501,6 +501,7 @@ impl DrawableComponent for CommitList {
&self.theme,
self.count_total,
self.selection,
Orientation::Vertical,
);

Ok(())
Expand Down
16 changes: 7 additions & 9 deletions src/components/compare_commits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl DrawableComponent for CompareCommitsComponent {
) -> Result<()> {
if self.is_visible() {
let percentages = if self.diff.focused() {
(30, 70)
(0, 100)
} else {
(50, 50)
};
Expand Down Expand Up @@ -121,7 +121,12 @@ impl Component for CompareCommitsComponent {

if let Event::Key(e) = ev {
if key_match(e, self.key_config.keys.exit_popup) {
self.hide_stacked(false);
if self.diff.focused() {
self.details.focus(true);
self.diff.focus(false);
} else {
self.hide_stacked(false);
}
} else if key_match(
e,
self.key_config.keys.focus_right,
Expand All @@ -132,13 +137,6 @@ impl Component for CompareCommitsComponent {
} else if key_match(
e,
self.key_config.keys.focus_left,
) && self.diff.focused()
{
self.details.focus(true);
self.diff.focus(false);
} else if key_match(
e,
self.key_config.keys.focus_left,
) {
self.hide_stacked(false);
}
Expand Down
83 changes: 72 additions & 11 deletions src/components/diff.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use super::{
utils::scroll_horizontal::HorizontalScroll,
utils::scroll_vertical::VerticalScroll, CommandBlocking,
Direction, DrawableComponent, ScrollType,
Direction, DrawableComponent, HorizontalScrollType, ScrollType,
};
use crate::{
components::{CommandInfo, Component, EventState},
keys::{key_match, SharedKeyConfig},
queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem},
string_utils::tabs_to_spaces,
string_utils::trim_offset,
strings, try_or_popup,
ui::style::SharedTheme,
};
Expand Down Expand Up @@ -102,13 +104,15 @@ impl Selection {
pub struct DiffComponent {
repo: RepoPathRef,
diff: Option<FileDiff>,
longest_line: usize,
pending: bool,
selection: Selection,
selected_hunk: Option<usize>,
current_size: Cell<(u16, u16)>,
focused: bool,
current: Current,
scroll: VerticalScroll,
vertical_scroll: VerticalScroll,
horizontal_scroll: HorizontalScroll,
queue: Queue,
theme: SharedTheme,
key_config: SharedKeyConfig,
Expand All @@ -131,9 +135,11 @@ impl DiffComponent {
pending: false,
selected_hunk: None,
diff: None,
longest_line: 0,
current_size: Cell::new((0, 0)),
selection: Selection::Single(0),
scroll: VerticalScroll::new(),
vertical_scroll: VerticalScroll::new(),
horizontal_scroll: HorizontalScroll::new(),
theme,
key_config,
is_immutable,
Expand All @@ -155,7 +161,9 @@ impl DiffComponent {
pub fn clear(&mut self, pending: bool) {
self.current = Current::default();
self.diff = None;
self.scroll.reset();
self.longest_line = 0;
self.vertical_scroll.reset();
self.horizontal_scroll.reset();
self.selection = Selection::Single(0);
self.selected_hunk = None;
self.pending = pending;
Expand All @@ -182,8 +190,27 @@ impl DiffComponent {

self.diff = Some(diff);

self.longest_line = self
.diff
.iter()
.flat_map(|diff| diff.hunks.iter())
.flat_map(|hunk| hunk.lines.iter())
.map(|line| {
let converted_content = tabs_to_spaces(
line.content.as_ref().to_string(),
);

converted_content.len()
})
.max()
.map_or(0, |len| {
// Each hunk uses a 1-character wide vertical bar to its left to indicate
// selection.
len + 1
});

if reset_selection {
self.scroll.reset();
self.vertical_scroll.reset();
self.selection = Selection::Single(0);
self.update_selection(0);
} else {
Expand Down Expand Up @@ -241,6 +268,11 @@ impl DiffComponent {
self.diff.as_ref().map_or(0, |diff| diff.lines)
}

fn max_scroll_right(&self) -> usize {
self.longest_line
.saturating_sub(self.current_size.get().0.into())
}

fn modify_selection(&mut self, direction: Direction) {
if self.diff.is_some() {
self.selection.modify(direction, self.lines_count());
Expand Down Expand Up @@ -340,7 +372,7 @@ impl DiffComponent {
Span::raw(Cow::from(")")),
])]);
} else {
let min = self.scroll.get_top();
let min = self.vertical_scroll.get_top();
let max = min + height as usize;

let mut line_cursor = 0_usize;
Expand Down Expand Up @@ -378,6 +410,8 @@ impl DiffComponent {
hunk_selected,
i == hunk_len - 1,
&self.theme,
self.horizontal_scroll
.get_right(),
));
lines_added += 1;
}
Expand All @@ -400,6 +434,7 @@ impl DiffComponent {
selected_hunk: bool,
end_of_hunk: bool,
theme: &SharedTheme,
scrolled_right: usize,
) -> Spans<'a> {
let style = theme.diff_hunk_marker(selected_hunk);

Expand All @@ -418,18 +453,22 @@ impl DiffComponent {
}
};

let content =
tabs_to_spaces(line.content.as_ref().to_string());
let content = trim_offset(&content, scrolled_right);

let filled = if selected {
// selected line
format!("{:w$}\n", line.content, w = width as usize)
format!("{content:w$}\n", w = width as usize)
} else {
// weird eof missing eol line
format!("{}\n", line.content)
format!("{content}\n")
};

Spans::from(vec![
left_side_of_line,
Span::styled(
Cow::from(tabs_to_spaces(filled)),
Cow::from(filled),
theme.diff_line(line.line_type, selected),
),
])
Expand Down Expand Up @@ -606,14 +645,20 @@ impl DrawableComponent for DiffComponent {
r.height.saturating_sub(2),
));

let current_width = self.current_size.get().0;
let current_height = self.current_size.get().1;

self.scroll.update(
self.vertical_scroll.update(
self.selection.get_end(),
self.lines_count(),
usize::from(current_height),
);

self.horizontal_scroll.update_no_selection(
self.longest_line,
current_width.into(),
);

let title = format!(
"{}{}",
strings::title_diff(&self.key_config),
Expand Down Expand Up @@ -643,7 +688,11 @@ impl DrawableComponent for DiffComponent {
);

if self.focused() {
self.scroll.draw(f, r, &self.theme);
self.vertical_scroll.draw(f, r, &self.theme);

if self.max_scroll_right() > 0 {
self.horizontal_scroll.draw(f, r, &self.theme);
}
}

Ok(())
Expand Down Expand Up @@ -754,6 +803,18 @@ impl Component for DiffComponent {
{
self.move_selection(ScrollType::PageDown);
Ok(EventState::Consumed)
} else if key_match(
e,
self.key_config.keys.move_right,
) {
self.horizontal_scroll
.move_right(HorizontalScrollType::Right);
Ok(EventState::Consumed)
} else if key_match(e, self.key_config.keys.move_left)
{
self.horizontal_scroll
.move_right(HorizontalScrollType::Left);
Ok(EventState::Consumed)
} else if key_match(
e,
self.key_config.keys.stage_unstage_item,
Expand Down
18 changes: 8 additions & 10 deletions src/components/file_revlog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
keys::SharedKeyConfig,
queue::{InternalEvent, NeedsUpdate, Queue},
strings,
ui::{draw_scrollbar, style::SharedTheme},
ui::{draw_scrollbar, style::SharedTheme, Orientation},
};
use anyhow::Result;
use asyncgit::{
Expand Down Expand Up @@ -412,6 +412,7 @@ impl FileRevlogComponent {
&self.theme,
self.count_total,
table_state.selected().unwrap_or(0),
Orientation::Vertical,
);

self.table_state.set(table_state);
Expand Down Expand Up @@ -445,7 +446,7 @@ impl DrawableComponent for FileRevlogComponent {
) -> Result<()> {
if self.visible {
let percentages = if self.diff.focused() {
(30, 70)
(0, 100)
} else {
(50, 50)
};
Expand Down Expand Up @@ -485,20 +486,17 @@ impl Component for FileRevlogComponent {

if let Event::Key(key) = event {
if key_match(key, self.key_config.keys.exit_popup) {
self.hide_stacked(false);
if self.diff.focused() {
self.diff.focus(false);
} else {
self.hide_stacked(false);
}
} else if key_match(
key,
self.key_config.keys.focus_right,
) && self.can_focus_diff()
{
self.diff.focus(true);
} else if key_match(
key,
self.key_config.keys.focus_left,
) {
if self.diff.focused() {
self.diff.focus(false);
}
} else if key_match(key, self.key_config.keys.enter) {
if let Some(commit_id) = self.selected_commit() {
self.hide_stacked(true);
Expand Down
18 changes: 8 additions & 10 deletions src/components/inspect_commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl DrawableComponent for InspectCommitComponent {
) -> Result<()> {
if self.is_visible() {
let percentages = if self.diff.focused() {
(30, 70)
(0, 100)
} else {
(50, 50)
};
Expand Down Expand Up @@ -126,7 +126,7 @@ impl Component for InspectCommitComponent {
));

out.push(CommandInfo::new(
strings::commands::diff_focus_left(&self.key_config),
strings::commands::close_popup(&self.key_config),
true,
self.diff.focused() || force_all,
));
Expand Down Expand Up @@ -157,7 +157,12 @@ impl Component for InspectCommitComponent {

if let Event::Key(e) = ev {
if key_match(e, self.key_config.keys.exit_popup) {
self.hide_stacked(false);
if self.diff.focused() {
self.details.focus(true);
self.diff.focus(false);
} else {
self.hide_stacked(false);
}
} else if key_match(
e,
self.key_config.keys.focus_right,
Expand All @@ -168,13 +173,6 @@ impl Component for InspectCommitComponent {
} else if key_match(
e,
self.key_config.keys.focus_left,
) && self.diff.focused()
{
self.details.focus(true);
self.diff.focus(false);
} else if key_match(
e,
self.key_config.keys.focus_left,
) {
self.hide_stacked(false);
}
Expand Down
6 changes: 6 additions & 0 deletions src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,12 @@ pub enum ScrollType {
PageDown,
}

#[derive(Copy, Clone)]
pub enum HorizontalScrollType {
Left,
Right,
}

#[derive(Copy, Clone)]
pub enum Direction {
Up,
Expand Down
1 change: 1 addition & 0 deletions src/components/syntax_text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ impl DrawableComponent for SyntaxTextComponent {
state.height().saturating_sub(2),
)),
usize::from(state.scroll().y),
ui::Orientation::Vertical,
);
}

Expand Down
Loading