aboutsummaryrefslogtreecommitdiff
path: root/src/config
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-22 02:21:12 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-22 02:23:35 +0300
commit0148c1379b76c5c0a9d05588c07dcb06ec32f93f (patch)
tree554766d959c738ca2aa433c3d4b4a7de25568008 /src/config
parenta9ff4012bdca0dbdbc77bc6e53a430689fc899be (diff)
feat: add git worktree workspace management
refs #137
Diffstat (limited to 'src/config')
-rw-r--r--src/config/io.rs8
-rw-r--r--src/config/keybinds.rs25
-rw-r--r--src/config/model.rs38
3 files changed, 71 insertions, 0 deletions
diff --git a/src/config/io.rs b/src/config/io.rs
index 3b483ba6..fe415d1c 100644
--- a/src/config/io.rs
+++ b/src/config/io.rs
@@ -191,6 +191,14 @@ fn load_live_config_from_str(content: &str) -> Result<LoadedConfig, Vec<String>>
);
load_live_section(
table,
+ "worktrees",
+ "worktree config",
+ &mut diagnostics,
+ &mut invalid_sections,
+ |section| config.worktrees = section,
+ );
+ load_live_section(
+ table,
"experimental",
"experimental config",
&mut diagnostics,
diff --git a/src/config/keybinds.rs b/src/config/keybinds.rs
index 1c9c491b..edd64c90 100644
--- a/src/config/keybinds.rs
+++ b/src/config/keybinds.rs
@@ -246,6 +246,9 @@ pub struct Keybinds {
pub help: ActionKeybinds,
pub settings: ActionKeybinds,
pub new_workspace: ActionKeybinds,
+ pub new_worktree: ActionKeybinds,
+ pub open_worktree: ActionKeybinds,
+ pub remove_worktree: ActionKeybinds,
pub rename_workspace: ActionKeybinds,
pub close_workspace: ActionKeybinds,
pub workspace_picker: ActionKeybinds,
@@ -375,6 +378,9 @@ impl Config {
help: action!("keys.help", &self.keys.help),
settings: action!("keys.settings", &self.keys.settings),
new_workspace: action!("keys.new_workspace", &self.keys.new_workspace),
+ new_worktree: action!("keys.new_worktree", &self.keys.new_worktree),
+ open_worktree: action!("keys.open_worktree", &self.keys.open_worktree),
+ remove_worktree: action!("keys.remove_worktree", &self.keys.remove_worktree),
rename_workspace: action!("keys.rename_workspace", &self.keys.rename_workspace),
close_workspace: action!("keys.close_workspace", &self.keys.close_workspace),
workspace_picker: action!("keys.workspace_picker", &self.keys.workspace_picker),
@@ -1042,6 +1048,25 @@ next_tab = "prefix+n"
}
#[test]
+ fn new_worktree_defaults_to_prefix_shift_g() {
+ let kb = Config::default().keybinds();
+ assert_eq!(
+ binding_triggers(&kb.new_worktree),
+ vec![BindingTrigger::Prefix((
+ KeyCode::Char('g'),
+ KeyModifiers::SHIFT
+ ))]
+ );
+ }
+
+ #[test]
+ fn open_and_remove_worktree_keybinds_are_unset_by_default() {
+ let kb = Config::default().keybinds();
+ assert!(kb.open_worktree.bindings.is_empty());
+ assert!(kb.remove_worktree.bindings.is_empty());
+ }
+
+ #[test]
fn array_bindings_allow_prefix_and_modified_direct() {
let config: Config = toml::from_str(
r#"
diff --git a/src/config/model.rs b/src/config/model.rs
index f270a69c..215e6f32 100644
--- a/src/config/model.rs
+++ b/src/config/model.rs
@@ -81,6 +81,7 @@ pub struct Config {
pub terminal: TerminalConfig,
pub keys: KeysConfig,
pub ui: UiConfig,
+ pub worktrees: WorktreesConfig,
pub advanced: AdvancedConfig,
pub experimental: ExperimentalConfig,
}
@@ -103,6 +104,12 @@ pub struct KeysConfig {
pub settings: BindingConfig,
/// Create a new workspace. Default: "prefix+shift+n"
pub new_workspace: BindingConfig,
+ /// Create a Git worktree from the selected workspace. Default: "prefix+shift+g"
+ pub new_worktree: BindingConfig,
+ /// Open an existing Git worktree from the selected workspace. Unset by default.
+ pub open_worktree: BindingConfig,
+ /// Delete the selected managed worktree checkout after confirmation. Unset by default.
+ pub remove_worktree: BindingConfig,
/// Rename the selected workspace. Default: "prefix+shift+w"
pub rename_workspace: BindingConfig,
/// Close the selected workspace. Default: "prefix+shift+d"
@@ -188,6 +195,13 @@ pub struct IndexedKeysConfig {
#[derive(Debug, Deserialize)]
#[serde(default)]
+pub struct WorktreesConfig {
+ /// Root directory under which Herdr creates <repo>/<branch-slug> checkouts.
+ pub directory: String,
+}
+
+#[derive(Debug, Deserialize)]
+#[serde(default)]
pub struct UiConfig {
pub sidebar_width: u16,
/// Minimum sidebar width (columns) when expanded. Default: 18.
@@ -288,6 +302,9 @@ impl Default for KeysConfig {
help: BindingConfig::one("prefix+?"),
settings: BindingConfig::one("prefix+s"),
new_workspace: BindingConfig::one("prefix+shift+n"),
+ new_worktree: BindingConfig::one("prefix+shift+g"),
+ open_worktree: BindingConfig::empty(),
+ remove_worktree: BindingConfig::empty(),
rename_workspace: BindingConfig::one("prefix+shift+w"),
close_workspace: BindingConfig::one("prefix+shift+d"),
workspace_picker: BindingConfig::one("prefix+w"),
@@ -326,6 +343,14 @@ impl Default for KeysConfig {
}
}
+impl Default for WorktreesConfig {
+ fn default() -> Self {
+ Self {
+ directory: "~/.herdr/worktrees".into(),
+ }
+ }
+}
+
impl Default for UiConfig {
fn default() -> Self {
Self {
@@ -432,6 +457,19 @@ show_agent_labels_on_pane_borders = true
}
#[test]
+ fn worktrees_directory_defaults_and_parses() {
+ let default_config = Config::default();
+ assert_eq!(default_config.worktrees.directory, "~/.herdr/worktrees");
+
+ let toml = r#"
+[worktrees]
+directory = "~/Projects/herdr-worktrees"
+"#;
+ let config: Config = toml::from_str(toml).unwrap();
+ assert_eq!(config.worktrees.directory, "~/Projects/herdr-worktrees");
+ }
+
+ #[test]
fn prompt_new_tab_name_defaults_on_and_parses() {
let default_config = Config::default();
assert!(default_config.ui.prompt_new_tab_name);