mirror of
https://github.com/gitui-org/gitui
synced 2026-05-23 08:58:21 +00:00
file tree of a commit (#715)
This commit is contained in:
parent
fce294066c
commit
5ba657cabe
13 changed files with 390 additions and 7 deletions
47
Cargo.lock
generated
47
Cargo.lock
generated
|
|
@ -26,6 +26,15 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.40"
|
||||
|
|
@ -50,6 +59,7 @@ dependencies = [
|
|||
"git2",
|
||||
"invalidstring",
|
||||
"log",
|
||||
"pretty_assertions",
|
||||
"rayon-core",
|
||||
"scopetime",
|
||||
"serial_test",
|
||||
|
|
@ -252,6 +262,16 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "debugid"
|
||||
version = "0.7.2"
|
||||
|
|
@ -261,6 +281,12 @@ dependencies = [
|
|||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
|
||||
|
||||
[[package]]
|
||||
name = "dirs-next"
|
||||
version = "2.0.0"
|
||||
|
|
@ -727,6 +753,15 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "output_vt100"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.1"
|
||||
|
|
@ -788,6 +823,18 @@ version = "0.2.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||
|
||||
[[package]]
|
||||
name = "pretty_assertions"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cab0e7c02cf376875e9335e0ba1da535775beb5450d21e1dffca068818ed98b"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"ctor",
|
||||
"diff",
|
||||
"output_vt100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
|
|
|
|||
|
|
@ -27,4 +27,5 @@ easy-cast = "0.4"
|
|||
[dev-dependencies]
|
||||
tempfile = "3.2"
|
||||
invalidstring = { path = "../invalidstring", version = "0.1" }
|
||||
serial_test = "0.5.1"
|
||||
serial_test = "0.5.1"
|
||||
pretty_assertions = "0.7"
|
||||
|
|
@ -24,6 +24,7 @@ mod stash;
|
|||
mod state;
|
||||
pub mod status;
|
||||
mod tags;
|
||||
mod tree;
|
||||
pub mod utils;
|
||||
|
||||
pub use blame::{blame_file, BlameHunk, FileBlame};
|
||||
|
|
@ -64,6 +65,7 @@ pub use stash::{
|
|||
};
|
||||
pub use state::{repo_state, RepoState};
|
||||
pub use tags::{get_tags, CommitTags, Tags};
|
||||
pub use tree::{tree_file_content, tree_files, TreeFile};
|
||||
pub use utils::{
|
||||
get_head, get_head_tuple, is_bare_repo, is_repo, stage_add_all,
|
||||
stage_add_file, stage_addremoved, Head,
|
||||
|
|
|
|||
112
asyncgit/src/sync/tree.rs
Normal file
112
asyncgit/src/sync/tree.rs
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
use super::{utils::bytes2string, CommitId};
|
||||
use crate::{error::Result, sync::utils::repo};
|
||||
use git2::{Oid, Repository, Tree};
|
||||
use scopetime::scope_time;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// `tree_files` returns a list of `FileTree`
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct TreeFile {
|
||||
/// path of this file
|
||||
pub path: PathBuf,
|
||||
/// unix filemode
|
||||
pub filemode: i32,
|
||||
// internal object id
|
||||
id: Oid,
|
||||
}
|
||||
|
||||
///
|
||||
pub fn tree_files(
|
||||
repo_path: &str,
|
||||
commit: CommitId,
|
||||
) -> Result<Vec<TreeFile>> {
|
||||
scope_time!("tree_files");
|
||||
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
let commit = repo.find_commit(commit.into())?;
|
||||
let tree = commit.tree()?;
|
||||
|
||||
let mut files: Vec<TreeFile> = Vec::new();
|
||||
|
||||
tree_recurse(&repo, &PathBuf::from("./"), &tree, &mut files)?;
|
||||
|
||||
Ok(files)
|
||||
}
|
||||
|
||||
///
|
||||
pub fn tree_file_content(
|
||||
repo_path: &str,
|
||||
file: &TreeFile,
|
||||
) -> Result<String> {
|
||||
scope_time!("tree_file_content");
|
||||
|
||||
let repo = repo(repo_path)?;
|
||||
|
||||
let blob = repo.find_blob(file.id)?;
|
||||
let content = String::from_utf8(blob.content().into())?;
|
||||
|
||||
Ok(content)
|
||||
}
|
||||
|
||||
///
|
||||
fn tree_recurse(
|
||||
repo: &Repository,
|
||||
path: &Path,
|
||||
tree: &Tree,
|
||||
out: &mut Vec<TreeFile>,
|
||||
) -> Result<()> {
|
||||
out.reserve(tree.len());
|
||||
|
||||
for e in tree {
|
||||
let path = path.join(bytes2string(e.name_bytes())?);
|
||||
match e.kind() {
|
||||
Some(git2::ObjectType::Blob) => {
|
||||
let id = e.id();
|
||||
let filemode = e.filemode();
|
||||
out.push(TreeFile { path, filemode, id });
|
||||
}
|
||||
Some(git2::ObjectType::Tree) => {
|
||||
let obj = e.to_object(repo)?;
|
||||
let tree = obj.peel_to_tree()?;
|
||||
tree_recurse(repo, &path, &tree, out)?;
|
||||
}
|
||||
Some(_) | None => (),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::sync::tests::{repo_init, write_commit_file};
|
||||
use pretty_assertions::{assert_eq, assert_ne};
|
||||
|
||||
#[test]
|
||||
fn test_smoke() {
|
||||
let (_td, repo) = repo_init().unwrap();
|
||||
let root = repo.path().parent().unwrap();
|
||||
let repo_path = root.as_os_str().to_str().unwrap();
|
||||
|
||||
let c1 =
|
||||
write_commit_file(&repo, "test.txt", "content", "c1");
|
||||
|
||||
let files = tree_files(repo_path, c1).unwrap();
|
||||
|
||||
assert_eq!(files.len(), 1);
|
||||
assert_eq!(files[0].path, PathBuf::from("./test.txt"));
|
||||
|
||||
let c2 =
|
||||
write_commit_file(&repo, "test.txt", "content2", "c2");
|
||||
|
||||
let content =
|
||||
tree_file_content(repo_path, &files[0]).unwrap();
|
||||
assert_eq!(&content, "content");
|
||||
|
||||
let files_c2 = tree_files(repo_path, c2).unwrap();
|
||||
|
||||
assert_eq!(files_c2.len(), 1);
|
||||
assert_ne!(files_c2[0], files[0]);
|
||||
}
|
||||
}
|
||||
17
src/app.rs
17
src/app.rs
|
|
@ -8,7 +8,8 @@ use crate::{
|
|||
ExternalEditorComponent, HelpComponent,
|
||||
InspectCommitComponent, MsgComponent, PullComponent,
|
||||
PushComponent, PushTagsComponent, RenameBranchComponent,
|
||||
ResetComponent, StashMsgComponent, TagCommitComponent,
|
||||
ResetComponent, RevisionFilesComponent, StashMsgComponent,
|
||||
TagCommitComponent,
|
||||
},
|
||||
input::{Input, InputEvent, InputState},
|
||||
keys::{KeyConfig, SharedKeyConfig},
|
||||
|
|
@ -45,6 +46,7 @@ pub struct App {
|
|||
stashmsg_popup: StashMsgComponent,
|
||||
inspect_commit_popup: InspectCommitComponent,
|
||||
external_editor_popup: ExternalEditorComponent,
|
||||
revision_files_popup: RevisionFilesComponent,
|
||||
push_popup: PushComponent,
|
||||
push_tags_popup: PushTagsComponent,
|
||||
pull_popup: PullComponent,
|
||||
|
|
@ -101,6 +103,12 @@ impl App {
|
|||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
revision_files_popup: RevisionFilesComponent::new(
|
||||
&queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
stashmsg_popup: StashMsgComponent::new(
|
||||
queue.clone(),
|
||||
theme.clone(),
|
||||
|
|
@ -386,6 +394,7 @@ impl App {
|
|||
create_branch_popup,
|
||||
rename_branch_popup,
|
||||
select_branch_popup,
|
||||
revision_files_popup,
|
||||
help,
|
||||
revlog,
|
||||
status_tab,
|
||||
|
|
@ -565,6 +574,10 @@ impl App {
|
|||
InternalEvent::StatusLastFileMoved => {
|
||||
self.status_tab.last_file_moved()?;
|
||||
}
|
||||
InternalEvent::OpenFileTree(c) => {
|
||||
self.revision_files_popup.open(c)?;
|
||||
flags.insert(NeedsUpdate::ALL | NeedsUpdate::COMMANDS)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(flags)
|
||||
|
|
@ -682,6 +695,7 @@ impl App {
|
|||
|| self.pull_popup.is_visible()
|
||||
|| self.select_branch_popup.is_visible()
|
||||
|| self.rename_branch_popup.is_visible()
|
||||
|| self.revision_files_popup.is_visible()
|
||||
}
|
||||
|
||||
fn draw_popups<B: Backend>(
|
||||
|
|
@ -709,6 +723,7 @@ impl App {
|
|||
self.select_branch_popup.draw(f, size)?;
|
||||
self.create_branch_popup.draw(f, size)?;
|
||||
self.rename_branch_popup.draw(f, size)?;
|
||||
self.revision_files_popup.draw(f, size)?;
|
||||
self.push_popup.draw(f, size)?;
|
||||
self.push_tags_popup.draw(f, size)?;
|
||||
self.pull_popup.draw(f, size)?;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ use super::{
|
|||
DrawableComponent, EventState,
|
||||
};
|
||||
use crate::{
|
||||
accessors, keys::SharedKeyConfig, queue::Queue, strings,
|
||||
accessors,
|
||||
keys::SharedKeyConfig,
|
||||
queue::{InternalEvent, Queue},
|
||||
strings,
|
||||
ui::style::SharedTheme,
|
||||
};
|
||||
use anyhow::Result;
|
||||
|
|
@ -22,6 +25,7 @@ use tui::{
|
|||
};
|
||||
|
||||
pub struct InspectCommitComponent {
|
||||
queue: Queue,
|
||||
commit_id: Option<CommitId>,
|
||||
tags: Option<CommitTags>,
|
||||
diff: DiffComponent,
|
||||
|
|
@ -98,6 +102,14 @@ impl Component for InspectCommitComponent {
|
|||
true,
|
||||
self.diff.focused() || force_all,
|
||||
));
|
||||
|
||||
out.push(CommandInfo::new(
|
||||
strings::commands::inspect_file_tree(
|
||||
&self.key_config,
|
||||
),
|
||||
true,
|
||||
true,
|
||||
));
|
||||
}
|
||||
|
||||
visibility_blocking(self)
|
||||
|
|
@ -124,6 +136,13 @@ impl Component for InspectCommitComponent {
|
|||
{
|
||||
self.details.focus(true);
|
||||
self.diff.focus(false);
|
||||
} else if e == self.key_config.open_file_tree {
|
||||
if let Some(commit) = self.commit_id {
|
||||
self.queue.borrow_mut().push_back(
|
||||
InternalEvent::OpenFileTree(commit),
|
||||
);
|
||||
self.hide();
|
||||
}
|
||||
} else if e == self.key_config.focus_left {
|
||||
self.hide();
|
||||
}
|
||||
|
|
@ -162,6 +181,7 @@ impl InspectCommitComponent {
|
|||
key_config: SharedKeyConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
queue: queue.clone(),
|
||||
details: CommitDetailsComponent::new(
|
||||
queue,
|
||||
sender,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ mod push;
|
|||
mod push_tags;
|
||||
mod rename_branch;
|
||||
mod reset;
|
||||
mod revision_files;
|
||||
mod stashmsg;
|
||||
mod tag_commit;
|
||||
mod textinput;
|
||||
|
|
@ -42,6 +43,7 @@ pub use push::PushComponent;
|
|||
pub use push_tags::PushTagsComponent;
|
||||
pub use rename_branch::RenameBranchComponent;
|
||||
pub use reset::ResetComponent;
|
||||
pub use revision_files::RevisionFilesComponent;
|
||||
pub use stashmsg::StashMsgComponent;
|
||||
pub use tag_commit::TagCommitComponent;
|
||||
pub use textinput::{InputType, TextInputComponent};
|
||||
|
|
|
|||
150
src/components/revision_files.rs
Normal file
150
src/components/revision_files.rs
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
use super::{
|
||||
visibility_blocking, CommandBlocking, CommandInfo, Component,
|
||||
DrawableComponent, EventState,
|
||||
};
|
||||
use crate::{
|
||||
keys::SharedKeyConfig,
|
||||
queue::Queue,
|
||||
strings,
|
||||
ui::{self, style::SharedTheme},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{
|
||||
sync::{self, CommitId, TreeFile},
|
||||
AsyncNotification, CWD,
|
||||
};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
use tui::{
|
||||
backend::Backend, layout::Rect, text::Span, widgets::Clear, Frame,
|
||||
};
|
||||
|
||||
pub struct RevisionFilesComponent {
|
||||
title: String,
|
||||
theme: SharedTheme,
|
||||
// queue: Queue,
|
||||
files: Vec<TreeFile>,
|
||||
revision: Option<CommitId>,
|
||||
visible: bool,
|
||||
key_config: SharedKeyConfig,
|
||||
current_height: std::cell::Cell<usize>,
|
||||
}
|
||||
|
||||
impl RevisionFilesComponent {
|
||||
///
|
||||
pub fn new(
|
||||
_queue: &Queue,
|
||||
_sender: &Sender<AsyncNotification>,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
title: String::new(),
|
||||
theme,
|
||||
files: Vec::new(),
|
||||
revision: None,
|
||||
// queue: queue.clone(),
|
||||
visible: false,
|
||||
key_config,
|
||||
current_height: std::cell::Cell::new(0),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn open(&mut self, commit: CommitId) -> Result<()> {
|
||||
self.files = sync::tree_files(CWD, commit)?;
|
||||
self.revision = Some(commit);
|
||||
self.title = format!(
|
||||
"File Tree at {}",
|
||||
self.revision
|
||||
.map(|c| c.get_short_string())
|
||||
.unwrap_or_default()
|
||||
);
|
||||
self.show()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DrawableComponent for RevisionFilesComponent {
|
||||
fn draw<B: Backend>(
|
||||
&self,
|
||||
f: &mut Frame<B>,
|
||||
area: Rect,
|
||||
) -> Result<()> {
|
||||
if self.is_visible() {
|
||||
let items = self.files.iter().map(|f| {
|
||||
Span::styled(
|
||||
f.path.to_string_lossy(),
|
||||
self.theme.text(true, false),
|
||||
)
|
||||
});
|
||||
|
||||
f.render_widget(Clear, area);
|
||||
ui::draw_list(
|
||||
f,
|
||||
area,
|
||||
&self.title,
|
||||
items,
|
||||
true,
|
||||
&self.theme,
|
||||
);
|
||||
|
||||
self.current_height.set(area.height.into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for RevisionFilesComponent {
|
||||
fn commands(
|
||||
&self,
|
||||
out: &mut Vec<CommandInfo>,
|
||||
force_all: bool,
|
||||
) -> CommandBlocking {
|
||||
if self.is_visible() || force_all {
|
||||
out.push(
|
||||
CommandInfo::new(
|
||||
strings::commands::close_popup(&self.key_config),
|
||||
true,
|
||||
true,
|
||||
)
|
||||
.order(1),
|
||||
);
|
||||
}
|
||||
|
||||
visibility_blocking(self)
|
||||
}
|
||||
|
||||
fn event(
|
||||
&mut self,
|
||||
event: crossterm::event::Event,
|
||||
) -> Result<EventState> {
|
||||
if self.is_visible() {
|
||||
if let Event::Key(key) = event {
|
||||
if key == self.key_config.exit_popup {
|
||||
self.hide();
|
||||
}
|
||||
|
||||
return Ok(EventState::Consumed);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(EventState::NotConsumed)
|
||||
}
|
||||
|
||||
fn is_visible(&self) -> bool {
|
||||
self.visible
|
||||
}
|
||||
|
||||
fn hide(&mut self) {
|
||||
self.visible = false
|
||||
}
|
||||
|
||||
fn show(&mut self) -> Result<()> {
|
||||
self.visible = true;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -71,6 +71,7 @@ pub struct KeyConfig {
|
|||
pub delete_branch: KeyEvent,
|
||||
pub merge_branch: KeyEvent,
|
||||
pub push: KeyEvent,
|
||||
pub open_file_tree: KeyEvent,
|
||||
pub force_push: KeyEvent,
|
||||
pub pull: KeyEvent,
|
||||
pub abort_merge: KeyEvent,
|
||||
|
|
@ -127,12 +128,13 @@ impl Default for KeyConfig {
|
|||
create_branch: KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::empty()},
|
||||
rename_branch: KeyEvent { code: KeyCode::Char('r'), modifiers: KeyModifiers::empty()},
|
||||
select_branch: KeyEvent { code: KeyCode::Char('b'), modifiers: KeyModifiers::empty()},
|
||||
delete_branch: KeyEvent{code: KeyCode::Char('D'), modifiers: KeyModifiers::SHIFT},
|
||||
merge_branch: KeyEvent{code: KeyCode::Char('m'), modifiers: KeyModifiers::empty()},
|
||||
delete_branch: KeyEvent { code: KeyCode::Char('D'), modifiers: KeyModifiers::SHIFT},
|
||||
merge_branch: KeyEvent { code: KeyCode::Char('m'), modifiers: KeyModifiers::empty()},
|
||||
push: KeyEvent { code: KeyCode::Char('p'), modifiers: KeyModifiers::empty()},
|
||||
force_push: KeyEvent { code: KeyCode::Char('P'), modifiers: KeyModifiers::SHIFT},
|
||||
pull: KeyEvent { code: KeyCode::Char('f'), modifiers: KeyModifiers::empty()},
|
||||
abort_merge: KeyEvent { code: KeyCode::Char('M'), modifiers: KeyModifiers::SHIFT},
|
||||
open_file_tree: KeyEvent { code: KeyCode::Char('F'), modifiers: KeyModifiers::SHIFT},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ pub enum InternalEvent {
|
|||
Pull(String),
|
||||
///
|
||||
PushTags,
|
||||
///
|
||||
OpenFileTree(CommitId),
|
||||
}
|
||||
|
||||
///
|
||||
|
|
|
|||
|
|
@ -864,6 +864,18 @@ pub mod commands {
|
|||
CMD_GROUP_LOG,
|
||||
)
|
||||
}
|
||||
pub fn inspect_file_tree(
|
||||
key_config: &SharedKeyConfig,
|
||||
) -> CommandText {
|
||||
CommandText::new(
|
||||
format!(
|
||||
"Files [{}]",
|
||||
key_config.get_hint(key_config.open_file_tree),
|
||||
),
|
||||
"inspect file tree at specific revision",
|
||||
CMD_GROUP_LOG,
|
||||
)
|
||||
}
|
||||
pub fn tag_commit_confirm_msg(
|
||||
key_config: &SharedKeyConfig,
|
||||
) -> CommandText {
|
||||
|
|
|
|||
|
|
@ -249,6 +249,16 @@ impl Component for Revlog {
|
|||
.borrow_mut()
|
||||
.push_back(InternalEvent::SelectBranch);
|
||||
return Ok(EventState::Consumed);
|
||||
} else if k == self.key_config.open_file_tree {
|
||||
return self.selected_commit().map_or(
|
||||
Ok(EventState::NotConsumed),
|
||||
|id| {
|
||||
self.queue.borrow_mut().push_back(
|
||||
InternalEvent::OpenFileTree(id),
|
||||
);
|
||||
Ok(EventState::Consumed)
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -280,7 +290,7 @@ impl Component for Revlog {
|
|||
|
||||
out.push(CommandInfo::new(
|
||||
strings::commands::log_tag_commit(&self.key_config),
|
||||
true,
|
||||
self.selected_commit().is_some(),
|
||||
self.visible || force_all,
|
||||
));
|
||||
|
||||
|
|
@ -294,7 +304,7 @@ impl Component for Revlog {
|
|||
|
||||
out.push(CommandInfo::new(
|
||||
strings::commands::copy_hash(&self.key_config),
|
||||
true,
|
||||
self.selected_commit().is_some(),
|
||||
self.visible || force_all,
|
||||
));
|
||||
|
||||
|
|
@ -304,6 +314,12 @@ impl Component for Revlog {
|
|||
self.visible || force_all,
|
||||
));
|
||||
|
||||
out.push(CommandInfo::new(
|
||||
strings::commands::inspect_file_tree(&self.key_config),
|
||||
self.selected_commit().is_some(),
|
||||
self.visible || force_all,
|
||||
));
|
||||
|
||||
visibility_blocking(self)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,8 @@
|
|||
force_push: ( code: Char('P'), modifiers: ( bits: 1,),),
|
||||
pull: ( code: Char('f'), modifiers: ( bits: 0,),),
|
||||
|
||||
open_file_tree: ( code: Char('F'), modifiers: ( bits: 1,),),
|
||||
|
||||
//removed in 0.11
|
||||
//tab_toggle_reverse_windows: ( code: BackTab, modifiers: ( bits: 1,),),
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue