Function: evil-define-type

evil-define-type is a macro defined in evil-macros.el.

Signature

(evil-define-type TYPE DOC [[KEY FUNC]...])

Documentation

Define type TYPE.

DOC is a general description and shows up in all docstrings.

Optional keyword arguments:
- :expand - expansion function. This function should accept two
  positions in the current buffer, BEG and END,and return a pair of
  expanded buffer positions.
- :contract - the opposite of :expand. Optional.
- :one-to-one - non-nil if expansion is one-to-one. This means that
  :expand followed by :contract always return the original range.
- :normalize - normalization function. This function should accept
  two unexpanded positions and adjust them before expansion. May be
  used to deal with buffer boundaries.
- :string - description function. Takes two buffer positions and
  returns a human-readable string. For example "2 lines"

If further keywords and functions are specified, they are assumed to be transformations on buffer positions, like :expand and :contract.

Source Code

;; Defined in ~/.emacs.d/elpa/evil-20251108.138/evil-macros.el
(defmacro evil-define-type (type doc &rest body)
  "Define type TYPE.
DOC is a general description and shows up in all docstrings.

Optional keyword arguments:
- `:expand' - expansion function.  This function should accept two
  positions in the current buffer, BEG and END,and return a pair of
  expanded buffer positions.
- `:contract' - the opposite of `:expand'.  Optional.
- `:one-to-one' - non-nil if expansion is one-to-one.  This means that
  `:expand' followed by `:contract' always return the original range.
- `:normalize' - normalization function.  This function should accept
  two unexpanded positions and adjust them before expansion.  May be
  used to deal with buffer boundaries.
- `:string' - description function.  Takes two buffer positions and
  returns a human-readable string.  For example \"2 lines\"

If further keywords and functions are specified, they are assumed to
be transformations on buffer positions, like `:expand' and `:contract'.

\(fn TYPE DOC [[KEY FUNC]...])"
  (declare (indent defun)
           (doc-string 2)
           (debug (&define name
                           [&optional stringp]
                           [&rest [keywordp function-form]])))
  (let ((plist (list :one-to-one t)) ; standard values
        args defun-forms func key name string sym val)
    ;; keywords
    (while (keywordp (car-safe body))
      (setq key (pop body)
            val (pop body))
      (if (plist-member plist key)      ; not a function
          (setq plist (plist-put plist key val))
        (setq func val
              sym (intern (replace-regexp-in-string
                           "^:" "" (symbol-name key)))
              name (intern (format "evil-%s-%s" type sym))
              args (car (cdr-safe func))
              string (cadr (cdr-safe func))
              string (if (stringp string)
                         (format "%s\n\n" string) "")
              plist (plist-put plist key `',name))
        (push
         (cond
          ((eq key :string)
           `(defun ,name (beg end &rest properties)
              ,(format "Return size of %s from BEG to END \
with PROPERTIES.\n\n%s%s" type string doc)
              (let ((type ',type)
                    plist range)
                (when (and beg end)
                  (evil-sort beg end)
                  (save-excursion
                    (unless (plist-get properties :expanded)
                      (setq range (apply #'evil-expand
                                         beg end type properties)
                            beg (evil-range-beginning range)
                            end (evil-range-end range)
                            type (evil-type range type)
                            plist (evil-range-properties range))
                      (setq properties
                            (evil-concat-plists properties plist)))
                    (or (apply #',func beg end
                               (when ,(> (length args) 2)
                                 properties))
                        ""))))))
          (t
           `(defun ,name (beg end &rest properties)
              ,(format "Perform %s transformation on %s from BEG to END \
with PROPERTIES.\n\n%s%s" sym type string doc)
              (let ((type ',type)
                    plist range)
                (when (and beg end)
                  (evil-sort beg end)
                  (save-excursion
                    (when (memq ,key '(:expand :contract))
                      (setq properties
                            (plist-put properties
                                       :expanded ,(eq key :expand))))
                    (setq range (or (apply #',func beg end
                                           (when ,(> (length args) 2)
                                             properties))
                                    (apply #'evil-range
                                           beg end type properties))
                          beg (evil-range-beginning range)
                          end (evil-range-end range)
                          type (evil-type range type)
                          plist (evil-range-properties range))
                    (setq properties
                          (evil-concat-plists properties plist))
                    (apply #'evil-range beg end type properties)))))))
         defun-forms)))
    ;; :one-to-one requires both or neither of :expand and :contract
    (when (plist-get plist :expand)
      (setq plist (plist-put plist :one-to-one
                             (and (plist-get plist :contract)
                                  (plist-get plist :one-to-one)))))
    `(progn
       (evil--add-to-alist evil-type-properties ',type (list ,@plist))
       ,@defun-forms
       ',type)))