diff options
| -rw-r--r-- | CLAUDE.md | 2 | ||||
| -rw-r--r-- | internal/config/config.go | 22 | ||||
| -rw-r--r-- | internal/config/config_test.go | 39 |
3 files changed, 50 insertions, 13 deletions
@@ -41,7 +41,7 @@ Config is read from `~/.config/foostore.json` at startup (merged over defaults). - `data_dir`: Git repo where encrypted `.index` / `.data` file pairs are stored (default: `~/git/geheimlager`) - `key_file`: Path to the raw encryption key file (default: `~/.geheimlager.key`) - `export_dir`: Temporary directory for decrypted exports (default: `~/.geheimlagerexport`) -- `edit_cmd`: Editor used by the `edit` command (default: `hx`) +- `edit_cmd`: Editor used by the `edit` command (default: `$EDITOR`, falling back to `vi`) - `sync_repos`: List of git remote names to push/pull when syncing The PIN (entered at startup or via `$PIN` env var) is used to derive the AES IV; the actual key comes from `key_file`. diff --git a/internal/config/config.go b/internal/config/config.go index 6354d83..04c8302 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -31,11 +31,20 @@ type Config struct { SyncRepos []string `json:"sync_repos"` } -// defaultConfig returns a Config populated with the same defaults as the -// Ruby reference implementation's Config::DEFAULTS. It calls -// os.UserHomeDir() so that path fields expand correctly at runtime. +// defaultConfig returns a Config populated with built-in defaults. +// EditCmd honours the $EDITOR environment variable and falls back to "vi" +// when the variable is unset or empty, so users get their preferred editor +// automatically without touching the config file. +// It calls os.UserHomeDir() so that path fields expand correctly at runtime. func defaultConfig() Config { home, _ := os.UserHomeDir() + + // Prefer $EDITOR; fall back to vi if not set. + editCmd := os.Getenv("EDITOR") + if editCmd == "" { + editCmd = "vi" + } + return Config{ DataDir: filepath.Join(home, "git", "geheimlager"), ExportDir: filepath.Join(home, ".geheimlagerexport"), @@ -43,7 +52,7 @@ func defaultConfig() Config { KeyLength: 32, EncAlg: "AES-256-CBC", AddToIV: "Hello world", - EditCmd: "hx", + EditCmd: editCmd, GnomeClipboardCmd: "gpaste-client", MacOSClipboardCmd: "pbcopy", SyncRepos: []string{"git1", "git2"}, @@ -68,8 +77,9 @@ func expandPathFields(cfg *Config) { cfg.KeyFile = expandTilde(cfg.KeyFile) } -// Load reads ~/.config/geheim.json and merges it over the built-in defaults. -// Any field present in the JSON file overrides the corresponding default; +// Load reads ~/.config/foostore.json and merges it over the built-in defaults. +// Any field present in the JSON file overrides the corresponding default +// (including edit_cmd, which defaults to $EDITOR or "vi" when unset); // fields absent from the file keep their default values. // If the file is missing or contains invalid JSON a warning is printed to // stderr and the pure defaults are returned. diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 3f8ace9..715a09e 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -69,9 +69,11 @@ func TestExpandTilde(t *testing.T) { // TestLoad_defaults verifies all 10 default values when no config file exists. // HOME is redirected to a temp dir so Load() looks for a file that will not exist. +// EDITOR is unset so EditCmd falls back to "vi". func TestLoad_defaults(t *testing.T) { dir := t.TempDir() t.Setenv("HOME", dir) + t.Setenv("EDITOR", "") // ensure fallback to "vi" cfg := Load() @@ -81,7 +83,7 @@ func TestLoad_defaults(t *testing.T) { {"KeyFile", cfg.KeyFile, filepath.Join(dir, ".geheimlager.key")}, {"EncAlg", cfg.EncAlg, "AES-256-CBC"}, {"AddToIV", cfg.AddToIV, "Hello world"}, - {"EditCmd", cfg.EditCmd, "hx"}, + {"EditCmd", cfg.EditCmd, "vi"}, {"GnomeClipboardCmd", cfg.GnomeClipboardCmd, "gpaste-client"}, {"MacOSClipboardCmd", cfg.MacOSClipboardCmd, "pbcopy"}, } @@ -98,6 +100,27 @@ func TestLoad_defaults(t *testing.T) { } } +// TestLoad_editorEnvVar verifies that when $EDITOR is set, defaultConfig uses it +// as the EditCmd, and that a JSON config value overrides $EDITOR. +func TestLoad_editorEnvVar(t *testing.T) { + dir := t.TempDir() + t.Setenv("HOME", dir) + + // $EDITOR set, no config file — EditCmd must equal $EDITOR. + t.Setenv("EDITOR", "nano") + cfg := Load() + if cfg.EditCmd != "nano" { + t.Errorf("EditCmd = %q; want nano (from $EDITOR)", cfg.EditCmd) + } + + // JSON config overrides $EDITOR. + writeUserConfig(t, dir, `{"edit_cmd":"vim"}`) + cfg = Load() + if cfg.EditCmd != "vim" { + t.Errorf("EditCmd = %q; want vim (from config file)", cfg.EditCmd) + } +} + // TestLoad_override calls Load() directly (via a redirected HOME) and verifies // that JSON-supplied fields override defaults while absent fields keep defaults. func TestLoad_override(t *testing.T) { @@ -143,10 +166,12 @@ func TestLoad_pathOverride(t *testing.T) { } // TestLoad_invalid_json verifies that invalid JSON causes Load() to emit a -// warning to stderr and return defaults. +// warning to stderr and return defaults (including EditCmd = "vi" when EDITOR +// is unset). func TestLoad_invalid_json(t *testing.T) { dir := t.TempDir() t.Setenv("HOME", dir) + t.Setenv("EDITOR", "") // ensure fallback to "vi" writeUserConfig(t, dir, `{invalid json}`) var cfg Config @@ -156,8 +181,8 @@ func TestLoad_invalid_json(t *testing.T) { t.Errorf("expected warning on stderr, got: %q", stderr) } // Defaults must be returned with the redirected HOME. - if cfg.EditCmd != "hx" { - t.Errorf("EditCmd = %q; want hx (default)", cfg.EditCmd) + if cfg.EditCmd != "vi" { + t.Errorf("EditCmd = %q; want vi (default)", cfg.EditCmd) } if cfg.KeyLength != 32 { t.Errorf("KeyLength = %d; want 32 (default)", cfg.KeyLength) @@ -179,12 +204,14 @@ func TestLoad_missing_file_no_warning(t *testing.T) { // TestLoad_unreadable_file verifies that a config file that exists but cannot // be read emits a warning and returns defaults (the !os.IsNotExist branch). +// EDITOR is unset so EditCmd falls back to "vi". func TestLoad_unreadable_file(t *testing.T) { if os.Getuid() == 0 { t.Skip("running as root: permission checks do not apply") } dir := t.TempDir() t.Setenv("HOME", dir) + t.Setenv("EDITOR", "") // ensure fallback to "vi" writeUserConfig(t, dir, `{"edit_cmd":"nvim"}`) // Make the file unreadable. @@ -201,7 +228,7 @@ func TestLoad_unreadable_file(t *testing.T) { t.Errorf("expected warning on stderr, got: %q", stderr) } // Must return pure defaults, not the file content. - if cfg.EditCmd != "hx" { - t.Errorf("EditCmd = %q; want hx (default)", cfg.EditCmd) + if cfg.EditCmd != "vi" { + t.Errorf("EditCmd = %q; want vi (default)", cfg.EditCmd) } } |
