support showing tags in log, speed up log by cloning less (#47)

This commit is contained in:
Stephan Dilly 2020-05-10 14:22:49 +02:00
parent ec6180af51
commit 16aa6f7c50
3 changed files with 71 additions and 10 deletions

View File

@ -7,6 +7,7 @@ mod hunks;
mod logwalker;
mod reset;
pub mod status;
mod tags;
pub mod utils;
pub use commits_info::{get_commits_info, CommitInfo};
@ -16,6 +17,7 @@ pub use logwalker::LogWalker;
pub use reset::{
reset_stage, reset_workdir_file, reset_workdir_folder,
};
pub use tags::{get_tags, Tags};
pub use utils::{
commit, stage_add_all, stage_add_file, stage_addremoved,
};

30
asyncgit/src/sync/tags.rs Normal file
View File

@ -0,0 +1,30 @@
use super::utils::repo;
use git2::Error;
use scopetime::scope_time;
use std::collections::HashMap;
/// hashmap of tag target commit hash to tag name
pub type Tags = HashMap<String, String>;
/// returns `Tags` type filled with all tags found in repo
pub fn get_tags(repo_path: &str) -> Result<Tags, Error> {
scope_time!("get_tags");
let mut res = Tags::new();
let repo = repo(repo_path);
for name in repo.tag_names(None)?.iter() {
if let Some(name) = name {
let obj = repo.revparse_single(name)?;
if let Some(tag) = obj.as_tag() {
let target_hash = tag.target_id().to_string();
let tag_name = String::from(name);
res.insert(target_hash, tag_name);
}
}
}
Ok(res)
}

View File

@ -8,7 +8,7 @@ use chrono::prelude::*;
use crossbeam_channel::Sender;
use crossterm::event::Event;
use std::{borrow::Cow, cmp, convert::TryFrom, time::Instant};
use sync::CommitInfo;
use sync::{CommitInfo, Tags};
use tui::{
backend::Backend,
layout::{Alignment, Rect},
@ -24,29 +24,32 @@ struct LogEntry {
hash: String,
}
impl From<&CommitInfo> for LogEntry {
fn from(c: &CommitInfo) -> Self {
impl From<CommitInfo> for LogEntry {
fn from(c: CommitInfo) -> Self {
let time =
DateTime::<Local>::from(DateTime::<Utc>::from_utc(
NaiveDateTime::from_timestamp(c.time, 0),
Utc,
));
Self {
author: c.author.clone(),
msg: c.message.clone(),
author: c.author,
msg: c.message,
time: time.format("%Y-%m-%d %H:%M:%S").to_string(),
hash: c.hash[0..7].to_string(),
hash: c.hash,
}
}
}
const COLOR_SELECTION_BG: Color = Color::Blue;
const STYLE_TAG: Style = Style::new().fg(Color::Yellow);
const STYLE_HASH: Style = Style::new().fg(Color::Magenta);
const STYLE_TIME: Style = Style::new().fg(Color::Blue);
const STYLE_AUTHOR: Style = Style::new().fg(Color::Green);
const STYLE_MSG: Style = Style::new().fg(Color::Reset);
const STYLE_TAG_SELECTED: Style =
Style::new().fg(Color::Yellow).bg(COLOR_SELECTION_BG);
const STYLE_HASH_SELECTED: Style =
Style::new().fg(Color::Magenta).bg(COLOR_SELECTION_BG);
const STYLE_TIME_SELECTED: Style =
@ -56,7 +59,7 @@ const STYLE_AUTHOR_SELECTED: Style =
const STYLE_MSG_SELECTED: Style =
Style::new().fg(Color::Reset).bg(COLOR_SELECTION_BG);
static ELEMENTS_PER_LINE: usize = 8;
static ELEMENTS_PER_LINE: usize = 10;
static SLICE_SIZE: usize = 1000;
static SLICE_OFFSET_RELOAD_THRESHOLD: usize = 100;
@ -69,6 +72,7 @@ pub struct Revlog {
visible: bool,
first_open_done: bool,
scroll_state: (Instant, f32),
tags: Tags,
}
impl Revlog {
@ -82,6 +86,7 @@ impl Revlog {
visible: false,
first_open_done: false,
scroll_state: (Instant::now(), 0_f32),
tags: Tags::new(),
}
}
@ -94,7 +99,12 @@ impl Revlog {
let mut txt = Vec::new();
for (idx, e) in self.items.iter().enumerate() {
Self::add_entry(e, idx == selection, &mut txt);
let tag = if let Some(tag_name) = self.tags.get(&e.hash) {
tag_name.as_str()
} else {
""
};
Self::add_entry(e, idx == selection, &mut txt, tag);
}
let title =
@ -138,9 +148,14 @@ impl Revlog {
);
if let Ok(commits) = commits {
self.items.extend(commits.iter().map(LogEntry::from));
self.items
.extend(commits.into_iter().map(LogEntry::from));
}
}
if self.tags.is_empty() {
self.tags = sync::get_tags(CWD).unwrap();
}
}
fn move_selection(&mut self, up: bool) {
@ -190,6 +205,7 @@ impl Revlog {
e: &'a LogEntry,
selected: bool,
txt: &mut Vec<Text<'a>>,
tag: &'a str,
) {
let count_before = txt.len();
@ -204,7 +220,7 @@ impl Revlog {
};
txt.push(Text::Styled(
Cow::from(e.hash.as_str()),
Cow::from(&e.hash[0..7]),
if selected {
STYLE_HASH_SELECTED
} else {
@ -229,6 +245,19 @@ impl Revlog {
STYLE_AUTHOR
},
));
txt.push(splitter.clone());
txt.push(Text::Styled(
Cow::from(if tag.is_empty() {
String::from("")
} else {
format!(" {}", tag)
}),
if selected {
STYLE_TAG_SELECTED
} else {
STYLE_TAG
},
));
txt.push(splitter);
txt.push(Text::Styled(
Cow::from(e.msg.as_str()),