mirror of
https://github.com/extrawurst/gitui.git
synced 2024-12-27 19:14:26 +03:00
Allow copying multiple commits (#1288)
This commit is contained in:
parent
9534e4c2f9
commit
e0fa63c6c9
@ -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))
|
* 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 `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)]
|
* 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
|
### 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))
|
||||||
|
@ -34,7 +34,7 @@ pub struct CommitList {
|
|||||||
branch: Option<String>,
|
branch: Option<String>,
|
||||||
count_total: usize,
|
count_total: usize,
|
||||||
items: ItemBatch,
|
items: ItemBatch,
|
||||||
marked: Vec<CommitId>,
|
marked: Vec<(usize, CommitId)>,
|
||||||
scroll_state: (Instant, f32),
|
scroll_state: (Instant, f32),
|
||||||
tags: Option<Tags>,
|
tags: Option<Tags>,
|
||||||
current_size: Cell<(u16, u16)>,
|
current_size: Cell<(u16, u16)>,
|
||||||
@ -134,7 +134,7 @@ impl CommitList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
pub fn marked(&self) -> &[CommitId] {
|
pub fn marked(&self) -> &[(usize, CommitId)] {
|
||||||
&self.marked
|
&self.marked
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,11 +143,85 @@ impl CommitList {
|
|||||||
self.marked.clear();
|
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<()> {
|
pub fn copy_entry_hash(&self) -> Result<()> {
|
||||||
if let Some(e) = self.items.iter().nth(
|
match self.marked_count() {
|
||||||
self.selection.saturating_sub(self.items.index_offset()),
|
0 => {
|
||||||
) {
|
if let Some(e) = self.items.iter().nth(
|
||||||
crate::clipboard::copy_string(&e.hash_short)?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -191,10 +265,17 @@ impl CommitList {
|
|||||||
fn mark(&mut self) {
|
fn mark(&mut self) {
|
||||||
if let Some(e) = self.selected_entry() {
|
if let Some(e) = self.selected_entry() {
|
||||||
let id = e.id;
|
let id = e.id;
|
||||||
|
let selected = self
|
||||||
|
.selection
|
||||||
|
.saturating_sub(self.items.index_offset());
|
||||||
if self.is_marked(&id).unwrap_or_default() {
|
if self.is_marked(&id).unwrap_or_default() {
|
||||||
self.marked.retain(|marked| marked != &id);
|
self.marked.retain(|marked| marked.1 != id);
|
||||||
} else {
|
} 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() {
|
if self.marked.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let found = self.marked.iter().any(|entry| entry == id);
|
let found =
|
||||||
|
self.marked.iter().any(|entry| entry.1 == *id);
|
||||||
Some(found)
|
Some(found)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,11 @@ impl Revlog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn copy_commit_hash(&self) -> Result<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +332,7 @@ impl Component for Revlog {
|
|||||||
self.queue.push(InternalEvent::OpenPopup(
|
self.queue.push(InternalEvent::OpenPopup(
|
||||||
StackablePopupOpen::CompareCommits(
|
StackablePopupOpen::CompareCommits(
|
||||||
InspectCommitOpen::new(
|
InspectCommitOpen::new(
|
||||||
self.list.marked()[0],
|
self.list.marked()[0].1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
@ -339,8 +343,8 @@ impl Component for Revlog {
|
|||||||
self.queue.push(InternalEvent::OpenPopup(
|
self.queue.push(InternalEvent::OpenPopup(
|
||||||
StackablePopupOpen::CompareCommits(
|
StackablePopupOpen::CompareCommits(
|
||||||
InspectCommitOpen {
|
InspectCommitOpen {
|
||||||
commit_id: marked[0],
|
commit_id: marked[0].1,
|
||||||
compare_id: Some(marked[1]),
|
compare_id: Some(marked[1].1),
|
||||||
tags: None,
|
tags: None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -78,7 +78,7 @@ impl StashList {
|
|||||||
fn drop_stash(&mut self) {
|
fn drop_stash(&mut self) {
|
||||||
if self.list.marked_count() > 0 {
|
if self.list.marked_count() > 0 {
|
||||||
self.queue.push(InternalEvent::ConfirmAction(
|
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() {
|
} else if let Some(e) = self.list.selected_entry() {
|
||||||
self.queue.push(InternalEvent::ConfirmAction(
|
self.queue.push(InternalEvent::ConfirmAction(
|
||||||
|
Loading…
Reference in New Issue
Block a user