From 51c60f03598a2cc634a85679794eaf16f27e49ae Mon Sep 17 00:00:00 2001 From: Chris Bouchard Date: Sun, 22 Sep 2024 22:51:50 -0400 Subject: [PATCH] Provide a unified (lsp-interface INTERFACE ...) pcase form This commit provides a new unified pcase form (lsp-interface INTERFACE ...) to replace the old per-interface (INTERFACE ...) forms -- the latter are now deprecated. (Unfortunately, I don't think there's a way to mark a pcase form as obsolete.) I've turned the existing pcase-defmacro definition into a helper function. The new pcase form delegates to that helper function, and the old pcase forms now delegate to the new form. This change addresses a few issues, which are detailed in #4430. In short: * The existing forms aren't namespaced. * The lsp-mode package adds hundreds of forms, which each add several lines to pcase's generated docstring, adding up to over 1000 lines. * Starting in Emacs 1.31, the number of forms added by lsp-mode causes a noticeable slowdown when loading the interactive help for pcase. --- lsp-protocol.el | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/lsp-protocol.el b/lsp-protocol.el index d5b98a00e5..fcfbff0c79 100644 --- a/lsp-protocol.el +++ b/lsp-protocol.el @@ -129,7 +129,7 @@ Allowed params: %s" interface (reverse (-map #'cl-first params))) $$result)) (-partition 2 plist)) $$result))) - `(pcase-defmacro ,interface (&rest property-bindings) + `(cl-defun ,(intern (format "lsp--pcase-macroexpander-%s" interface)) (&rest property-bindings) ,(if lsp-use-plists ``(and (pred listp) @@ -225,6 +225,8 @@ Allowed params: %s" interface (reverse (-map #'cl-first params))) output-bindings) (setf current-list (cddr current-list)))))) output-bindings)))) + `(pcase-defmacro ,interface (&rest property-bindings) + `(lsp-interface ,',interface ,@property-bindings)) (-mapcat (-lambda ((label . name)) (list `(defun ,(intern (format "lsp:%s-%s" @@ -246,6 +248,21 @@ Allowed params: %s" interface (reverse (-map #'cl-first params))) (apply #'append) (cl-list* 'progn)))) +(pcase-defmacro lsp-interface (interface &rest property-bindings) + "If EXPVAL is an instance of the LSP interface INTERFACE, destructure its +properties. + +Each :PROPERTY key may be followed by an optional PATTERN, which is a `pcase' +pattern to apply to the property value. Otherwise, PROPERTY is bound to the +property value. + +\(fn INTERFACE [:PROPERTY [PATTERN]]...)" + (cl-check-type interface symbol) + (let ((lsp-pcase-macroexpander + (intern (format "lsp--pcase-macroexpander-%s" interface)))) + (cl-assert (fboundp lsp-pcase-macroexpander) "not a known LSP interface: %s" interface) + (apply lsp-pcase-macroexpander property-bindings))) + (if lsp-use-plists (progn (defun lsp-get (from key)