Inline git blame (#10398)
This adds so-called "inline git blame" to the editor that, when turned on, shows `git blame` information about the current line inline:  When the inline information is hovered, a new tooltip appears that contains more information on the current commit:  The commit message in this tooltip is rendered as Markdown, is scrollable and clickable. The tooltip is now also the tooltip used in the gutter:  ## Settings 1. The inline git blame information can be turned on and off via settings: ```json { "git": { "inline_blame": { "enabled": true } } } ``` 2. Optionally, a delay can be configured. When a delay is set, the inline blame information will only show up `x milliseconds` after a cursor movement: ```json { "git": { "inline_blame": { "enabled": true, "delay_ms": 600 } } } ``` 3. It can also be turned on/off for the current buffer with `editor: toggle git blame inline`. ## To be done in follow-up PRs - [ ] Add link to pull request in tooltip - [ ] Add avatars of users if possible ## Release notes Release Notes: - Added inline `git blame` information the editor. It can be turned on in the settings with `{"git": { "inline_blame": "on" } }` for every buffer or, temporarily for the current buffer, with `editor: toggle git blame inline`.
This commit is contained in:
parent
573ba83034
commit
faebce8cd0
13 changed files with 655 additions and 237 deletions
|
@ -7756,13 +7756,20 @@ impl Project {
|
|||
.as_local()
|
||||
.context("worktree was not local")?
|
||||
.snapshot();
|
||||
let (work_directory, repo) = worktree
|
||||
.repository_and_work_directory_for_path(&buffer_project_path.path)
|
||||
.context("failed to get repo for blamed buffer")?;
|
||||
|
||||
let repo_entry = worktree
|
||||
.get_local_repo(&repo)
|
||||
.context("failed to get repo for blamed buffer")?;
|
||||
let (work_directory, repo) = match worktree
|
||||
.repository_and_work_directory_for_path(&buffer_project_path.path)
|
||||
{
|
||||
Some(work_dir_repo) => work_dir_repo,
|
||||
None => anyhow::bail!(NoRepositoryError {}),
|
||||
};
|
||||
|
||||
let repo_entry = match worktree.get_local_repo(&repo) {
|
||||
Some(repo_entry) => repo_entry,
|
||||
None => anyhow::bail!(NoRepositoryError {}),
|
||||
};
|
||||
|
||||
let repo = repo_entry.repo().clone();
|
||||
|
||||
let relative_path = buffer_project_path
|
||||
.path
|
||||
|
@ -7773,7 +7780,6 @@ impl Project {
|
|||
Some(version) => buffer.rope_for_version(&version).clone(),
|
||||
None => buffer.as_rope().clone(),
|
||||
};
|
||||
let repo = repo_entry.repo().clone();
|
||||
|
||||
anyhow::Ok((repo, relative_path, content))
|
||||
});
|
||||
|
@ -10782,3 +10788,14 @@ fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
|
|||
Some(hover)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NoRepositoryError {}
|
||||
|
||||
impl std::fmt::Display for NoRepositoryError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "no git repository for worktree found")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for NoRepositoryError {}
|
||||
|
|
|
@ -3,7 +3,7 @@ use gpui::AppContext;
|
|||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use settings::{Settings, SettingsSources};
|
||||
use std::sync::Arc;
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct ProjectSettings {
|
||||
|
@ -29,6 +29,30 @@ pub struct GitSettings {
|
|||
/// Default: tracked_files
|
||||
pub git_gutter: Option<GitGutterSetting>,
|
||||
pub gutter_debounce: Option<u64>,
|
||||
/// Whether or not to show git blame data inline in
|
||||
/// the currently focused line.
|
||||
///
|
||||
/// Default: off
|
||||
pub inline_blame: Option<InlineBlameSettings>,
|
||||
}
|
||||
|
||||
impl GitSettings {
|
||||
pub fn inline_blame_enabled(&self) -> bool {
|
||||
match self.inline_blame {
|
||||
Some(InlineBlameSettings { enabled, .. }) => enabled,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inline_blame_delay(&self) -> Option<Duration> {
|
||||
match self.inline_blame {
|
||||
Some(InlineBlameSettings {
|
||||
delay_ms: Some(delay_ms),
|
||||
..
|
||||
}) if delay_ms > 0 => Some(Duration::from_millis(delay_ms)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
|
@ -41,6 +65,21 @@ pub enum GitGutterSetting {
|
|||
Hide,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct InlineBlameSettings {
|
||||
/// Whether or not to show git blame data inline in
|
||||
/// the currently focused line.
|
||||
///
|
||||
/// Default: false
|
||||
pub enabled: bool,
|
||||
/// Whether to only show the inline blame information
|
||||
/// after a delay once the cursor stops moving.
|
||||
///
|
||||
/// Default: 0
|
||||
pub delay_ms: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
|
||||
pub struct BinarySettings {
|
||||
pub path: Option<String>,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue