diff --git a/Cargo.lock b/Cargo.lock index 8628d002fd95..1322cc52b703 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1421,6 +1421,7 @@ dependencies = [ "imara-diff", "log", "parking_lot", + "serde", "tempfile", "tokio", ] diff --git a/book/src/configuration.md b/book/src/configuration.md index d8793645793c..cb869dfa297f 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -397,3 +397,17 @@ S-tab = "move_parent_node_start" tab = "extend_parent_node_end" S-tab = "extend_parent_node_start" ``` + +### `[editor.vcs]` Section + +Options for configuring VCSs (version control systems). + +| Key | Description | Default | +| `providers` | VCSs to try (in the given order) for diff computations and the `version-control` element in the statusline | See note | + +The only valid provider is `git` at the moment (if Helix is compiled with git support) + +Note: the default providers change based on how Helix was compiled: + +- If the `git` feature was used (the default): `["git"]` +- Else: `[]` diff --git a/helix-vcs/Cargo.toml b/helix-vcs/Cargo.toml index 874b92d03a62..6995bfbd7c2b 100644 --- a/helix-vcs/Cargo.toml +++ b/helix-vcs/Cargo.toml @@ -22,6 +22,7 @@ arc-swap = { version = "1.7.0" } gix = { version = "0.58.0", features = ["attributes"], default-features = false, optional = true } imara-diff = "0.1.5" anyhow = "1" +serde = { version = "1.0", features = ["derive"] } log = "0.4" diff --git a/helix-vcs/src/config.rs b/helix-vcs/src/config.rs new file mode 100644 index 000000000000..8df7ae535064 --- /dev/null +++ b/helix-vcs/src/config.rs @@ -0,0 +1,37 @@ +//! Configuration for helix's VCS handling, to provide diffs and current VCS state. + +use serde::{Deserialize, Serialize}; + +/// Main configuration struct, to be embedded in the larger editor configuration. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case", default)] +pub struct Vcs { + /// Providers for diff and state. + /// + /// The default is either the empty vec or just git (if the relevant feature is active). + #[serde(default = "default_providers")] + pub providers: Vec, +} + +impl Default for Vcs { + fn default() -> Self { + Self { + providers: default_providers(), + } + } +} + +/// Supported providers +#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum Provider { + #[cfg(feature = "git")] + Git, +} + +fn default_providers() -> Vec { + vec![ + #[cfg(feature = "git")] + Provider::Git, + ] +} diff --git a/helix-vcs/src/git/test.rs b/helix-vcs/src/git/test.rs index 9c67d2c331de..365d7d78bbab 100644 --- a/helix-vcs/src/git/test.rs +++ b/helix-vcs/src/git/test.rs @@ -2,7 +2,7 @@ use std::{fs::File, io::Write, path::Path, process::Command}; use tempfile::TempDir; -use crate::{DiffProvider, Git}; +use crate::{git::Git, DiffProvider}; fn exec_git_cmd(args: &str, git_dir: &Path) { let res = Command::new("git") diff --git a/helix-vcs/src/lib.rs b/helix-vcs/src/lib.rs index 63487fbcde6c..f86cfbb010b9 100644 --- a/helix-vcs/src/lib.rs +++ b/helix-vcs/src/lib.rs @@ -1,19 +1,15 @@ -use anyhow::{bail, Result}; +use anyhow::Result; use arc_swap::ArcSwap; use std::{path::Path, sync::Arc}; -#[cfg(feature = "git")] -pub use git::Git; -#[cfg(not(feature = "git"))] -pub use Dummy as Git; - #[cfg(feature = "git")] mod git; mod diff; - pub use diff::{DiffHandle, Hunk}; +pub mod config; + pub trait DiffProvider { /// Returns the data that a diff should be computed against /// if this provider is used. @@ -23,19 +19,8 @@ pub trait DiffProvider { fn get_current_head_name(&self, file: &Path) -> Result>>>; } -#[doc(hidden)] -pub struct Dummy; -impl DiffProvider for Dummy { - fn get_diff_base(&self, _file: &Path) -> Result> { - bail!("helix was compiled without git support") - } - - fn get_current_head_name(&self, _file: &Path) -> Result>>> { - bail!("helix was compiled without git support") - } -} - pub struct DiffProviderRegistry { + /// Built from the list in the user configuration. providers: Vec>, } @@ -67,12 +52,17 @@ impl DiffProviderRegistry { } } -impl Default for DiffProviderRegistry { - fn default() -> Self { - // currently only git is supported - // TODO make this configurable when more providers are added - let git: Box = Box::new(Git); - let providers = vec![git]; - DiffProviderRegistry { providers } +impl From<&config::Vcs> for DiffProviderRegistry { + fn from(value: &config::Vcs) -> Self { + fn mapper(p: &config::Provider) -> Box { + match p { + #[cfg(feature = "git")] + config::Provider::Git => Box::new(git::Git), + } + } + + Self { + providers: value.providers.iter().map(mapper).collect(), + } } } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index f46a0d6a6cac..64cbcfb7f3ea 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -305,6 +305,9 @@ pub struct Config { /// Which indent heuristic to use when a new line is inserted #[serde(default)] pub indent_heuristic: IndentationHeuristic, + /// VCS configuration (notably which to activate, in which order) + #[serde(default)] + pub vcs: helix_vcs::config::Vcs, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] @@ -867,6 +870,7 @@ impl Default for Config { smart_tab: Some(SmartTabConfig::default()), popup_border: PopupBorderConfig::None, indent_heuristic: IndentationHeuristic::default(), + vcs: Default::default(), } } } @@ -1060,7 +1064,7 @@ impl Editor { theme: theme_loader.default(), language_servers, diagnostics: BTreeMap::new(), - diff_providers: DiffProviderRegistry::default(), + diff_providers: DiffProviderRegistry::from(&conf.vcs), debugger: None, debugger_events: SelectAll::new(), breakpoints: HashMap::new(),