Skip to content

Commit

Permalink
Support recursive blame (fixes extrawurst#2194)
Browse files Browse the repository at this point in the history
- Replaces `BlameFilePopup.blame: Option<BlameProcess>` with `BlameFilePopup.blame_stack: Vec<BlameProcess>`.
- Adds keybinding for going back from a blame (`b`).
- Makes keybinding for `blame` (`Shift+B`) work in the `popups/blame_file.rs` view, where it will take the commit and open a blame from that.
  • Loading branch information
Kaniel Kirby committed Jul 1, 2024
1 parent 6ec7eea commit 8998aec
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 49 deletions.
2 changes: 2 additions & 0 deletions src/keys/key_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ pub struct KeysList {
pub shift_down: GituiKeyEvent,
pub enter: GituiKeyEvent,
pub blame: GituiKeyEvent,
pub blame_back: GituiKeyEvent,
pub file_history: GituiKeyEvent,
pub edit_file: GituiKeyEvent,
pub status_stage_all: GituiKeyEvent,
Expand Down Expand Up @@ -160,6 +161,7 @@ impl Default for KeysList {
shift_down: GituiKeyEvent::new(KeyCode::Down, KeyModifiers::SHIFT),
enter: GituiKeyEvent::new(KeyCode::Enter, KeyModifiers::empty()),
blame: GituiKeyEvent::new(KeyCode::Char('B'), KeyModifiers::SHIFT),
blame_back: GituiKeyEvent::new(KeyCode::Char('b'), KeyModifiers::empty()),
file_history: GituiKeyEvent::new(KeyCode::Char('H'), KeyModifiers::SHIFT),
edit_file: GituiKeyEvent::new(KeyCode::Char('e'), KeyModifiers::empty()),
status_stage_all: GituiKeyEvent::new(KeyCode::Char('a'), KeyModifiers::empty()),
Expand Down
123 changes: 74 additions & 49 deletions src/popups/blame_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ pub struct BlameFilePopup {
table_state: std::cell::Cell<TableState>,
key_config: SharedKeyConfig,
current_height: std::cell::Cell<usize>,
blame: Option<BlameProcess>,
blame_stack: Vec<BlameProcess>,
app_sender: Sender<AsyncAppNotification>,
git_sender: Sender<AsyncGitNotification>,
repo: RepoPathRef,
Expand Down Expand Up @@ -123,7 +123,7 @@ impl DrawableComponent for BlameFilePopup {
];

let number_of_rows: usize = rows.len();
let syntax_highlight_progress = match self.blame {
let syntax_highlight_progress = match self.blame_stack.last() {
Some(BlameProcess::SyntaxHighlighting {
ref job,
..
Expand Down Expand Up @@ -193,10 +193,7 @@ impl Component for BlameFilePopup {
out: &mut Vec<CommandInfo>,
force_all: bool,
) -> CommandBlocking {
let has_result = self
.blame
.as_ref()
.is_some_and(|blame| blame.result().is_some());
let has_result = self.blame_stack.last().is_some_and(|last| last.result().is_some());
if self.is_visible() || force_all {
out.push(
CommandInfo::new(
Expand Down Expand Up @@ -307,8 +304,40 @@ impl Component for BlameFilePopup {
),
));
}
} else if key_match(
key,
self.key_config.keys.blame,
) {
if let Some(file_path) = self
.params
.as_ref()
.map(|p| p.file_path.clone())
{
let _ = self.open(BlameFileOpen {
file_path,
commit_id: self.selected_commit(),
selection: self.get_selection(),
});
}
} else if key_match(
key,
self.key_config.keys.blame_back,
) {
match self.blame_stack.len() {
0 => {
self.hide_stacked(false)
},
1 => {
self.blame_stack.pop();
self.hide_stacked(false)
},
_ => {
self.blame_stack.pop();
},
}
}


return Ok(EventState::Consumed);
}
}
Expand Down Expand Up @@ -342,7 +371,7 @@ impl BlameFilePopup {
current_height: std::cell::Cell::new(0),
app_sender: env.sender_app.clone(),
git_sender: env.sender_git.clone(),
blame: None,
blame_stack: vec![],
repo: env.repo.clone(),
}
}
Expand Down Expand Up @@ -371,11 +400,12 @@ impl BlameFilePopup {
file_path: open.file_path,
commit_id: open.commit_id,
});
self.blame =
Some(BlameProcess::GettingBlame(AsyncBlame::new(
self.blame_stack.push(
BlameProcess::GettingBlame(AsyncBlame::new(
self.repo.borrow().clone(),
&self.git_sender,
)));
))
);
self.table_state.get_mut().select(Some(0));
self.visible = true;
self.update()?;
Expand All @@ -384,9 +414,8 @@ impl BlameFilePopup {
}

///
pub const fn any_work_pending(&self) -> bool {
self.blame.is_some()
&& !matches!(self.blame, Some(BlameProcess::Result(_)))
pub fn any_work_pending(&self) -> bool {
self.blame_stack.last().is_some_and(|last| last.result().is_some())
}

pub fn update_async(
Expand Down Expand Up @@ -416,7 +445,7 @@ impl BlameFilePopup {
if self.is_visible() {
if let Some(BlameProcess::GettingBlame(
ref mut async_blame,
)) = self.blame
)) = self.blame_stack.last_mut()
{
if let Some(params) = &self.params {
if let Some((
Expand All @@ -425,19 +454,17 @@ impl BlameFilePopup {
)) = async_blame.last()?
{
if previous_blame_params == *params {
self.blame = Some(
BlameProcess::SyntaxHighlighting {
unstyled_file_blame:
SyntaxFileBlame {
file_blame:
last_file_blame,
styled_text: None,
},
job: AsyncSingleJob::new(
self.app_sender.clone(),
),
},
);
*self.blame_stack.last_mut().unwrap() = BlameProcess::SyntaxHighlighting {
unstyled_file_blame:
SyntaxFileBlame {
file_blame:
last_file_blame,
styled_text: None,
},
job: AsyncSingleJob::new(
self.app_sender.clone(),
),
};
self.set_open_selection();
self.highlight_blame_lines();

Expand All @@ -457,7 +484,7 @@ impl BlameFilePopup {
let Some(BlameProcess::SyntaxHighlighting {
ref unstyled_file_blame,
ref job,
}) = self.blame
}) = self.blame_stack.last()
else {
return;
};
Expand All @@ -474,16 +501,15 @@ impl BlameFilePopup {
== Path::new(
unstyled_file_blame.path(),
) {
self.blame =
Some(BlameProcess::Result(
SyntaxFileBlame {
file_blame:
unstyled_file_blame
.file_blame
.clone(),
styled_text: Some(syntax),
},
));
*self.blame_stack.last_mut().unwrap() = BlameProcess::Result(
SyntaxFileBlame {
file_blame:
unstyled_file_blame
.file_blame
.clone(),
styled_text: Some(syntax),
},
);
}
}
}
Expand All @@ -498,7 +524,7 @@ impl BlameFilePopup {
match (
self.any_work_pending(),
self.params.as_ref(),
self.blame.as_ref().and_then(|blame| blame.result()),
self.blame_stack.last().and_then(|blame| blame.result()),
) {
(true, Some(params), _) => {
format!(
Expand Down Expand Up @@ -526,8 +552,7 @@ impl BlameFilePopup {

///
fn get_rows(&self, width: usize) -> Vec<Row> {
self.blame
.as_ref()
self.blame_stack.last()
.and_then(|blame| blame.result())
.map(|file_blame| {
let styled_text: Option<Text<'_>> = file_blame
Expand Down Expand Up @@ -556,7 +581,7 @@ impl BlameFilePopup {
let Some(BlameProcess::SyntaxHighlighting {
ref unstyled_file_blame,
ref mut job,
}) = self.blame
}) = self.blame_stack.last_mut()
else {
return;
};
Expand Down Expand Up @@ -654,7 +679,7 @@ impl BlameFilePopup {
});

let file_blame =
self.blame.as_ref().and_then(|blame| blame.result());
self.blame_stack.last().and_then(|blame| blame.result());
let is_blamed_commit = file_blame
.and_then(|file_blame| {
blame_hunk.map(|hunk| {
Expand All @@ -673,8 +698,8 @@ impl BlameFilePopup {
}

fn get_max_line_number(&self) -> usize {
self.blame
.as_ref()
self.blame_stack
.last()
.and_then(|blame| blame.result())
.map_or(0, |file_blame| file_blame.lines().len() - 1)
}
Expand Down Expand Up @@ -727,8 +752,8 @@ impl BlameFilePopup {
}

fn get_selection(&self) -> Option<usize> {
self.blame
.as_ref()
self.blame_stack
.last()
.and_then(|blame| blame.result())
.and_then(|_| {
let table_state = self.table_state.take();
Expand All @@ -742,8 +767,8 @@ impl BlameFilePopup {
}

fn selected_commit(&self) -> Option<CommitId> {
self.blame
.as_ref()
self.blame_stack
.last()
.and_then(|blame| blame.result())
.and_then(|file_blame| {
let table_state = self.table_state.take();
Expand Down

0 comments on commit 8998aec

Please sign in to comment.