aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitar Gyurov2023-03-10 22:42:42 +0000
committerGitHub2023-03-10 22:42:42 +0000
commit1661e4b5e1d8ebfef28f798fcb86ba2656373ba0 (patch)
tree1c3d36d81a8fe5fafd66b6b61bc5253883ed1516
parent98415f288ffa043520b0c85bc4464dc44b85f948 (diff)
Add a version-control statusline element (#5682)
-rw-r--r--Cargo.lock1
-rw-r--r--book/src/configuration.md1
-rw-r--r--helix-term/src/ui/statusline.rs14
-rw-r--r--helix-vcs/Cargo.toml1
-rw-r--r--helix-vcs/src/git.rs17
-rw-r--r--helix-vcs/src/lib.rs14
-rw-r--r--helix-view/src/document.rs16
-rw-r--r--helix-view/src/editor.rs4
8 files changed, 67 insertions, 1 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a1a9eae4..de985bca 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1212,6 +1212,7 @@ dependencies = [
name = "helix-vcs"
version = "0.6.0"
dependencies = [
+ "arc-swap",
"gix",
"helix-core",
"imara-diff",
diff --git a/book/src/configuration.md b/book/src/configuration.md
index 4b62ca52..e698646b 100644
--- a/book/src/configuration.md
+++ b/book/src/configuration.md
@@ -111,6 +111,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
diff --git a/helix-term/src/ui/statusline.rs b/helix-term/src/ui/statusline.rs
index 3e7065b8..88786351 100644
--- a/helix-term/src/ui/statusline.rs
+++ b/helix-term/src/ui/statusline.rs
@@ -159,6 +159,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,
}
}
@@ -476,3 +477,16 @@ 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,
+{
+ let head = context
+ .doc
+ .version_control_head()
+ .unwrap_or_default()
+ .to_string();
+
+ write(context, head, None);
+}
diff --git a/helix-vcs/Cargo.toml b/helix-vcs/Cargo.toml
index 789ee795..58c078b4 100644
--- a/helix-vcs/Cargo.toml
+++ b/helix-vcs/Cargo.toml
@@ -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" }
gix = { version = "0.39.0", default-features = false , optional = true }
imara-diff = "0.1.5"
diff --git a/helix-vcs/src/git.rs b/helix-vcs/src/git.rs
index 2a540c8d..1732bdd0 100644
--- a/helix-vcs/src/git.rs
+++ b/helix-vcs/src/git.rs
@@ -1,4 +1,6 @@
+use arc_swap::ArcSwap;
use std::path::Path;
+use std::sync::Arc;
use gix::objs::tree::EntryMode;
use gix::sec::trust::DefaultForLevel;
@@ -87,6 +89,21 @@ impl DiffProvider for Git {
}
Some(data)
}
+
+ fn get_current_head_name(&self, file: &Path) -> Option<Arc<ArcSwap<Box<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(name.into_boxed_str())))
+ }
}
/// Finds the object that contains the contents of a file at a specific commit.
diff --git a/helix-vcs/src/lib.rs b/helix-vcs/src/lib.rs
index 97320d32..6f5e40d0 100644
--- a/helix-vcs/src/lib.rs
+++ b/helix-vcs/src/lib.rs
@@ -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;
@@ -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<Box<str>>>>;
}
#[doc(hidden)]
@@ -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<Box<str>>>> {
+ None
+ }
}
pub struct DiffProviderRegistry {
@@ -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<Box<str>>>> {
+ self.providers
+ .iter()
+ .find_map(|provider| provider.get_current_head_name(file))
+ }
}
impl Default for DiffProviderRegistry {
diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs
index db12fb92..b2a9ddec 100644
--- a/helix-view/src/document.rs
+++ b/helix-view/src/document.rs
@@ -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;
@@ -158,6 +159,7 @@ pub struct Document {
language_server: Option<Arc<helix_lsp::Client>>,
diff_handle: Option<DiffHandle>,
+ version_control_head: Option<Arc<ArcSwap<Box<str>>>>,
}
use std::{fmt, mem};
@@ -404,6 +406,7 @@ impl Document {
language_server: None,
diff_handle: None,
config,
+ version_control_head: None,
}
}
pub fn default(config: Arc<dyn DynAccess<Config>>) -> Self {
@@ -707,6 +710,8 @@ impl Document {
None => self.diff_handle = None,
}
+ self.version_control_head = provider_registry.get_current_head_name(&path);
+
Ok(())
}
@@ -1158,6 +1163,17 @@ impl Document {
}
}
+ pub fn version_control_head(&self) -> Option<Arc<Box<str>>> {
+ self.version_control_head.as_ref().map(|a| a.load_full())
+ }
+
+ pub fn set_version_control_head(
+ &mut self,
+ version_control_head: Option<Arc<ArcSwap<Box<str>>>>,
+ ) {
+ self.version_control_head = version_control_head;
+ }
+
#[inline]
/// Tree-sitter AST tree
pub fn syntax(&self) -> Option<&Syntax> {
diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs
index 1b4664ff..41aa707f 100644
--- a/helix-view/src/editor.rs
+++ b/helix-view/src/editor.rs
@@ -467,6 +467,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
@@ -1297,6 +1300,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);