refactor(lib): add + use defbackport! macro

In the future, doom-lib (among other things) will be byte-compiled as
part of 'doom sync'. To spare runtime the overhead of checking for these
functions, I've wrapped these in a macro. It also makes their
definitions a tad simpler.
This commit is contained in:
Henrik Lissner 2022-09-06 19:03:33 +02:00
parent 5ebc2528d8
commit edaa887bd9
No known key found for this signature in database
GPG key ID: B60957CA074D39A3

View file

@ -777,68 +777,66 @@ testing advice (when combined with `rotate-text').
(dolist (target (cdr targets)) (dolist (target (cdr targets))
(advice-remove target #',symbol))))) (advice-remove target #',symbol)))))
(defmacro defbackport! (type symbol &rest body)
"Backport a function/macro/alias from later versions of Emacs."
(declare (indent defun) (doc-string 4))
(unless (fboundp (doom-unquote symbol))
`(,type ,symbol ,@body)))
;; ;;
;;; Backports ;;; Backports
;; `format-spec' wasn't autoloaded until 28.1 ;; `format-spec' wasn't autoloaded until 28.1
(unless (fboundp 'format-spec) (defbackport! autoload 'format-spec "format-spec")
(autoload #'format-spec "format-spec"))
;; Introduced in Emacs 28.1 ;; Introduced in Emacs 28.1
(unless (fboundp 'ensure-list) (defbackport! defun ensure-list (object)
(defun ensure-list (object) "Return OBJECT as a list.
"Return OBJECT as a list.
If OBJECT is already a list, return OBJECT itself. If it's If OBJECT is already a list, return OBJECT itself. If it's
not a list, return a one-element list containing OBJECT." not a list, return a one-element list containing OBJECT."
(declare (pure t) (side-effect-free t)) (declare (pure t) (side-effect-free t))
(if (listp object) (if (listp object) object (list object)))
object
(list object))))
;; Introduced in Emacs 28.1 ;; Introduced in Emacs 28.1
(unless (fboundp 'always) (defbackport! defun always (&rest _args)
(defun always (&rest _arguments) "Do nothing and return t.
"Do nothing and return t.
This function accepts any number of ARGUMENTS, but ignores them. This function accepts any number of ARGUMENTS, but ignores them.
Also see `ignore'." Also see `ignore'."
t)) t)
;; Introduced in 28.1 ;; Introduced in Emacs 28.1
(unless (fboundp 'file-name-concat) (defbackport! defun file-name-concat (directory &rest components)
(defun file-name-concat (directory &rest components) "Append COMPONENTS to DIRECTORY and return the resulting string.
"Append COMPONENTS to DIRECTORY and return the resulting string.
Elements in COMPONENTS must be a string or nil. Elements in COMPONENTS must be a string or nil.
DIRECTORY or the non-final elements in COMPONENTS may or may not end DIRECTORY or the non-final elements in COMPONENTS may or may not end
with a slash -- if they don't end with a slash, a slash will be with a slash -- if they don't end with a slash, a slash will be
inserted before contatenating." inserted before contatenating."
(mapconcat (mapconcat
#'identity #'identity
(save-match-data (save-match-data
(cl-loop for str in (cons directory components) (cl-loop for str in (cons directory components)
when (and str (/= 0 (length str)) when (and str (/= 0 (length str))
(string-match "\\(.+\\)/?" str)) (string-match "\\(.+\\)/?" str))
collect (match-string 1 str))) collect (match-string 1 str)))
"/"))) "/"))
;; Introduced in 28.1 ;; Introduced in Emacs 28.1
(unless (fboundp 'with-environment-variables) (defbackport! defmacro with-environment-variables (variables &rest body)
(defmacro with-environment-variables (variables &rest body) "Set VARIABLES in the environment and execute BODY.
"Set VARIABLES in the environment and execute BODY.
VARIABLES is a list of variable settings of the form (VAR VALUE), VARIABLES is a list of variable settings of the form (VAR VALUE),
where VAR is the name of the variable (a string) and VALUE where VAR is the name of the variable (a string) and VALUE
is its value (also a string). is its value (also a string).
The previous values will be be restored upon exit." The previous values will be be restored upon exit."
(declare (indent 1) (debug (sexp body))) (declare (indent 1) (debug (sexp body)))
(unless (consp variables) (unless (consp variables)
(error "Invalid VARIABLES: %s" variables)) (error "Invalid VARIABLES: %s" variables))
`(let ((process-environment (copy-sequence process-environment))) `(let ((process-environment (copy-sequence process-environment)))
,@(mapcar (lambda (elem) ,@(cl-loop for var in variables
`(setenv ,(car elem) ,(cadr elem))) collect `(setenv ,(car var) ,(cadr var)))
variables) ,@body))
,@body)))
(provide 'doom-lib) (provide 'doom-lib)
;;; doom-lib.el ends here ;;; doom-lib.el ends here