branch: elpa/evil-numbers
commit e7adac70a076ae381c03960d9d669071c1177f3a
Author: Campbell Barton <[email protected]>
Commit: Campbell Barton <[email protected]>

    Add option disable negative number support
    
    Add `evil-numbers-negative' option (default t) that controls
    whether the minus sign before a number is recognized. When set to nil,
    -5 is treated as 5, allowing increment/decrement without sign handling.
    
    This can be useful when dealing with date-ranges and numbers which tend
    not be be negative.
---
 README.org                  |  8 ++++++-
 evil-numbers.el             | 36 +++++++++++++++++++++-------
 tests/evil-numbers-tests.el | 57 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 91 insertions(+), 10 deletions(-)

diff --git a/README.org b/README.org
index 8adf86e495c..96313548719 100644
--- a/README.org
+++ b/README.org
@@ -31,7 +31,7 @@
 ** Customization
 
    - =evil-numbers-pad-default= ::
-     Set  to =t= if you want numbers to be padded with zeros (numbers with a 
leading zero are always padded).
+     Set to =t= if you want numbers to be padded with zeros (numbers with a 
leading zero are always padded).
      If you want both behaviors, all commands take an optional argument 
=padded=.
 
    - =evil-numbers-separator-chars= ::
@@ -52,6 +52,12 @@
 
      This is off by default as it doesn't follow VIM's behavior.
 
+   - =evil-numbers-negative= ::
+     Configure negative number support.
+
+     - =t= Support negative numbers (default).
+     - =nil= Numbers negative prefix is ignored, useful when numbers may be 
date/year ranges.
+
 ** Key Bindings
    Example key bindings:
 
diff --git a/evil-numbers.el b/evil-numbers.el
index 0ffdcd308d3..8c4d206d973 100644
--- a/evil-numbers.el
+++ b/evil-numbers.el
@@ -111,6 +111,11 @@ Set to nil to disable this functionality."
 This doesn't match VIM's behavior."
   :type 'boolean)
 
+(defcustom evil-numbers-negative t
+  "When non-nil, recognize and preserve negative numbers.
+When nil, the minus sign before a number is ignored, treating -5 as 5."
+  :type 'boolean)
+
 ;; ---------------------------------------------------------------------------
 ;; Internal Variables
 
@@ -446,7 +451,12 @@ replacing it by the result of NUMBER-XFORM-FN and return 
non-nil."
              (str-prev
               (funcall decode-fn
                        (concat
-                        (match-string sign-group) (match-string num-group))))
+                        (cond
+                         (evil-numbers-negative
+                          (match-string sign-group))
+                         (t
+                          ""))
+                        (match-string num-group))))
 
              (str-prev-strip
               (cond
@@ -456,7 +466,14 @@ replacing it by the result of NUMBER-XFORM-FN and return 
non-nil."
                 str-prev)))
 
              (num-prev (string-to-number str-prev-strip base))
-             (num-next (funcall number-xform-fn num-prev))
+             (num-next
+              (let ((result (funcall number-xform-fn num-prev)))
+                ;; When negative numbers are disabled, clamp to 0.
+                (cond
+                 (evil-numbers-negative
+                  result)
+                 (t
+                  (max 0 result)))))
              (str-next
               (evil-numbers--format
                (abs num-next)
@@ -493,13 +510,14 @@ replacing it by the result of NUMBER-XFORM-FN and return 
non-nil."
         (replace-match (funcall encode-fn str-next) t t nil num-group)
 
         ;; Replace the sign (as needed).
-        (cond
-         ;; From negative to positive.
-         ((and (< num-prev 0) (not (< num-next 0)))
-          (replace-match "" t t nil sign-group))
-         ;; From positive to negative.
-         ((and (not (< num-prev 0)) (< num-next 0))
-          (replace-match (funcall encode-fn "-") t t nil sign-group)))
+        (when evil-numbers-negative
+          (cond
+           ;; From negative to positive.
+           ((and (< num-prev 0) (not (< num-next 0)))
+            (replace-match "" t t nil sign-group))
+           ;; From positive to negative.
+           ((and (not (< num-prev 0)) (< num-next 0))
+            (replace-match (funcall encode-fn "-") t t nil sign-group))))
 
         (goto-char (match-end num-group)))
 
diff --git a/tests/evil-numbers-tests.el b/tests/evil-numbers-tests.el
index b200ecfd45b..dc03671a2d9 100644
--- a/tests/evil-numbers-tests.el
+++ b/tests/evil-numbers-tests.el
@@ -770,5 +770,62 @@ should result in 08 (matching original width), not 8."
         ;; Number SHOULD be incremented (cursor ends at number).
         (should (equal "foo(2|)" (buffer-string)))))))
 
+(ert-deftest simple-handle-negative-disabled ()
+  "Check `evil-numbers-negative' behavior when disabled.
+When disabled, the minus sign before a number is ignored."
+  ;; Test with option ENABLED (default behavior).
+  ;; Incrementing -5 should give -4.
+  (let ((evil-numbers-negative t)
+        (text-expected " -4| ")
+        (text-initial " -5 "))
+    (with-evil-numbers-test text-initial
+      (simulate-input
+        (kbd "C-a")
+        "a|")
+      (should (equal text-expected (buffer-string)))))
+
+  ;; Test with option DISABLED.
+  ;; The minus sign is ignored, so -5 is treated as 5.
+  ;; Incrementing 5 gives 6, result is -6 (minus untouched).
+  (let ((evil-numbers-negative nil)
+        (text-expected " -6| ")
+        (text-initial " -5 "))
+    (with-evil-numbers-test text-initial
+      (simulate-input
+        (kbd "C-a")
+        "a|")
+      (should (equal text-expected (buffer-string)))))
+
+  ;; Test decrement with option DISABLED.
+  ;; Decrementing 5 (ignoring the minus) gives 4, result is -4.
+  (let ((evil-numbers-negative nil)
+        (text-expected " -4| ")
+        (text-initial " -5 "))
+    (with-evil-numbers-test text-initial
+      (simulate-input
+        (kbd "C-x")
+        "a|")
+      (should (equal text-expected (buffer-string)))))
+
+  ;; Positive numbers should work normally with option disabled.
+  (let ((evil-numbers-negative nil)
+        (text-expected " 6| ")
+        (text-initial " 5 "))
+    (with-evil-numbers-test text-initial
+      (simulate-input
+        (kbd "C-a")
+        "a|")
+      (should (equal text-expected (buffer-string)))))
+
+  ;; Decrementing 0 with option disabled should clamp to 0.
+  (let ((evil-numbers-negative nil)
+        (text-expected " 0| ")
+        (text-initial " 0 "))
+    (with-evil-numbers-test text-initial
+      (simulate-input
+        (kbd "C-x")
+        "a|")
+      (should (equal text-expected (buffer-string))))))
+
 (provide 'evil-numbers-tests)
 ;;; evil-numbers-tests.el ends here

Reply via email to