branch: elpa/evil-numbers
commit 616aff9e5cee012954756ed2715209fa90308cdf
Author: Campbell Barton <[email protected]>
Commit: Campbell Barton <[email protected]>
Refactor: use shift-number for core implementation
Replace evil-numbers' number manipulation with shift-number package:
- Use shift-number-increment-at-point-with-search as the backend
- Pass customization values via keyword arguments:
:pad-default, :negative, :separator-chars, :case, :motion
- Extract helper lambdas to reduce code duplication
Documentation:
- Add decimal literals (with positive sign) to Detected Literals
- Use https instead of http for GitHub URL
- Remove shift-number from Similar Packages (it's a dependency)
Resolve #4.
---
README.org | 9 +-
evil-numbers.el | 740 ++++++++------------------------------------------------
2 files changed, 102 insertions(+), 647 deletions(-)
diff --git a/README.org b/README.org
index 96313548719..a75273cdec0 100644
--- a/README.org
+++ b/README.org
@@ -15,6 +15,7 @@
** Detected Literals
+ - Decimal, e.g. =42=, =-17=, =+5=, =007=.
- Binary, e.g. =0b0101=, =0B0101=.
- Octal, e.g. =0o755=, =0O700=.
- Hexadecimal, e.g. =0xDEADBEEF=, =0XCAFE=.
@@ -88,23 +89,27 @@
* Install
+** Dependencies
+ This package requires the
[[https://melpa.org/#/shift-number][shift-number]] package, which provides the
+ core number manipulation logic.
+
** Basic Installation
Put in =load-path=, =(require 'evil-numbers)= and set key bindings.
** Use Package
Assuming you have the =melpa= repository enabled, =use-package= can be used
as follows.
+ The =shift-number= dependency will be installed automatically.
#+BEGIN_SRC emacs-lisp
(use-package evil-numbers)
#+END_SRC
* Known Bugs
- See http://github.com/juliapath/evil-numbers/issues
+ See https://github.com/juliapath/evil-numbers/issues
* Similar Packages
- [[https://melpa.org/#/mouse-slider-mode][Mouse Slider Package]]
- [[https://melpa.org/#/number][Number Package]]
- - [[https://melpa.org/#/shift-number][Shift Number Package]]
- [[https://www.emacswiki.org/emacs/IncrementNumber][Emacs Wiki (Increment
Number)]]
* Contributors
diff --git a/evil-numbers.el b/evil-numbers.el
index 8c4d206d973..0a024dac7c7 100644
--- a/evil-numbers.el
+++ b/evil-numbers.el
@@ -12,8 +12,8 @@
;; URL: http://github.com/juliapath/evil-numbers
;; Git-Repository: git://github.com/juliapath/evil-numbers.git
;; Created: 2011-09-02
-;; Version: 0.7
-;; Package-Requires: ((emacs "24.1") (evil "1.2.0"))
+;; Version: 0.8
+;; Package-Requires: ((emacs "24.1") (evil "1.2.0") (shift-number "0.2"))
;; Keywords: convenience tools
;;; Commentary:
@@ -54,25 +54,7 @@
;;; Code:
(require 'evil)
-
-(eval-when-compile
- ;; For `pcase-dolist'.
- (require 'pcase))
-
-
-;; ---------------------------------------------------------------------------
-;; Compatibility
-
-(when (version< emacs-version "29.1")
- (defsubst pos-bol (&optional n)
- "Return the position at the line beginning.
-N specifies which line (default 1, the current line)."
- (line-beginning-position n))
- (defsubst pos-eol (&optional n)
- "Return the position at the line end.
-N specifies which line (default 1, the current line)."
- (line-end-position n)))
-
+(require 'shift-number)
;; ---------------------------------------------------------------------------
;; Custom Variables
@@ -106,9 +88,7 @@ Set to nil to disable this functionality."
(const :tag "Lower Case" downcase)))
(defcustom evil-numbers-use-cursor-at-end-of-number nil
- "When non-nil, recognize numbers directly before the cursor.
-
-This doesn't match VIM's behavior."
+ "When non-nil, recognize numbers directly before the cursor."
:type 'boolean)
(defcustom evil-numbers-negative t
@@ -116,541 +96,14 @@ This doesn't match VIM's behavior."
When nil, the minus sign before a number is ignored, treating -5 as 5."
:type 'boolean)
-;; ---------------------------------------------------------------------------
-;; Internal Variables
-
-(defconst evil-numbers--chars-superscript "⁰¹²³⁴⁵⁶⁷⁸⁹"
- "String containing superscript digit characters 0-9.")
-(defconst evil-numbers--chars-subscript "₀₁₂₃₄₅₆₇₈₉"
- "String containing subscript digit characters 0-9.")
-
-(defun evil-numbers--build-script-alist (minus-char plus-char digit-chars)
- "Build an alist mapping ASCII characters to script equivalents.
-MINUS-CHAR is the script minus sign.
-PLUS-CHAR is the script plus sign.
-DIGIT-CHARS is a 10-character string of script digits 0-9."
- (cons
- (cons ?- minus-char)
- (cons
- (cons ?+ plus-char)
- (mapcar
- (lambda (i)
- (cons
- (string-to-char (number-to-string i))
- (aref digit-chars i)))
- (number-sequence 0 9)))))
-
-(defconst evil-numbers--superscript-alist
- (evil-numbers--build-script-alist ?⁻ ?⁺ evil-numbers--chars-superscript)
- "Alist mapping regular characters to superscript equivalents.")
-
-(defconst evil-numbers--subscript-alist
- (evil-numbers--build-script-alist ?₋ ?₊ evil-numbers--chars-subscript)
- "Alist mapping regular characters to subscript equivalents.")
-
-
-;; ---------------------------------------------------------------------------
-;; Internal String Separator Utilities
-;;
-;; To remove and restore separators.
-
-(defun evil-numbers--strip-chars (str sep-chars)
- "Remove SEP-CHARS from STR."
- (dotimes (i (length sep-chars))
- (let ((ch (char-to-string (aref sep-chars i))))
- (setq str (replace-regexp-in-string (regexp-quote ch) "" str t t))))
- str)
-
-(defun evil-numbers--strip-chars-apply (str-src str-dst sep-chars)
- "Restore SEP-CHARS positions from STR-SRC into STR-DST."
- (let ((sep-chars-list (append sep-chars nil))
- ;; Convert strings to lists.
- (str-src-rev (nreverse (append str-src nil)))
- (str-dst-rev (nreverse (append str-dst nil)))
- (result (list)))
- (while str-dst-rev
- (let ((ch-src (pop str-src-rev)))
- (cond
- ((and ch-src (memq ch-src sep-chars-list))
- (push ch-src result))
- (t
- (push (pop str-dst-rev) result)))))
- (apply #'string result)))
-
-;; ---------------------------------------------------------------------------
-;; Internal Utilities
-;;
-;; Not directly related to incrementing numbers.
-
-(defun evil-numbers--case-category (str default)
- "Categorize the case of STR.
-Return DEFAULT if STR has no case (e.g., digits only), otherwise:
-- 1: Upper case.
-- -1: Lower case.
-- nil: Mixed case."
- (let ((str-dn (downcase str))
- (str-up (upcase str)))
- (cond
- ((string-equal str str-dn)
- (cond
- ((string-equal str str-up)
- default)
- (t
- -1)))
- (t
- (cond
- ((string-equal str str-up)
- 1)
- (t
- nil))))))
-
-(defun evil-numbers--format-binary (number &optional width fillchar)
- "Format NUMBER as binary.
-Fill up to WIDTH with FILLCHAR (defaults to ?0) if binary
-representation of NUMBER is smaller than WIDTH."
- (let ((nums (list))
- (fillchar (or fillchar ?0)))
- (while (> number 0)
- (push (number-to-string (% number 2)) nums)
- (setq number (truncate number 2)))
- (let ((len (length nums)))
- (apply #'concat
- (cond
- ((and width (< len width))
- (make-string (- width len) fillchar))
- (t
- ""))
- nums))))
-
-(defun evil-numbers--format (num width base)
- "Format NUM with at least WIDTH digits in BASE."
- (cond
- ((= base 2)
- (evil-numbers--format-binary num width))
- ((= base 8)
- (format (format "%%0%do" width) num))
- ((= base 16)
- (format (format "%%0%dX" width) num))
- ((= base 10)
- (format (format "%%0%dd" width) num))
- (t
- "")))
-
-(defun evil-numbers--skip-chars-impl (ch-skip ch-sep-optional dir ch-num limit)
- "Wrapper for `skip-chars-forward' and `skip-chars-backward'.
-
-CH-SKIP: Characters to skip.
-CH-SEP-OPTIONAL: Separator characters (single instances are stepped over).
-DIR: Direction to step in (1 or -1).
-CH-NUM: Number of characters to step.
-LIMIT: Point which will not be stepped past."
- (let* ((is-forward (< 0 dir))
- (skip-chars-fn
- (cond
- (is-forward
- #'skip-chars-forward)
- (t
- #'skip-chars-backward)))
- (clamp-fn
- (cond
- (is-forward
- #'min)
- (t
- #'max)))
- (skipped
- (abs
- (funcall skip-chars-fn
- ch-skip
- ;; Limit.
- (funcall clamp-fn (+ (point) (* ch-num dir)) limit)))))
-
- ;; Step over single separators, as long as there is a number after them.
- ;; Allow '100,123' and '16_777_216' to be handled as single numbers.
- (when ch-sep-optional
- (let ((point-next nil)
- (skipped-next 0))
- (setq ch-num (- ch-num skipped))
- (while (and (not (zerop ch-num))
- (save-excursion
- (and (eq
- 1
- (evil-numbers--skip-chars-impl
- ch-sep-optional nil dir 1 limit))
- (progn
- ;; Not counted towards 'skipped'
- ;; as this character is to be ignored entirely.
- (setq skipped-next
- (evil-numbers--skip-chars-impl
- ch-skip nil dir ch-num limit))
- (unless (zerop skipped-next)
- (setq point-next (point))
- ;; Found (apply `point-next').
- t)))))
- ;; Step over the separator and contents found afterwards.
- (when point-next
- (goto-char point-next)
- (setq skipped (+ skipped skipped-next))
- (setq ch-num (- ch-num skipped-next))
- t))))
-
- skipped))
-
-(defun evil-numbers--match-from-skip-chars
- (match-chars dir limit do-check do-match)
- "Match MATCH-CHARS in DIR (-1 or 1), until LIMIT.
-
-When DO-CHECK is non-nil, any failure to match returns nil.
-When DO-MATCH is non-nil, match data is set.
-
-Each item in MATCH-CHARS is a list of (CH-SKIP CH-NUM CH-SEP-OPTIONAL).
-- CH-SKIP is the argument to pass to
- `skip-chars-forward' or `skip-chars-backward'.
-- CH-NUM specifies how many characters to match.
- Valid values:
- - Symbol `+' one or more.
- - Symbol `*' zero or more.
- - An integer: match exactly this many.
-- CH-SEP-OPTIONAL specifies optional separator characters."
- (catch 'result
- (let* ((is-forward (< 0 dir))
- (point-init (point))
- ;; Fill when `do-match' is set.
- (match-list (list)))
-
- ;; Sanity check.
- (when (cond
- (is-forward
- (> (point) limit))
- (t
- (< (point) limit)))
- (error "Limit is on wrong side of point (internal error)"))
-
- (unless is-forward
- (setq match-chars (reverse match-chars)))
-
- (pcase-dolist (`(,ch-skip ,ch-num ,ch-sep-optional) match-chars)
- ;; Beginning of the match.
- (when do-match
- (push (point) match-list))
-
- (cond
- ((integerp ch-num)
- (let ((skipped
- (evil-numbers--skip-chars-impl
- ch-skip ch-sep-optional dir ch-num limit)))
- (when do-check
- (unless (eq skipped ch-num)
- (throw 'result nil)))))
- ((eq ch-num '+)
- (let ((skipped
- (evil-numbers--skip-chars-impl
- ch-skip ch-sep-optional dir most-positive-fixnum limit)))
- (when do-check
- (unless (>= skipped 1)
- (throw 'result nil)))))
-
- ;; No length checking needed as zero is acceptable.
- ;; Skip these characters if they exist.
- ((eq ch-num '*)
- (evil-numbers--skip-chars-impl
- ch-skip ch-sep-optional dir most-positive-fixnum limit))
- ((eq ch-num '\?)
- (evil-numbers--skip-chars-impl ch-skip ch-sep-optional dir 1 limit))
- (t
- (error "Unknown type %S (internal error)" ch-num)))
-
- ;; End of the match.
- (when do-match
- (push (point) match-list)))
-
- ;; Add match group 0 (full match) at the beginning of the list.
- (when do-match
- (setq match-list
- (cond ; `point-init' `point' `match-list'.
- (is-forward
- (cons point-init (cons (point) (nreverse match-list))))
- (t ; `point' `point-init' `match-list'.
- (cons (point) (cons point-init match-list)))))
-
- (set-match-data match-list)))
- t))
-
-(defun evil-numbers--swap-alist (alist)
- "Swap keys and values in association list ALIST."
- (mapcar (lambda (x) (cons (cdr x) (car x))) alist))
-
-(defun evil-numbers--translate-with-alist (alist string)
- "Translate every character in STRING using ALIST."
- (funcall (cond
- ((stringp string)
- #'concat)
- (t
- #'identity))
- (mapcar (lambda (c) (cdr (assoc c alist))) string)))
-
-(defun evil-numbers--encode-super (x)
- "Convert string X to superscript."
- (evil-numbers--translate-with-alist evil-numbers--superscript-alist x))
-(defun evil-numbers--decode-super (x)
- "Convert string X from superscript to regular characters."
- (evil-numbers--translate-with-alist
- (evil-numbers--swap-alist evil-numbers--superscript-alist) x))
-
-(defun evil-numbers--encode-sub (x)
- "Convert string X to subscript."
- (evil-numbers--translate-with-alist evil-numbers--subscript-alist x))
-(defun evil-numbers--decode-sub (x)
- "Convert string X from subscript to regular characters."
- (evil-numbers--translate-with-alist
- (evil-numbers--swap-alist evil-numbers--subscript-alist) x))
-
-
-;; ---------------------------------------------------------------------------
-;; Internal Implementation
-
-(defun evil-numbers--inc-at-pt-impl-with-match-chars
- (match-chars
- ;; Numeric & other options.
- sign-group num-group base beg end padded do-case
- ;; Callbacks.
- range-check-fn number-xform-fn decode-fn encode-fn)
- "Perform the increment/decrement within BEG and END.
-
-For MATCH-CHARS docs see `evil-numbers--match-from-skip-chars'.
-NUM-GROUP is the match group used to evaluate the number.
-SIGN-GROUP is the match group used for the sign ('-' or '+').
-
-When PADDED is non-nil,
-the number keeps its current width (with leading zeroes).
-
-When RANGE-CHECK-FN is non-nil, it's called with the match beginning & end.
-A nil result causes this function to skip this match.
-
-When DO-CASE is non-nil, apply case handling for hexadecimal numbers.
-
-DECODE-FN converts the matched string to regular characters for parsing.
-ENCODE-FN converts the result back for replacement.
-
-When all characters are found in sequence, evaluate the number in BASE,
-replacing it by the result of NUMBER-XFORM-FN and return non-nil."
- (save-match-data
- (when (and (save-excursion
- ;; Skip backwards (as needed), there may be no
- ;; characters to skip back, so don't check the result.
- (evil-numbers--match-from-skip-chars
- match-chars -1 beg nil nil)
- ;; Skip forwards from the beginning, setting match data.
- (evil-numbers--match-from-skip-chars match-chars 1 end t t))
-
- ;; Either there is no range checking or the range must
- ;; be accepted by the caller.
- (or (null range-check-fn)
- (funcall range-check-fn (match-beginning 0) (match-end 0))))
-
- (let* ((sep-char (nth 2 (nth (1- num-group) match-chars)))
- (str-prev
- (funcall decode-fn
- (concat
- (cond
- (evil-numbers-negative
- (match-string sign-group))
- (t
- ""))
- (match-string num-group))))
-
- (str-prev-strip
- (cond
- (sep-char
- (evil-numbers--strip-chars str-prev sep-char))
- (t
- str-prev)))
-
- (num-prev (string-to-number str-prev-strip base))
- (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)
- (cond
- (padded
- (- (match-end num-group) (match-beginning num-group)))
- (t
- 1))
- base)))
-
- ;; Maintain case.
- (when do-case
- ;; Upper case (already set), no need to handle here.
- (cond
- ;; Keep current case.
- ((null evil-numbers-case)
- (when (eq -1 (or (evil-numbers--case-category str-prev -1) -1))
- (setq str-next (downcase str-next))))
- ((eq evil-numbers-case 'downcase)
- (setq str-next (downcase str-next)))))
-
- (when sep-char
- ;; This is a relatively expensive operation,
- ;; only apply separators back if any were found to begin with.
- (unless (string-equal str-prev str-prev-strip)
- (setq str-next
- (evil-numbers--strip-chars-apply
- str-prev str-next sep-char))))
-
- ;; Replace number then sign to work around Emacs bug #74666.
- ;; Order doesn't affect correctness, but this order avoids the bug.
-
- ;; Replace the number.
- (replace-match (funcall encode-fn str-next) t t nil num-group)
-
- ;; Replace the sign (as needed).
- (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)))
-
- t)))
-
-(defun evil-numbers--inc-at-pt-impl
- (beg end padded range-check-fn number-xform-fn)
- "Increment/decrement the number at point, limited by BEG and END.
-
-Keep padding when PADDED is non-nil.
-
-See `evil-numbers--inc-at-pt-impl-with-match-chars' for details on
-RANGE-CHECK-FN and NUMBER-XFORM-FN.
-
-Return non-nil on success, leaving the point at the end of the number."
- (or
- ;; Find binary literals:
- ;; 0[bB][01]+, e.g. 0b101 or 0B0.
- (evil-numbers--inc-at-pt-impl-with-match-chars
- `(("+-" \?) ("0" 1) ("bB" 1) ("01" + ,evil-numbers-separator-chars))
- ;; Sign, number groups & base.
- 1 4 2
- ;; Other arguments.
- beg end padded nil range-check-fn number-xform-fn
- ;; Decode & encode callbacks.
- #'identity #'identity)
-
- ;; Find octal literals:
- ;; 0[oO][0-7]+, e.g. 0o42 or 0O5.
- (evil-numbers--inc-at-pt-impl-with-match-chars
-
- `(("+-" \?) ("0" 1) ("oO" 1) ("0-7" + ,evil-numbers-separator-chars))
- ;; Sign, number groups & base.
- 1 4 8
- ;; Other arguments.
- beg end padded nil range-check-fn number-xform-fn
- ;; Decode & encode callbacks.
- #'identity #'identity)
-
- ;; Find hex literals:
- ;; 0[xX][0-9a-fA-F]+, e.g. 0xBEEF or 0Xcafe.
- (evil-numbers--inc-at-pt-impl-with-match-chars
- `(("+-" \?) ("0" 1) ("xX" 1) ("[:xdigit:]" +
,evil-numbers-separator-chars))
- ;; Sign, number groups & base.
- 1 4 16
- ;; Other arguments.
- beg end padded t range-check-fn number-xform-fn
- ;; Decode & encode callbacks.
- #'identity #'identity)
-
- ;; Find decimal literals:
- ;; [0-9]+, e.g. 42 or 23.
- (evil-numbers--inc-at-pt-impl-with-match-chars
- `(("+-" \?) ("0123456789" + ,evil-numbers-separator-chars))
- ;; Sign, number groups & base.
- 1 2 10
- ;; Other arguments.
- beg end padded nil range-check-fn number-xform-fn
- ;; Decode & encode callbacks.
- #'identity #'identity)
-
- ;; Find decimal literals (superscript).
- (evil-numbers--inc-at-pt-impl-with-match-chars
- `(("⁺⁻" \?) (,evil-numbers--chars-superscript + nil))
- ;; Sign, number groups & base.
- 1 2 10
- ;; Other arguments.
- beg end padded nil range-check-fn number-xform-fn
- ;; Decode & encode callbacks.
- #'evil-numbers--decode-super #'evil-numbers--encode-super)
-
- ;; Find decimal literals (subscript).
- (evil-numbers--inc-at-pt-impl-with-match-chars
- `(("₊₋" \?) (,evil-numbers--chars-subscript + nil))
- ;; Sign, number groups & base.
- 1 2 10
- ;; Other arguments.
- beg end padded nil range-check-fn number-xform-fn
- ;; Decode & encode callbacks.
- #'evil-numbers--decode-sub #'evil-numbers--encode-sub)))
-
-(defun evil-numbers--inc-at-pt-impl-with-search
- (amount beg end padded range-check-fn)
- "Change the number at point by AMOUNT, limited by BEG and END.
-
-Keep padding when PADDED is non-nil.
-
-See `evil-numbers--inc-at-pt-impl-with-match-chars' for details on
-RANGE-CHECK-FN.
-
-Return non-nil on success, leaving the point at the end of the number."
- (let ((found nil))
- (save-match-data
- ;; Search for any text that might be part of a number,
- ;; if `evil-numbers--inc-at-pt-impl' cannot parse it - that's fine,
- ;; keep searching until `end'.
- ;; This avoids doubling up on number parsing logic.
- ;;
- ;; Note that the while body is empty.
- (while (and
- ;; Found item, exit the loop.
- (null
- (when (evil-numbers--inc-at-pt-impl
- ;; Clamp limits to line bounds.
- ;; The caller may use a range that spans lines to
- ;; allow searching and finding items across
- ;; multiple lines (currently used for selection).
- (max beg (pos-bol))
- (min end (pos-eol))
- padded
- range-check-fn
- (lambda (n) (+ n amount)))
- (setq found t)))
-
- ;; No more matches found, exit the loop.
- (re-search-forward (concat
- "["
- "[:xdigit:]"
- evil-numbers--chars-superscript
- evil-numbers--chars-subscript
- "]")
- end t))))
- found))
-
;; ---------------------------------------------------------------------------
;; Public Functions
;;;###autoload (autoload 'evil-numbers/inc-at-pt "evil-numbers" nil t)
-(evil-define-operator evil-numbers/inc-at-pt
- (amount beg end type &optional incremental padded)
-
- "Increment the number at point or after point before `end-of-line' by AMOUNT.
+(evil-define-operator
+ evil-numbers/inc-at-pt (amount beg end type &optional incremental padded)
+ "Increment the number at point or after point before `end-of-line' by AMOUNT.
When region is selected, increment all numbers in the region by AMOUNT.
INCREMENTAL causes the first number to be increased by 1*AMOUNT,
@@ -661,94 +114,90 @@ PADDED is whether numbers should be padded (e.g.
decrementing 10 -> 09).
- t: is the opposite of `evil-numbers-pad-default',
- `'(t)': enables padding and `'(nil)' disables padding.
-Numbers with a leading zero are always padded.
-Signs are preserved when padding is enabled, for example: increasing a
-negative number to a positive will result in a number with a + sign."
- :motion
- nil
- (interactive "*<c><R>")
-
- (setq amount (or amount 1))
- (setq padded
- (cond
- ((consp padded)
- (car padded))
- (t
- (funcall (cond
- (padded
- #'not)
- (t
- #'identity))
- evil-numbers-pad-default))))
- (cond
- ;; Handle selection (block or line).
- ;; Increment each number in the selection.
- ((and beg end type)
- (let ((count 1))
- (save-excursion
- (funcall (cond
- ((eq type 'block)
- (lambda (f) (evil-apply-on-block f beg end nil)))
- (t
- (lambda (f) (funcall f beg end))))
- (lambda (beg end)
- (evil-with-restriction
- beg end (goto-char beg)
- (while (evil-numbers--inc-at-pt-impl-with-search
- (* amount count) (point) (point-max) padded nil)
- (when incremental
- (setq count (+ count 1))))))))))
-
- ;; Handle the simple case, either the cursor is over a number,
- ;; or a number exists between the cursor and `end-of-line'.
- (t
- (let ((point-next
- (save-excursion
- (when (evil-numbers--inc-at-pt-impl-with-search
- amount (pos-bol) (pos-eol) padded
- ;; Optional range checking function, only needed when
- ;; `evil-numbers-use-cursor-at-end-of-number' is nil.
- (cond
- (evil-numbers-use-cursor-at-end-of-number
- nil)
- (t
- ;; VIM doesn't allow the number directly before
- ;; the cursor to be manipulated.
- ;; This function checks the range to disallow that case.
- ;;
- ;; Note that this turns out to be simpler than enforcing
- ;; the limit in the searching logic.
- (let ((point-init (point)))
- (lambda (_beg end) (< point-init end))))))
- (point)))))
-
- (cond
- ((null point-next)
- ;; Point not found, note that VIM doesn't report anything in this case.
- (message "No number at point or until end of line")
- nil)
- (t
- ;; Moves point one position back to conform with VIM,
- ;; see `evil-adjust-cursor' for details.
- (goto-char (1- point-next))
- t))))))
+Numbers with a leading zero are always padded."
+ :motion nil (interactive "*<c><R>")
+
+ (setq amount (or amount 1))
+ (setq padded
+ (cond
+ ((consp padded)
+ (car padded))
+ (padded
+ (not evil-numbers-pad-default))
+ (t
+ evil-numbers-pad-default)))
+
+ (let ((do-increment
+ (lambda (amt range &optional range-check-fn)
+ (shift-number-increment-at-point-with-search
+ :amount amt
+ :range range
+ :pad-default padded
+ :negative evil-numbers-negative
+ :separator-chars evil-numbers-separator-chars
+ :case evil-numbers-case
+ :motion t
+ :range-check-fn range-check-fn))))
+ (cond
+ ;; Handle selection (block or line).
+ ;; Increment each number in the selection.
+ ((and beg end type)
+ (let* ((count 1)
+ (process-region
+ (lambda (beg end)
+ (evil-with-restriction
+ beg end (goto-char beg)
+ (while (funcall do-increment
+ (* amount count)
+ (cons (point) (point-max)))
+ (when incremental
+ (incf count)))))))
+ (save-excursion
+ (if (eq type 'block)
+ (evil-apply-on-block process-region beg end nil)
+ (funcall process-region beg end)))))
+
+ ;; Handle the simple case, either the cursor is over a number,
+ ;; or a number exists between the cursor and `end-of-line'.
+ (t
+ (let ((point-next
+ (save-excursion
+ (when (funcall
+ do-increment
+ amount
+ (cons (line-beginning-position) (line-end-position))
+ ;; Ignore numbers directly before the cursor unless
+ ;; `evil-numbers-use-cursor-at-end-of-number' is enabled.
+ (unless evil-numbers-use-cursor-at-end-of-number
+ (let ((point-init (point)))
+ (lambda (_beg end) (< point-init end)))))
+ (point)))))
+ (cond
+ ((null point-next)
+ (message "No number at point or until end of line")
+ nil)
+ (t
+ ;; Moves point one position back, see `evil-adjust-cursor'.
+ (goto-char (1- point-next))
+ t)))))))
;;;###autoload (autoload 'evil-numbers/dec-at-pt "evil-numbers" nil t)
-(evil-define-operator evil-numbers/dec-at-pt
- (amount beg end type &optional incremental padded)
- "Decrement the number at point or after point before `end-of-line' by AMOUNT.
+(evil-define-operator
+ evil-numbers/dec-at-pt
+ (amount beg end type &optional incremental padded)
+ "Decrement the number at point or after point before `end-of-line' by AMOUNT.
If a region is active, decrement all the numbers in the region by AMOUNT."
- :motion nil
+ :motion nil
- (interactive "*<c><R>")
- (evil-numbers/inc-at-pt (- (or amount 1)) beg end type incremental padded))
+ (interactive "*<c><R>")
+ (evil-numbers/inc-at-pt (- (or amount 1)) beg end type incremental padded))
;;;###autoload (autoload 'evil-numbers/inc-at-pt-incremental "evil-numbers"
nil t)
-(evil-define-operator evil-numbers/inc-at-pt-incremental
- (amount beg end type padded)
- "Increment the number by AMOUNT.
-
+(evil-define-operator
+ evil-numbers/inc-at-pt-incremental
+ (amount beg end type padded)
+ "Increment the number by AMOUNT.
When there is no active region, use the number at point
or between the point and the `end-of-line'.
@@ -756,19 +205,20 @@ When a region is active, increment all the numbers in the
region by AMOUNT*n, wh
n is the index of the number among the numbers in the region, starting at 1.
That is, increment the first number by AMOUNT, the second by 2*AMOUNT,
and so on."
- :motion nil
+ :motion nil
- (interactive "*<c><R>")
- (evil-numbers/inc-at-pt amount beg end type 'incremental padded))
+ (interactive "*<c><R>")
+ (evil-numbers/inc-at-pt amount beg end type 'incremental padded))
;;;###autoload (autoload 'evil-numbers/dec-at-pt-incremental "evil-numbers"
nil t)
-(evil-define-operator evil-numbers/dec-at-pt-incremental
- (amount beg end type padded)
- "Like `evil-numbers/inc-at-pt-incremental' but with negated argument AMOUNT."
- :motion nil
-
- (interactive "*<c><R>")
- (evil-numbers/inc-at-pt (- (or amount 1)) beg end type 'incremental padded))
+(evil-define-operator
+ evil-numbers/dec-at-pt-incremental
+ (amount beg end type padded)
+ "Like `evil-numbers/inc-at-pt-incremental' but with negated argument AMOUNT."
+ :motion nil
+
+ (interactive "*<c><R>")
+ (evil-numbers/inc-at-pt (- (or amount 1)) beg end type 'incremental padded))
(provide 'evil-numbers)