diff options
author | Dimitar Gyurov | 2023-03-10 22:42:42 +0000 |
---|---|---|
committer | GitHub | 2023-03-10 22:42:42 +0000 |
commit | 1661e4b5e1d8ebfef28f798fcb86ba2656373ba0 (patch) | |
tree | 1c3d36d81a8fe5fafd66b6b61bc5253883ed1516 | |
parent | 98415f288ffa043520b0c85bc4464dc44b85f948 (diff) |
Add a version-control statusline element (#5682)
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | book/src/configuration.md | 1 | ||||
-rw-r--r-- | helix-term/src/ui/statusline.rs | 14 | ||||
-rw-r--r-- | helix-vcs/Cargo.toml | 1 | ||||
-rw-r--r-- | helix-vcs/src/git.rs | 17 | ||||
-rw-r--r-- | helix-vcs/src/lib.rs | 14 | ||||
-rw-r--r-- | helix-view/src/document.rs | 16 | ||||
-rw-r--r-- | helix-view/src/editor.rs | 4 |
8 files changed, 67 insertions, 1 deletions
@@ -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); |