Allow copying multiple commits (#1288)

This commit is contained in:
Emil Jaszczuk 2022-09-19 10:54:29 +02:00 committed by GitHub
parent 9534e4c2f9
commit e0fa63c6c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 101 additions and 14 deletions

View File

@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* file blame at right revision from commit-details [[@heiskane](https://github.com/heiskane)] ([#1122](https://github.com/extrawurst/gitui/issues/1122))
* add `regex-fancy` and `regex-onig` features to allow building Syntect with Onigumara regex engine instead of the default engine based on fancy-regex [[@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))
### Fixes
* remove insecure dependency `ansi_term` ([#1290](https://github.com/extrawurst/gitui/issues/1290))

View File

@ -34,7 +34,7 @@ pub struct CommitList {
branch: Option<String>,
count_total: usize,
items: ItemBatch,
marked: Vec<CommitId>,
marked: Vec<(usize, CommitId)>,
scroll_state: (Instant, f32),
tags: Option<Tags>,
current_size: Cell<(u16, u16)>,
@ -134,7 +134,7 @@ impl CommitList {
}
///
pub fn marked(&self) -> &[CommitId] {
pub fn marked(&self) -> &[(usize, CommitId)] {
&self.marked
}
@ -143,11 +143,85 @@ impl CommitList {
self.marked.clear();
}
///
pub fn marked_indexes(&self) -> Vec<usize> {
let (indexes, _): (Vec<usize>, Vec<_>) =
self.marked.iter().copied().unzip();
indexes
}
///
pub fn marked_commits(&self) -> Vec<CommitId> {
let (_, commits): (Vec<_>, Vec<CommitId>) =
self.marked.iter().copied().unzip();
commits
}
fn marked_consecutive(&self) -> bool {
let marked = self.marked_indexes();
for i in 1..marked.len() {
if marked[i - 1] + 1 != marked[i] {
return false;
}
}
true
}
pub fn copy_marked_hashes(&self) -> Result<()> {
if self.marked_consecutive() {
let m = self.marked_indexes();
let first = self.items.iter().nth(m[0]);
let last = self.items.iter().nth(m[m.len() - 1]);
if let (Some(f), Some(l)) = (first, last) {
let yank =
format!("{}^..{}", f.hash_short, l.hash_short);
crate::clipboard::copy_string(&yank)?;
};
} else {
let separate = self
.marked_indexes()
.iter()
.map(|e| {
self.items
.iter()
.nth(*e)
.map_or_else(String::new, |le| {
le.hash_short.to_string()
})
})
.join(" ");
crate::clipboard::copy_string(&separate)?;
}
Ok(())
}
pub fn copy_entry_hash(&self) -> Result<()> {
if let Some(e) = self.items.iter().nth(
self.selection.saturating_sub(self.items.index_offset()),
) {
crate::clipboard::copy_string(&e.hash_short)?;
match self.marked_count() {
0 => {
if let Some(e) = self.items.iter().nth(
self.selection
.saturating_sub(self.items.index_offset()),
) {
crate::clipboard::copy_string(&e.hash_short)?;
}
}
1 => {
if let Some(e) =
self.items.iter().nth(self.marked_indexes()[0])
{
crate::clipboard::copy_string(&e.hash_short)?;
}
}
_ => {}
}
Ok(())
}
@ -191,10 +265,17 @@ impl CommitList {
fn mark(&mut self) {
if let Some(e) = self.selected_entry() {
let id = e.id;
let selected = self
.selection
.saturating_sub(self.items.index_offset());
if self.is_marked(&id).unwrap_or_default() {
self.marked.retain(|marked| marked != &id);
self.marked.retain(|marked| marked.1 != id);
} else {
self.marked.push(id);
self.marked.push((selected, id));
self.marked.sort_unstable_by(|first, second| {
first.0.cmp(&second.0)
});
}
}
}
@ -227,7 +308,8 @@ impl CommitList {
if self.marked.is_empty() {
None
} else {
let found = self.marked.iter().any(|entry| entry == id);
let found =
self.marked.iter().any(|entry| entry.1 == *id);
Some(found)
}
}

View File

@ -165,7 +165,11 @@ impl Revlog {
}
fn copy_commit_hash(&self) -> Result<()> {
self.list.copy_entry_hash()?;
if self.list.marked_count() > 1 {
self.list.copy_marked_hashes()?;
} else {
self.list.copy_entry_hash()?;
}
Ok(())
}
@ -328,7 +332,7 @@ impl Component for Revlog {
self.queue.push(InternalEvent::OpenPopup(
StackablePopupOpen::CompareCommits(
InspectCommitOpen::new(
self.list.marked()[0],
self.list.marked()[0].1,
),
),
));
@ -339,8 +343,8 @@ impl Component for Revlog {
self.queue.push(InternalEvent::OpenPopup(
StackablePopupOpen::CompareCommits(
InspectCommitOpen {
commit_id: marked[0],
compare_id: Some(marked[1]),
commit_id: marked[0].1,
compare_id: Some(marked[1].1),
tags: None,
},
),

View File

@ -78,7 +78,7 @@ impl StashList {
fn drop_stash(&mut self) {
if self.list.marked_count() > 0 {
self.queue.push(InternalEvent::ConfirmAction(
Action::StashDrop(self.list.marked().to_vec()),
Action::StashDrop(self.list.marked_commits()),
));
} else if let Some(e) = self.list.selected_entry() {
self.queue.push(InternalEvent::ConfirmAction(