Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a version-control statusline element #5682

Merged
merged 10 commits into from
Mar 10, 2023
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions book/src/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ The following statusline elements can be configured:
| `position-percentage` | The cursor position as a percentage of the total number of lines |
| `separator` | The string defined in `editor.statusline.separator` (defaults to `"│"`) |
| `spacer` | Inserts a space between elements (multiple/contiguous spacers may be specified) |
| `version-control` | The current branch name or detached commit hash of the opened workspace |

### `[editor.lsp]` Section

Expand Down
12 changes: 12 additions & 0 deletions helix-term/src/ui/statusline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ where
helix_view::editor::StatusLineElement::TotalLineNumbers => render_total_line_numbers,
helix_view::editor::StatusLineElement::Separator => render_separator,
helix_view::editor::StatusLineElement::Spacer => render_spacer,
helix_view::editor::StatusLineElement::VersionControl => render_version_control,
}
}

Expand Down Expand Up @@ -466,3 +467,14 @@ where
{
write(context, String::from(" "), None);
}

fn render_version_control<F>(context: &mut RenderContext, write: F)
where
F: Fn(&mut RenderContext, String, Option<Style>) + Copy,
{
write(
context,
context.doc.version_control_head().unwrap_or_default(),
None,
);
}
1 change: 1 addition & 0 deletions helix-vcs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ helix-core = { version = "0.6", path = "../helix-core" }

tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "sync", "parking_lot", "macros"] }
parking_lot = "0.12"
arc-swap = { version = "1.6.0" }

git-repository = { version = "0.32", default-features = false , optional = true }
imara-diff = "0.1.5"
Expand Down
17 changes: 17 additions & 0 deletions helix-vcs/src/git.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use arc_swap::ArcSwap;
use std::path::Path;
use std::sync::Arc;

use git::objs::tree::EntryMode;
use git::sec::trust::DefaultForLevel;
Expand Down Expand Up @@ -88,6 +90,21 @@ impl DiffProvider for Git {
}
Some(data)
}

fn get_current_head_name(&self, file: &Path) -> Option<Arc<ArcSwap<Arc<str>>>> {
debug_assert!(!file.exists() || file.is_file());
debug_assert!(file.is_absolute());
let repo = Git::open_repo(file.parent()?, None)?.to_thread_local();
let head_ref = repo.head_ref().ok()?;
let head_commit = repo.head_commit().ok()?;

let name = match head_ref {
Some(reference) => reference.name().shorten().to_string(),
None => head_commit.id.to_hex_with_len(8).to_string(),
};

Some(Arc::new(ArcSwap::from_pointee(Arc::from(name))))
}
}

/// Finds the object that contains the contents of a file at a specific commit.
Expand Down
14 changes: 13 additions & 1 deletion helix-vcs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::path::Path;
use arc_swap::ArcSwap;
use std::{path::Path, sync::Arc};

#[cfg(feature = "git")]
pub use git::Git;
Expand All @@ -18,6 +19,7 @@ pub trait DiffProvider {
/// The data is returned as raw byte without any decoding or encoding performed
/// to ensure all file encodings are handled correctly.
fn get_diff_base(&self, file: &Path) -> Option<Vec<u8>>;
fn get_current_head_name(&self, file: &Path) -> Option<Arc<ArcSwap<Arc<str>>>>;
dgyurov marked this conversation as resolved.
Show resolved Hide resolved
}

#[doc(hidden)]
Expand All @@ -26,6 +28,10 @@ impl DiffProvider for Dummy {
fn get_diff_base(&self, _file: &Path) -> Option<Vec<u8>> {
None
}

fn get_current_head_name(&self, _file: &Path) -> Option<Arc<ArcSwap<Arc<str>>>> {
None
}
}

pub struct DiffProviderRegistry {
Expand All @@ -38,6 +44,12 @@ impl DiffProviderRegistry {
.iter()
.find_map(|provider| provider.get_diff_base(file))
}

pub fn get_current_head_name(&self, file: &Path) -> Option<Arc<ArcSwap<Arc<str>>>> {
self.providers
.iter()
.find_map(|provider| provider.get_current_head_name(file))
}
}

impl Default for DiffProviderRegistry {
Expand Down
18 changes: 18 additions & 0 deletions helix-view/src/document.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use anyhow::{anyhow, bail, Context, Error};
use arc_swap::access::DynAccess;
use arc_swap::ArcSwap;
use futures_util::future::BoxFuture;
use futures_util::FutureExt;
use helix_core::auto_pairs::AutoPairs;
Expand Down Expand Up @@ -143,6 +144,7 @@ pub struct Document {
language_server: Option<Arc<helix_lsp::Client>>,

diff_handle: Option<DiffHandle>,
version_control_head: Option<Arc<ArcSwap<Arc<str>>>>,
dgyurov marked this conversation as resolved.
Show resolved Hide resolved
}

use std::{fmt, mem};
Expand Down Expand Up @@ -387,6 +389,7 @@ impl Document {
language_server: None,
diff_handle: None,
config,
version_control_head: None,
}
}
pub fn default(config: Arc<dyn DynAccess<Config>>) -> Self {
Expand Down Expand Up @@ -675,6 +678,8 @@ impl Document {
None => self.diff_handle = None,
}

self.version_control_head = provider_registry.get_current_head_name(&path);

Ok(())
}

Expand Down Expand Up @@ -1093,6 +1098,19 @@ impl Document {
}
}

pub fn version_control_head(&self) -> Option<String> {
self.version_control_head
.clone()
.map(|head| (*head).load().as_ref().as_ref().to_owned())
dgyurov marked this conversation as resolved.
Show resolved Hide resolved
}
dgyurov marked this conversation as resolved.
Show resolved Hide resolved

pub fn set_version_control_head(
&mut self,
version_control_head: Option<Arc<ArcSwap<Arc<str>>>>,
) {
self.version_control_head = version_control_head;
}

#[inline]
/// Tree-sitter AST tree
pub fn syntax(&self) -> Option<&Syntax> {
Expand Down
4 changes: 4 additions & 0 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,9 @@ pub enum StatusLineElement {

/// A single space
Spacer,

/// Current version control information
VersionControl,
}

// Cursor shape is read and used on every rendered frame and so needs
Expand Down Expand Up @@ -1305,6 +1308,7 @@ impl Editor {
if let Some(diff_base) = self.diff_providers.get_diff_base(&path) {
doc.set_diff_base(diff_base, self.redraw_handle.clone());
}
doc.set_version_control_head(self.diff_providers.get_current_head_name(&path));

let id = self.new_document(doc);
let _ = self.launch_language_server(id);
Expand Down