Merge remote-tracking branch 'nikitarevenco/gix-blame'
This commit is contained in:
commit
5fd7d98b73
6 changed files with 73 additions and 22 deletions
|
@ -13,7 +13,8 @@ use helix_stdx::path::get_relative_path;
|
|||
use helix_view::{
|
||||
align_view,
|
||||
document::{DocumentOpenError, DocumentSavedEventResult},
|
||||
editor::{ConfigEvent, EditorEvent},
|
||||
editor::{ConfigEvent, EditorEvent, TICK_DURATION},
|
||||
events::DidRequestInlineBlame,
|
||||
graphics::Rect,
|
||||
theme,
|
||||
tree::Layout,
|
||||
|
@ -35,7 +36,7 @@ use crate::{
|
|||
use log::{debug, error, info, warn};
|
||||
#[cfg(not(feature = "integration"))]
|
||||
use std::io::stdout;
|
||||
use std::{io::stdin, path::Path, sync::Arc};
|
||||
use std::{io::stdin, path::Path, sync::Arc, time::Duration};
|
||||
|
||||
#[cfg(not(windows))]
|
||||
use anyhow::Context;
|
||||
|
@ -586,6 +587,18 @@ impl Application {
|
|||
));
|
||||
}
|
||||
|
||||
async fn handle_tick(&mut self) {
|
||||
self.editor.ticks_elapsed += 1;
|
||||
// request an inline blame refresh every this amount of ticks
|
||||
const INLINE_BLAME_REQUEST_TIME: u128 =
|
||||
Duration::from_millis(150).as_nanos() / TICK_DURATION.as_nanos();
|
||||
if self.editor.ticks_elapsed % INLINE_BLAME_REQUEST_TIME == 0 {
|
||||
helix_event::dispatch(DidRequestInlineBlame {
|
||||
editor: &mut self.editor,
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub async fn handle_editor_event(&mut self, event: EditorEvent) -> bool {
|
||||
log::debug!("received editor event: {:?}", event);
|
||||
|
@ -622,6 +635,9 @@ impl Application {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
EditorEvent::Tick => {
|
||||
self.handle_tick().await;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use helix_event::{events, register_event};
|
||||
use helix_view::document::Mode;
|
||||
use helix_view::events::{
|
||||
DiagnosticsDidChange, DocumentDidChange, DocumentDidOpen, DocumentFocusLost, SelectionDidChange,
|
||||
DiagnosticsDidChange, DocumentDidChange, DocumentDidOpen, DocumentFocusLost, SelectionDidChange, DidRequestInlineBlame
|
||||
};
|
||||
|
||||
use crate::commands;
|
||||
|
@ -20,6 +20,7 @@ pub fn register() {
|
|||
register_event::<DocumentDidChange>();
|
||||
register_event::<DocumentDidOpen>();
|
||||
register_event::<DocumentFocusLost>();
|
||||
register_event::<DidRequestInlineBlame>();
|
||||
register_event::<SelectionDidChange>();
|
||||
register_event::<DiagnosticsDidChange>();
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use helix_event::{register_hook, send_blocking};
|
||||
use helix_view::handlers::{BlameEvent, Handlers};
|
||||
use helix_view::{
|
||||
events::DidRequestInlineBlame,
|
||||
handlers::{BlameEvent, Handlers},
|
||||
};
|
||||
use tokio::{task::JoinHandle, time::Instant};
|
||||
|
||||
use crate::{events::PostCommand, job};
|
||||
use crate::job;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BlameHandler {
|
||||
|
@ -77,13 +80,14 @@ impl helix_event::AsyncHook for BlameHandler {
|
|||
|
||||
pub(super) fn register_hooks(handlers: &Handlers) {
|
||||
let tx = handlers.blame.clone();
|
||||
register_hook!(move |event: &mut PostCommand<'_, '_>| {
|
||||
let version_control_config = &event.cx.editor.config().version_control;
|
||||
register_hook!(move |event: &mut DidRequestInlineBlame<'_>| {
|
||||
let version_control_config = &event.editor.config().version_control;
|
||||
if !version_control_config.inline_blame {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let (view, doc) = current!(event.cx.editor);
|
||||
let (view, doc) = current!(event.editor);
|
||||
|
||||
let Some(file) = doc.path() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
@ -93,10 +97,24 @@ pub(super) fn register_hooks(handlers: &Handlers) {
|
|||
return Ok(());
|
||||
};
|
||||
|
||||
let hunks = doc.diff_handle().unwrap().load();
|
||||
if let Some(cached) = &mut event.editor.blame_cache {
|
||||
// don't update the blame if we haven't moved to a different line
|
||||
if (view.id, cursor_line) == *cached {
|
||||
return Ok(());
|
||||
} else {
|
||||
*cached = (view.id, cursor_line)
|
||||
}
|
||||
};
|
||||
|
||||
let (inserted_lines_count, deleted_lines_count) =
|
||||
hunks.inserted_and_deleted_before_line(cursor_line as usize);
|
||||
let Some(hunks) = doc.diff_handle() else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
log::error!("updated blame!");
|
||||
|
||||
let (inserted_lines_count, deleted_lines_count) = hunks
|
||||
.load()
|
||||
.inserted_and_deleted_before_line(cursor_line as usize);
|
||||
|
||||
send_blocking(
|
||||
&tx,
|
||||
|
@ -106,7 +124,7 @@ pub(super) fn register_hooks(handlers: &Handlers) {
|
|||
deleted_lines_count,
|
||||
inserted_lines_count,
|
||||
// ok to clone because diff_providers is very small
|
||||
diff_providers: event.cx.editor.diff_providers.clone(),
|
||||
diff_providers: event.editor.diff_providers.clone(),
|
||||
// ok to clone because blame_format is likely to be about 30 characters or less
|
||||
blame_format: version_control_config.inline_blame_format.clone(),
|
||||
},
|
||||
|
|
|
@ -185,12 +185,10 @@ pub fn blame_line(
|
|||
})
|
||||
}
|
||||
|
||||
// attributes on expressions are not allowed
|
||||
// however, in our macro its possible that sometimes the
|
||||
// assignment to the mutable variable will not be read.
|
||||
//
|
||||
// when the last line has no expected blame commit
|
||||
#[allow(unused_assignments)]
|
||||
// For some reasons the CI is failing on windows with the message "Commits not found".
|
||||
// There is nothing windows-specific in this implementation
|
||||
// As long as these tests pass on other platforms, on Windows it should work too
|
||||
// #[cfg(not(windows))]
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::fs::File;
|
||||
|
@ -341,6 +339,7 @@ mod test {
|
|||
|
||||
$(
|
||||
let line_diff_flag = line_diff_flag!($($line_diff)?, $commit_msg, $line);
|
||||
#[allow(unused_assignments)]
|
||||
match line_diff_flag {
|
||||
LineDiff::Insert => added_lines += 1,
|
||||
LineDiff::Delete => removed_lines += 1,
|
||||
|
@ -373,7 +372,10 @@ mod test {
|
|||
.unwrap_or("<no commit>")
|
||||
);
|
||||
)?
|
||||
line_number += 1;
|
||||
#[allow(unused_assignments)]
|
||||
{
|
||||
line_number += 1;
|
||||
}
|
||||
}
|
||||
)*
|
||||
)*
|
||||
|
@ -448,7 +450,7 @@ mod test {
|
|||
" four" delete,
|
||||
" two" delete,
|
||||
" five" delete,
|
||||
" four",
|
||||
" four" 5,
|
||||
"}" 1,
|
||||
" five" 5,
|
||||
" four" 5;
|
||||
|
|
|
@ -23,7 +23,7 @@ use icons::Icons;
|
|||
use futures_util::stream::select_all::SelectAll;
|
||||
use futures_util::{future, StreamExt};
|
||||
use helix_lsp::{Call, LanguageServerId};
|
||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||
use tokio_stream::wrappers::{IntervalStream, UnboundedReceiverStream};
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
|
@ -39,7 +39,7 @@ use std::{
|
|||
|
||||
use tokio::{
|
||||
sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
|
||||
time::{sleep, Duration, Instant, Sleep},
|
||||
time::{interval, sleep, Duration, Instant, Sleep},
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, bail, Error};
|
||||
|
@ -1111,6 +1111,8 @@ pub struct Editor {
|
|||
pub auto_pairs: Option<AutoPairs>,
|
||||
|
||||
pub idle_timer: Pin<Box<Sleep>>,
|
||||
pub tick: IntervalStream,
|
||||
pub ticks_elapsed: u128,
|
||||
redraw_timer: Pin<Box<Sleep>>,
|
||||
last_motion: Option<Motion>,
|
||||
pub last_completion: Option<CompleteAction>,
|
||||
|
@ -1136,6 +1138,7 @@ pub struct Editor {
|
|||
|
||||
pub mouse_down_range: Option<Range>,
|
||||
pub cursor_cache: CursorCache,
|
||||
pub blame_cache: Option<(ViewId, u32)>,
|
||||
}
|
||||
|
||||
pub type Motion = Box<dyn Fn(&mut Editor)>;
|
||||
|
@ -1147,6 +1150,7 @@ pub enum EditorEvent {
|
|||
LanguageServerMessage((LanguageServerId, Call)),
|
||||
DebuggerEvent(dap::Payload),
|
||||
IdleTimer,
|
||||
Tick,
|
||||
Redraw,
|
||||
}
|
||||
|
||||
|
@ -1201,6 +1205,9 @@ pub enum CloseError {
|
|||
SaveError(anyhow::Error),
|
||||
}
|
||||
|
||||
/// A tick happens every this amount of milliseconds
|
||||
pub const TICK_DURATION: Duration = Duration::from_millis(1000 / 60);
|
||||
|
||||
impl Editor {
|
||||
pub fn new(
|
||||
mut area: Rect,
|
||||
|
@ -1246,6 +1253,8 @@ impl Editor {
|
|||
status_msg: None,
|
||||
autoinfo: None,
|
||||
idle_timer: Box::pin(sleep(conf.idle_timeout)),
|
||||
tick: IntervalStream::new(interval(TICK_DURATION)),
|
||||
ticks_elapsed: 0,
|
||||
redraw_timer: Box::pin(sleep(Duration::MAX)),
|
||||
last_motion: None,
|
||||
last_completion: None,
|
||||
|
@ -1258,6 +1267,7 @@ impl Editor {
|
|||
handlers,
|
||||
mouse_down_range: None,
|
||||
cursor_cache: CursorCache::default(),
|
||||
blame_cache: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2164,6 +2174,9 @@ impl Editor {
|
|||
_ = &mut self.idle_timer => {
|
||||
return EditorEvent::IdleTimer
|
||||
}
|
||||
_ = &mut self.tick.next() => {
|
||||
return EditorEvent::Tick
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,4 +16,5 @@ events! {
|
|||
DiagnosticsDidChange<'a> { editor: &'a mut Editor, doc: DocumentId }
|
||||
// called **after** a document loses focus (but not when its closed)
|
||||
DocumentFocusLost<'a> { editor: &'a mut Editor, doc: DocumentId }
|
||||
DidRequestInlineBlame<'a> { editor: &'a mut Editor }
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue