From d8dbb90931995c84dfe4a49716aeb9f5320c7737 Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Mon, 22 Jul 2019 18:04:50 +0200 Subject: [PATCH] Add core plist library --- core/autoload/plist.el | 84 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 core/autoload/plist.el diff --git a/core/autoload/plist.el b/core/autoload/plist.el new file mode 100644 index 000000000..88c50b54a --- /dev/null +++ b/core/autoload/plist.el @@ -0,0 +1,84 @@ +;;; ../work/conf/doom-emacs/core/autoload/plist.el -*- lexical-binding: t; -*- + +;;;###autoload +(defun doom-plist-get (plist prop &optional nil-value) + "Return PROP in PLIST, if it exists. Otherwise NIL-VALUE." + (if-let (val (plist-member plist prop)) + (cadr val) + nil-value)) + +;;;###autoload +(defun doom-plist-merge (from-plist to-plist) + "Destructively merge FROM-PLIST onto TO-PLIST" + (while plist + (plist-put! old-plist (pop plist) (pop plist)))) + +;;;###autoload +(defun doom-plist-delete-nil (plist) + "Delete `nil' properties from a copy of PLIST." + (let (p) + (while plist + (if (car plist) + (setq p (plist-put p (car plist) (nth 1 plist)))) + (setq plist (cddr plist))) + p)) + +;;;###autoload +(defun doom-plist-delete (plist prop) + "Delete PROP from a copy of PLIST." + (let (p) + (while plist + (if (not (eq prop (car plist))) + (setq p (plist-put p (car plist) (nth 1 plist)))) + (setq plist (cddr plist))) + p)) + + +;; +;;; Macros + +;;;###autoload +(cl-defmacro doplist! ((arglist plist &optional retval) &rest body) + "Loop over a PLIST's (property value) pairs then return RETVAL. + +Evaluate BODY with either ARGLIST bound to (cons PROP VAL) or, if ARGLIST is a +list, the pair is destructured into (CAR . CDR)." + (declare (indent defun)) + (let ((plist-var (make-symbol "plist"))) + `(let ((,plist-var ,plist)) + (while ,plist-var + (let ,(if (listp arglist) + `((,(pop arglist) (pop ,plist-var)) + (,(pop arglist) (pop ,plist-var))) + `((,arglist (cons (pop ,plist-var) + (pop ,plist-var))))) + ,@body))))) + +;;;###autoload +(defmacro plist-put! (plist prop value) + "Set PROP to VALUE in PLIST in-place." + (let ((plist-var (make-symbol "plist"))) + `(setq ,plist (plist-put ,plist ,prop ,value)))) + +;;;###autoload +(defmacro plist-delete! (plist prop) + "Delete PROP from PLIST in-place." + `(setq ,plist (doom-plist-delete ,plist ,prop))) + +;;;###autoload +(defmacro with-plist! (plist props &rest body) + "With props bound from PLIST to PROPS, evaluate BODY. + +PROPS is a list of symbols. Each one is converted to a keyword and then its +value is looked up in the PLIST and bound to the symbol for the duration of +BODY." + (declare (indent 2)) + (let ((plist-sym (make-symbol "plist"))) + `(let* ((,plist-sym ,plist) + ,@(cl-loop for prop in props + collect + `(,prop + (plist-get + ,plist-sym + ,(doom-keyword-intern (symbol-name prop)))))) + ,@body)))