Function: evil-define-text-object
evil-define-text-object is a macro defined in evil-macros.el.
Signature
(evil-define-text-object OBJECT (COUNT) DOC [[KEY VALUE]...] BODY...)
Documentation
Define a text object command OBJECT.
BODY should return a range (BEG END) to the right of point if COUNT is positive, and to the left of it if negative.
Optional keyword arguments:
- :type - determines how the range applies after an operator
(inclusive, line, block, and exclusive, or a self-defined
motion type).
- :extend-selection - if non-nil (default), the text object always
enlarges the current selection. Otherwise, it replaces the current
selection.
Source Code
;; Defined in ~/.emacs.d/elpa/evil-20251108.138/evil-macros.el
(defmacro evil-define-text-object (object args &rest body)
"Define a text object command OBJECT.
BODY should return a range (BEG END) to the right of point
if COUNT is positive, and to the left of it if negative.
Optional keyword arguments:
- `:type' - determines how the range applies after an operator
(`inclusive', `line', `block', and `exclusive', or a self-defined
motion type).
- `:extend-selection' - if non-nil (default), the text object always
enlarges the current selection. Otherwise, it replaces the current
selection.
\(fn OBJECT (COUNT) DOC [[KEY VALUE]...] BODY...)"
(declare (indent defun)
(doc-string 3)
(debug (&define name lambda-list
[&optional stringp]
[&rest keywordp sexp]
def-body)))
(let* ((args (delq '&optional args))
(count (or (pop args) 'count))
(args (when args `(&optional ,@args)))
(interactive '(interactive "<c><v>"))
doc keys)
;; collect docstring
(when (stringp (car body))
(setq doc (pop body)))
;; collect keywords
(setq keys (plist-put keys :extend-selection t))
(while (keywordp (car body))
(setq keys (plist-put keys (pop body) (pop body))))
;; interactive
(when (eq (car-safe (car body)) 'interactive)
(setq interactive (pop body)))
;; macro expansion
`(evil-define-motion ,object (,count ,@args)
,@(when doc `(,doc))
,@keys
,interactive
(setq ,count (or ,count 1))
(when (/= ,count 0)
;; FIXME: These let-bindings shadow variables in args
(let ((type (evil-type ',object evil-visual-char))
(extend (and (evil-visual-state-p)
(evil-get-command-property
',object :extend-selection
',(plist-get keys :extend-selection))))
(dir evil-visual-direction)
mark point range selection)
(cond
;; Visual state: extend the current selection
((and (evil-visual-state-p)
(called-interactively-p 'any))
;; if we are at the beginning of the Visual selection,
;; go to the left (negative COUNT); if at the end,
;; go to the right (positive COUNT)
(setq dir evil-visual-direction
,count (* ,count dir))
(setq range (progn ,@body))
(when (evil-range-p range)
(setq range (evil-expand-range range))
(evil-set-type range (evil-type range type))
(setq range (evil-contract-range range))
;; the beginning is mark and the end is point
;; unless the selection goes the other way
(setq mark (evil-range-beginning range)
point (evil-range-end range)
type (evil-type
(if evil-text-object-change-visual-type
range
(evil-visual-range))))
(when (and (eq type 'line)
(not (eq type (evil-type range))))
(let ((newrange (evil-text-object-make-linewise range)))
(setq mark (evil-range-beginning newrange)
point (evil-range-end newrange))))
(when (< dir 0)
(evil-swap mark point))
;; select the union
(evil-visual-make-selection mark point type)))
;; not Visual state: return a pair of buffer positions
(t
(setq range (progn ,@body))
(unless (evil-range-p range)
(setq ,count (- ,count)
range (progn ,@body)))
(when (evil-range-p range)
(setq selection (evil-range (point) (point) type))
(if extend
(setq range (evil-range-union range selection))
(evil-set-type range (evil-type range type)))
;; possibly convert to linewise
(when (eq evil-this-type-modified 'line)
(setq range (evil-text-object-make-linewise range)))
(evil-set-range-properties range nil)
range))))))))