diff --git a/evil-ghostel.el b/evil-ghostel.el index c432d14..72975a0 100644 --- a/evil-ghostel.el +++ b/evil-ghostel.el @@ -27,6 +27,35 @@ (require 'evil) (require 'ghostel) +;; --------------------------------------------------------------------------- +;; Customization +;; --------------------------------------------------------------------------- + +(defgroup evil-ghostel nil + "Evil-mode integration for ghostel." + :group 'ghostel + :prefix "evil-ghostel-") + +(defcustom evil-ghostel-initial-state 'insert + "Initial evil state for new `ghostel-mode' buffers. +Setting this option via `customize-set-variable', `setopt', or the +Customize UI calls `evil-set-initial-state' so the change takes effect +immediately. Users who prefer the raw API can call +`evil-set-initial-state' directly from their config — the registry is +last-writer-wins." + :type '(choice (const :tag "Emacs" emacs) + (const :tag "Insert" insert) + (const :tag "Normal" normal) + (symbol :tag "Other state")) + :set (lambda (sym val) + (set-default-toplevel-value sym val) + (evil-set-initial-state 'ghostel-mode val))) + +;; Apply the current value at load. Covers the case where the user set +;; the variable with plain `setq' before loading the package — in that +;; path `defcustom' preserves the value without invoking `:set'. +(evil-set-initial-state 'ghostel-mode evil-ghostel-initial-state) + ;; --------------------------------------------------------------------------- ;; Guard predicate ;; --------------------------------------------------------------------------- @@ -334,7 +363,6 @@ state transitions." :keymap evil-ghostel-mode-map (if evil-ghostel-mode (progn - (evil-set-initial-state 'ghostel-mode 'insert) (evil-ghostel--escape-stay) (add-hook 'evil-normal-state-entry-hook #'evil-ghostel--normal-state-entry nil t) diff --git a/test/evil-ghostel-test.el b/test/evil-ghostel-test.el index 309b94c..562deda 100644 --- a/test/evil-ghostel-test.el +++ b/test/evil-ghostel-test.el @@ -81,6 +81,38 @@ Uses mocks for native functions." (should-not (memq 'evil-ghostel--insert-state-entry evil-insert-state-entry-hook)))) +;; ----------------------------------------------------------------------- +;; Test: initial-state defcustom +;; ----------------------------------------------------------------------- + +(ert-deftest evil-ghostel-test-initial-state-load-applied () + "Current value of `evil-ghostel-initial-state' is registered with evil at load." + (should (eq (evil-initial-state 'ghostel-mode) + evil-ghostel-initial-state))) + +(ert-deftest evil-ghostel-test-initial-state-custom-set-updates-registry () + "Setting the option via `customize-set-variable' updates evil's registry." + (let ((orig evil-ghostel-initial-state)) + (unwind-protect + (progn + (customize-set-variable 'evil-ghostel-initial-state 'emacs) + (should (eq (evil-initial-state 'ghostel-mode) 'emacs)) + (customize-set-variable 'evil-ghostel-initial-state 'normal) + (should (eq (evil-initial-state 'ghostel-mode) 'normal))) + (customize-set-variable 'evil-ghostel-initial-state orig)))) + +(ert-deftest evil-ghostel-test-mode-activation-preserves-initial-state () + "Enabling `evil-ghostel-mode' must not clobber the initial-state setting. +Regression guard: the minor-mode body used to call +`evil-set-initial-state' on every activation, overriding user config." + (let ((orig evil-ghostel-initial-state)) + (unwind-protect + (progn + (customize-set-variable 'evil-ghostel-initial-state 'emacs) + (evil-ghostel-test--with-evil-buffer + (should (eq (evil-initial-state 'ghostel-mode) 'emacs)))) + (customize-set-variable 'evil-ghostel-initial-state orig)))) + ;; ----------------------------------------------------------------------- ;; Test: escape-stay (evil-move-cursor-back disabled) ;; -----------------------------------------------------------------------