Display current repository path in the top-right corner (#1387)

This commit is contained in:
Alexandru Macovei 2022-10-20 17:23:58 +03:00 committed by GitHub
parent c7e54fa17d
commit 9c2d8c0e0d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 13 deletions

View file

@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* add `vendor-openssl` feature to allow building without vendored openssl [[@jirutka](https://github.com/jirutka)] * add `vendor-openssl` feature to allow building without vendored openssl [[@jirutka](https://github.com/jirutka)]
* allow copying marked commits [[@remique](https://github.com/remique)] ([#1288](https://github.com/extrawurst/gitui/issues/1288)) * allow copying marked commits [[@remique](https://github.com/remique)] ([#1288](https://github.com/extrawurst/gitui/issues/1288))
* display tags and branches in the log view [[@alexmaco]](https://github.com/alexmaco)([#1371](https://github.com/extrawurst/gitui/pull/1371)) * display tags and branches in the log view [[@alexmaco]](https://github.com/alexmaco)([#1371](https://github.com/extrawurst/gitui/pull/1371))
* display current repository path in the top-right corner [[@alexmaco]](https://github.com/alexmaco)([#1387](https://github.com/extrawurst/gitui/pull/1387))
### Fixes ### Fixes
* remove insecure dependency `ansi_term` ([#1290](https://github.com/extrawurst/gitui/issues/1290)) * remove insecure dependency `ansi_term` ([#1290](https://github.com/extrawurst/gitui/issues/1290))

View file

@ -22,7 +22,7 @@ use crate::{
Action, InternalEvent, NeedsUpdate, Queue, StackablePopupOpen, Action, InternalEvent, NeedsUpdate, Queue, StackablePopupOpen,
}, },
setup_popups, setup_popups,
strings::{self, order}, strings::{self, ellipsis_trim_start, order},
tabs::{FilesTab, Revlog, StashList, Stashing, Status}, tabs::{FilesTab, Revlog, StashList, Stashing, Status},
ui::style::{SharedTheme, Theme}, ui::style::{SharedTheme, Theme},
AsyncAppNotification, AsyncNotification, AsyncAppNotification, AsyncNotification,
@ -41,11 +41,14 @@ use std::{
}; };
use tui::{ use tui::{
backend::Backend, backend::Backend,
layout::{Constraint, Direction, Layout, Margin, Rect}, layout::{
Alignment, Constraint, Direction, Layout, Margin, Rect,
},
text::{Span, Spans}, text::{Span, Spans},
widgets::{Block, Borders, Tabs}, widgets::{Block, Borders, Paragraph, Tabs},
Frame, Frame,
}; };
use unicode_width::UnicodeWidthStr;
#[derive(Clone)] #[derive(Clone)]
pub enum QuitState { pub enum QuitState {
@ -94,6 +97,7 @@ pub struct App {
input: Input, input: Input,
popup_stack: PopupStack, popup_stack: PopupStack,
options: SharedOptions, options: SharedOptions,
repo_path_text: String,
// "Flags" // "Flags"
requires_redraw: Cell<bool>, requires_redraw: Cell<bool>,
@ -114,6 +118,9 @@ impl App {
) -> Result<Self> { ) -> Result<Self> {
log::trace!("open repo at: {:?}", &repo); log::trace!("open repo at: {:?}", &repo);
let repo_path_text =
repo_work_dir(&repo.borrow()).unwrap_or_default();
let queue = Queue::new(); let queue = Queue::new();
let theme = Rc::new(theme); let theme = Rc::new(theme);
let key_config = Rc::new(key_config); let key_config = Rc::new(key_config);
@ -311,6 +318,7 @@ impl App {
requires_redraw: Cell::new(false), requires_redraw: Cell::new(false),
file_to_open: None, file_to_open: None,
repo, repo,
repo_path_text,
popup_stack: PopupStack::default(), popup_stack: PopupStack::default(),
}; };
@ -339,7 +347,7 @@ impl App {
self.cmdbar.borrow().draw(f, chunks_main[2]); self.cmdbar.borrow().draw(f, chunks_main[2]);
self.draw_tabs(f, chunks_main[0]); self.draw_top_bar(f, chunks_main[0]);
//TODO: component property + a macro `fullscreen_popup_open!` //TODO: component property + a macro `fullscreen_popup_open!`
// to make this scale better? // to make this scale better?
@ -1104,23 +1112,47 @@ impl App {
} }
//TODO: make this dynamic //TODO: make this dynamic
fn draw_tabs<B: Backend>(&self, f: &mut Frame<B>, r: Rect) { fn draw_top_bar<B: Backend>(&self, f: &mut Frame<B>, r: Rect) {
const DIVIDER_PAD_SPACES: usize = 2;
const SIDE_PADS: usize = 2;
const MARGIN_LEFT_AND_RIGHT: usize = 2;
let r = r.inner(&Margin { let r = r.inner(&Margin {
vertical: 0, vertical: 0,
horizontal: 1, horizontal: 1,
}); });
let tabs = [ let tab_labels = [
Span::raw(strings::tab_status(&self.key_config)), Span::raw(strings::tab_status(&self.key_config)),
Span::raw(strings::tab_log(&self.key_config)), Span::raw(strings::tab_log(&self.key_config)),
Span::raw(strings::tab_files(&self.key_config)), Span::raw(strings::tab_files(&self.key_config)),
Span::raw(strings::tab_stashing(&self.key_config)), Span::raw(strings::tab_stashing(&self.key_config)),
Span::raw(strings::tab_stashes(&self.key_config)), Span::raw(strings::tab_stashes(&self.key_config)),
] ];
.iter() let divider = strings::tab_divider(&self.key_config);
.cloned()
.map(Spans::from) // heuristic, since tui doesn't provide a way to know
.collect(); // how much space is needed to draw a `Tabs`
let tabs_len: usize =
tab_labels.iter().map(Span::width).sum::<usize>()
+ tab_labels.len().saturating_sub(1)
* (divider.width() + DIVIDER_PAD_SPACES)
+ SIDE_PADS + MARGIN_LEFT_AND_RIGHT;
let left_right = Layout::default()
.direction(Direction::Horizontal)
.constraints(vec![
Constraint::Length(
u16::try_from(tabs_len).unwrap_or(r.width),
),
Constraint::Min(0),
])
.split(r);
let table_area = r; // use entire area to allow drawing the horizontal separator line
let text_area = left_right[1];
let tabs = tab_labels.into_iter().map(Spans::from).collect();
f.render_widget( f.render_widget(
Tabs::new(tabs) Tabs::new(tabs)
@ -1131,9 +1163,21 @@ impl App {
) )
.style(self.theme.tab(false)) .style(self.theme.tab(false))
.highlight_style(self.theme.tab(true)) .highlight_style(self.theme.tab(true))
.divider(strings::tab_divider(&self.key_config)) .divider(divider)
.select(self.tab), .select(self.tab),
r, table_area,
);
f.render_widget(
Paragraph::new(Spans::from(vec![Span::styled(
ellipsis_trim_start(
&self.repo_path_text,
text_area.width as usize,
),
self.theme.title(true),
)]))
.alignment(Alignment::Right),
text_area,
); );
} }
} }

View file

@ -1,4 +1,8 @@
use std::borrow::Cow;
use asyncgit::sync::CommitId; use asyncgit::sync::CommitId;
use unicode_truncate::UnicodeTruncateStr;
use unicode_width::UnicodeWidthStr;
use crate::keys::SharedKeyConfig; use crate::keys::SharedKeyConfig;
@ -34,6 +38,7 @@ pub mod symbol {
pub const FOLDER_ICON_COLLAPSED: &str = "\u{25b8}"; //▸ pub const FOLDER_ICON_COLLAPSED: &str = "\u{25b8}"; //▸
pub const FOLDER_ICON_EXPANDED: &str = "\u{25be}"; //▾ pub const FOLDER_ICON_EXPANDED: &str = "\u{25be}"; //▾
pub const EMPTY_STR: &str = ""; pub const EMPTY_STR: &str = "";
pub const ELLIPSIS: char = '\u{2026}'; // …
} }
pub fn title_branches() -> String { pub fn title_branches() -> String {
@ -348,6 +353,21 @@ pub fn rename_branch_popup_msg(
"new branch name".to_string() "new branch name".to_string()
} }
pub fn ellipsis_trim_start(s: &str, width: usize) -> Cow<str> {
if s.width() <= width {
Cow::Borrowed(s)
} else {
Cow::Owned(format!(
"[{}]{}",
symbol::ELLIPSIS,
s.unicode_truncate_start(
width.saturating_sub(3 /* front indicator */)
)
.0
))
}
}
pub mod commit { pub mod commit {
use crate::keys::SharedKeyConfig; use crate::keys::SharedKeyConfig;