diff options
author | Lars Wirzenius <liw@liw.fi> | 2021-07-18 12:25:58 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2021-07-18 12:25:58 +0300 |
commit | ad392a22b55ef278797753b82f10e4cd50a8febb (patch) | |
tree | fe4b393b30b355434a67899fa5772d6563fab82f /emacs.d | |
parent | ba6730976e5ec75116cfb8eab85209f03e288336 (diff) | |
download | liw-dot-files-ad392a22b55ef278797753b82f10e4cd50a8febb.tar.gz |
emacs: add elpa files
Sponsored-by: author
Diffstat (limited to 'emacs.d')
133 files changed, 48501 insertions, 0 deletions
diff --git a/emacs.d/.lsp-session-v1 b/emacs.d/.lsp-session-v1 new file mode 100644 index 0000000..4b1b5fd --- /dev/null +++ b/emacs.d/.lsp-session-v1 @@ -0,0 +1 @@ +#s(lsp-session ("/home/liw/pers/vmadm/git") nil #s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8125 data ()) #s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8125 data ()) #s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8125 data ()))
\ No newline at end of file diff --git a/emacs.d/elpa/archives/gnu/archive-contents.signed b/emacs.d/elpa/archives/gnu/archive-contents.signed new file mode 100644 index 0000000..7e93e80 --- /dev/null +++ b/emacs.d/elpa/archives/gnu/archive-contents.signed @@ -0,0 +1 @@ +Good signature from 066DAFCB81E42C40 GNU ELPA Signing Agent (2019) <elpasign@elpa.gnu.org> (trust undefined) created at 2021-07-16T00:05:02+0300 using RSA
\ No newline at end of file diff --git a/emacs.d/elpa/dash-20210708.2009/dash-autoloads.el b/emacs.d/elpa/dash-20210708.2009/dash-autoloads.el new file mode 100644 index 0000000..3a96693 --- /dev/null +++ b/emacs.d/elpa/dash-20210708.2009/dash-autoloads.el @@ -0,0 +1,74 @@ +;;; dash-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "dash" "dash.el" (0 0 0 0)) +;;; Generated autoloads from dash.el + +(autoload 'dash-fontify-mode "dash" "\ +Toggle fontification of Dash special variables. + +If called interactively, enable Dash-Fontify mode if ARG is +positive, and disable it if ARG is zero or negative. If called +from Lisp, also enable the mode if ARG is omitted or nil, and +toggle it if ARG is `toggle'; disable the mode otherwise. + +Dash-Fontify mode is a buffer-local minor mode intended for Emacs +Lisp buffers. Enabling it causes the special variables bound in +anaphoric Dash macros to be fontified. These anaphoras include +`it', `it-index', `acc', and `other'. In older Emacs versions +which do not dynamically detect macros, Dash-Fontify mode +additionally fontifies Dash macro calls. + +See also `dash-fontify-mode-lighter' and +`global-dash-fontify-mode'. + +\(fn &optional ARG)" t nil) + +(put 'global-dash-fontify-mode 'globalized-minor-mode t) + +(defvar global-dash-fontify-mode nil "\ +Non-nil if Global Dash-Fontify mode is enabled. +See the `global-dash-fontify-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `global-dash-fontify-mode'.") + +(custom-autoload 'global-dash-fontify-mode "dash" nil) + +(autoload 'global-dash-fontify-mode "dash" "\ +Toggle Dash-Fontify mode in all buffers. +With prefix ARG, enable Global Dash-Fontify mode if ARG is positive; +otherwise, disable it. If called from Lisp, enable the mode if +ARG is omitted or nil. + +Dash-Fontify mode is enabled in all buffers where +`dash--turn-on-fontify-mode' would do it. +See `dash-fontify-mode' for more information on Dash-Fontify mode. + +\(fn &optional ARG)" t nil) + +(autoload 'dash-register-info-lookup "dash" "\ +Register the Dash Info manual with `info-lookup-symbol'. +This allows Dash symbols to be looked up with \\[info-lookup-symbol]." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "dash" '("!cdr" "!cons" "--" "->" "-a" "-butlast" "-c" "-d" "-e" "-f" "-gr" "-i" "-juxt" "-keep" "-l" "-m" "-no" "-o" "-p" "-r" "-s" "-t" "-u" "-value-to-list" "-when-let" "-zip" "dash-"))) + +;;;*** + +;;;### (autoloads nil nil ("dash-pkg.el") (0 0 0 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; dash-autoloads.el ends here diff --git a/emacs.d/elpa/dash-20210708.2009/dash-pkg.el b/emacs.d/elpa/dash-20210708.2009/dash-pkg.el new file mode 100644 index 0000000..97c683b --- /dev/null +++ b/emacs.d/elpa/dash-20210708.2009/dash-pkg.el @@ -0,0 +1,12 @@ +(define-package "dash" "20210708.2009" "A modern list library for Emacs" + '((emacs "24")) + :commit "2675596b9ac1c4b9d47b93e227f06f8ec6755ec6" :authors + '(("Magnar Sveen" . "magnars@gmail.com")) + :maintainer + '("Magnar Sveen" . "magnars@gmail.com") + :keywords + '("extensions" "lisp") + :url "https://github.com/magnars/dash.el") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/emacs.d/elpa/dash-20210708.2009/dash.el b/emacs.d/elpa/dash-20210708.2009/dash.el new file mode 100644 index 0000000..4e56da4 --- /dev/null +++ b/emacs.d/elpa/dash-20210708.2009/dash.el @@ -0,0 +1,3533 @@ +;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*- + +;; Copyright (C) 2012-2021 Free Software Foundation, Inc. + +;; Author: Magnar Sveen <magnars@gmail.com> +;; Version: 2.19.0 +;; Package-Requires: ((emacs "24")) +;; Keywords: extensions, lisp +;; Homepage: https://github.com/magnars/dash.el + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; A modern list API for Emacs. +;; +;; See its overview at https://github.com/magnars/dash.el#functions. + +;;; Code: + +;; TODO: `gv' was introduced in Emacs 24.3, so remove this and all +;; calls to `defsetf' when support for earlier versions is dropped. +(eval-when-compile + (unless (fboundp 'gv-define-setter) + (require 'cl))) + +(defgroup dash () + "Customize group for Dash, a modern list library." + :group 'extensions + :group 'lisp + :prefix "dash-") + +(defmacro !cons (car cdr) + "Destructive: Set CDR to the cons of CAR and CDR." + (declare (debug (form symbolp))) + `(setq ,cdr (cons ,car ,cdr))) + +(defmacro !cdr (list) + "Destructive: Set LIST to the cdr of LIST." + (declare (debug (symbolp))) + `(setq ,list (cdr ,list))) + +(defmacro --each (list &rest body) + "Evaluate BODY for each element of LIST and return nil. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating BODY. +This is the anaphoric counterpart to `-each'." + (declare (debug (form body)) (indent 1)) + (let ((l (make-symbol "list")) + (i (make-symbol "i"))) + `(let ((,l ,list) + (,i 0) + it it-index) + (ignore it it-index) + (while ,l + (setq it (pop ,l) it-index ,i ,i (1+ ,i)) + ,@body)))) + +(defun -each (list fn) + "Call FN on each element of LIST. +Return nil; this function is intended for side effects. + +Its anaphoric counterpart is `--each'. + +For access to the current element's index in LIST, see +`-each-indexed'." + (declare (indent 1)) + (ignore (mapc fn list))) + +(defalias '--each-indexed '--each) + +(defun -each-indexed (list fn) + "Call FN on each index and element of LIST. +For each ITEM at INDEX in LIST, call (funcall FN INDEX ITEM). +Return nil; this function is intended for side effects. + +See also: `-map-indexed'." + (declare (indent 1)) + (--each list (funcall fn it-index it))) + +(defmacro --each-while (list pred &rest body) + "Evaluate BODY for each item in LIST, while PRED evaluates to non-nil. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating PRED or BODY. Once +an element is reached for which PRED evaluates to nil, no further +BODY is evaluated. The return value is always nil. +This is the anaphoric counterpart to `-each-while'." + (declare (debug (form form body)) (indent 2)) + (let ((l (make-symbol "list")) + (i (make-symbol "i")) + (elt (make-symbol "elt"))) + `(let ((,l ,list) + (,i 0) + ,elt it it-index) + (ignore it it-index) + (while (and ,l (setq ,elt (pop ,l) it ,elt it-index ,i) ,pred) + (setq it ,elt it-index ,i ,i (1+ ,i)) + ,@body)))) + +(defun -each-while (list pred fn) + "Call FN on each ITEM in LIST, while (PRED ITEM) is non-nil. +Once an ITEM is reached for which PRED returns nil, FN is no +longer called. Return nil; this function is intended for side +effects. + +Its anaphoric counterpart is `--each-while'." + (declare (indent 2)) + (--each-while list (funcall pred it) (funcall fn it))) + +(defmacro --each-r (list &rest body) + "Evaluate BODY for each element of LIST in reversed order. +Each element of LIST in turn, starting at its end, is bound to +`it' and its index within LIST to `it-index' before evaluating +BODY. The return value is always nil. +This is the anaphoric counterpart to `-each-r'." + (declare (debug (form body)) (indent 1)) + (let ((v (make-symbol "vector")) + (i (make-symbol "i"))) + ;; Implementation note: building a vector is considerably faster + ;; than building a reversed list (vector takes less memory, so + ;; there is less GC), plus `length' comes naturally. In-place + ;; `nreverse' would be faster still, but BODY would be able to see + ;; that, even if the modification was undone before we return. + `(let* ((,v (vconcat ,list)) + (,i (length ,v)) + it it-index) + (ignore it it-index) + (while (> ,i 0) + (setq ,i (1- ,i) it-index ,i it (aref ,v ,i)) + ,@body)))) + +(defun -each-r (list fn) + "Call FN on each element of LIST in reversed order. +Return nil; this function is intended for side effects. + +Its anaphoric counterpart is `--each-r'." + (--each-r list (funcall fn it))) + +(defmacro --each-r-while (list pred &rest body) + "Eval BODY for each item in reversed LIST, while PRED evals to non-nil. +Each element of LIST in turn, starting at its end, is bound to +`it' and its index within LIST to `it-index' before evaluating +PRED or BODY. Once an element is reached for which PRED +evaluates to nil, no further BODY is evaluated. The return value +is always nil. +This is the anaphoric counterpart to `-each-r-while'." + (declare (debug (form form body)) (indent 2)) + (let ((v (make-symbol "vector")) + (i (make-symbol "i")) + (elt (make-symbol "elt"))) + `(let* ((,v (vconcat ,list)) + (,i (length ,v)) + ,elt it it-index) + (ignore it it-index) + (while (when (> ,i 0) + (setq ,i (1- ,i) it-index ,i) + (setq ,elt (aref ,v ,i) it ,elt) + ,pred) + (setq it-index ,i it ,elt) + ,@body)))) + +(defun -each-r-while (list pred fn) + "Call FN on each ITEM in reversed LIST, while (PRED ITEM) is non-nil. +Once an ITEM is reached for which PRED returns nil, FN is no +longer called. Return nil; this function is intended for side +effects. + +Its anaphoric counterpart is `--each-r-while'." + (--each-r-while list (funcall pred it) (funcall fn it))) + +(defmacro --dotimes (num &rest body) + "Evaluate BODY NUM times, presumably for side effects. +BODY is evaluated with the local variable `it' temporarily bound +to successive integers running from 0, inclusive, to NUM, +exclusive. BODY is not evaluated if NUM is less than 1. +This is the anaphoric counterpart to `-dotimes'." + (declare (debug (form body)) (indent 1)) + (let ((n (make-symbol "num")) + (i (make-symbol "i"))) + `(let ((,n ,num) + (,i 0) + it) + (ignore it) + (while (< ,i ,n) + (setq it ,i ,i (1+ ,i)) + ,@body)))) + +(defun -dotimes (num fn) + "Call FN NUM times, presumably for side effects. +FN is called with a single argument on successive integers +running from 0, inclusive, to NUM, exclusive. FN is not called +if NUM is less than 1. + +This function's anaphoric counterpart is `--dotimes'." + (declare (indent 1)) + (--dotimes num (funcall fn it))) + +(defun -map (fn list) + "Apply FN to each item in LIST and return the list of results. + +This function's anaphoric counterpart is `--map'." + (mapcar fn list)) + +(defmacro --map (form list) + "Eval FORM for each item in LIST and return the list of results. +Each element of LIST in turn is bound to `it' before evaluating +FORM. +This is the anaphoric counterpart to `-map'." + (declare (debug (def-form form))) + `(mapcar (lambda (it) (ignore it) ,form) ,list)) + +(defmacro --reduce-from (form init list) + "Accumulate a value by evaluating FORM across LIST. +This macro is like `--each' (which see), but it additionally +provides an accumulator variable `acc' which it successively +binds to the result of evaluating FORM for the current LIST +element before processing the next element. For the first +element, `acc' is initialized with the result of evaluating INIT. +The return value is the resulting value of `acc'. If LIST is +empty, FORM is not evaluated, and the return value is the result +of INIT. +This is the anaphoric counterpart to `-reduce-from'." + (declare (debug (form form form))) + `(let ((acc ,init)) + (--each ,list (setq acc ,form)) + acc)) + +(defun -reduce-from (fn init list) + "Reduce the function FN across LIST, starting with INIT. +Return the result of applying FN to INIT and the first element of +LIST, then applying FN to that result and the second element, +etc. If LIST is empty, return INIT without calling FN. + +This function's anaphoric counterpart is `--reduce-from'. + +For other folds, see also `-reduce' and `-reduce-r'." + (--reduce-from (funcall fn acc it) init list)) + +(defmacro --reduce (form list) + "Accumulate a value by evaluating FORM across LIST. +This macro is like `--reduce-from' (which see), except the first +element of LIST is taken as INIT. Thus if LIST contains a single +item, it is returned without evaluating FORM. If LIST is empty, +FORM is evaluated with `it' and `acc' bound to nil. +This is the anaphoric counterpart to `-reduce'." + (declare (debug (form form))) + (let ((lv (make-symbol "list-value"))) + `(let ((,lv ,list)) + (if ,lv + (--reduce-from ,form (car ,lv) (cdr ,lv)) + ;; Explicit nil binding pacifies lexical "variable left uninitialized" + ;; warning. See issue #377 and upstream https://bugs.gnu.org/47080. + (let ((acc nil) (it nil)) + (ignore acc it) + ,form))))) + +(defun -reduce (fn list) + "Reduce the function FN across LIST. +Return the result of applying FN to the first two elements of +LIST, then applying FN to that result and the third element, etc. +If LIST contains a single element, return it without calling FN. +If LIST is empty, return the result of calling FN with no +arguments. + +This function's anaphoric counterpart is `--reduce'. + +For other folds, see also `-reduce-from' and `-reduce-r'." + (if list + (-reduce-from fn (car list) (cdr list)) + (funcall fn))) + +(defmacro --reduce-r-from (form init list) + "Accumulate a value by evaluating FORM across LIST in reverse. +This macro is like `--reduce-from', except it starts from the end +of LIST. +This is the anaphoric counterpart to `-reduce-r-from'." + (declare (debug (form form form))) + `(let ((acc ,init)) + (--each-r ,list (setq acc ,form)) + acc)) + +(defun -reduce-r-from (fn init list) + "Reduce the function FN across LIST in reverse, starting with INIT. +Return the result of applying FN to the last element of LIST and +INIT, then applying FN to the second-to-last element and the +previous result of FN, etc. That is, the first argument of FN is +the current element, and its second argument the accumulated +value. If LIST is empty, return INIT without calling FN. + +This function is like `-reduce-from' but the operation associates +from the right rather than left. In other words, it starts from +the end of LIST and flips the arguments to FN. Conceptually, it +is like replacing the conses in LIST with applications of FN, and +its last link with INIT, and evaluating the resulting expression. + +This function's anaphoric counterpart is `--reduce-r-from'. + +For other folds, see also `-reduce-r' and `-reduce'." + (--reduce-r-from (funcall fn it acc) init list)) + +(defmacro --reduce-r (form list) + "Accumulate a value by evaluating FORM across LIST in reverse order. +This macro is like `--reduce', except it starts from the end of +LIST. +This is the anaphoric counterpart to `-reduce-r'." + (declare (debug (form form))) + `(--reduce ,form (reverse ,list))) + +(defun -reduce-r (fn list) + "Reduce the function FN across LIST in reverse. +Return the result of applying FN to the last two elements of +LIST, then applying FN to the third-to-last element and the +previous result of FN, etc. That is, the first argument of FN is +the current element, and its second argument the accumulated +value. If LIST contains a single element, return it without +calling FN. If LIST is empty, return the result of calling FN +with no arguments. + +This function is like `-reduce' but the operation associates from +the right rather than left. In other words, it starts from the +end of LIST and flips the arguments to FN. Conceptually, it is +like replacing the conses in LIST with applications of FN, +ignoring its last link, and evaluating the resulting expression. + +This function's anaphoric counterpart is `--reduce-r'. + +For other folds, see also `-reduce-r-from' and `-reduce'." + (if list + (--reduce-r (funcall fn it acc) list) + (funcall fn))) + +(defmacro --reductions-from (form init list) + "Return a list of FORM's intermediate reductions across LIST. +That is, a list of the intermediate values of the accumulator +when `--reduce-from' (which see) is called with the same +arguments. +This is the anaphoric counterpart to `-reductions-from'." + (declare (debug (form form form))) + `(nreverse + (--reduce-from (cons (let ((acc (car acc))) (ignore acc) ,form) acc) + (list ,init) + ,list))) + +(defun -reductions-from (fn init list) + "Return a list of FN's intermediate reductions across LIST. +That is, a list of the intermediate values of the accumulator +when `-reduce-from' (which see) is called with the same +arguments. + +This function's anaphoric counterpart is `--reductions-from'. + +For other folds, see also `-reductions' and `-reductions-r'." + (--reductions-from (funcall fn acc it) init list)) + +(defmacro --reductions (form list) + "Return a list of FORM's intermediate reductions across LIST. +That is, a list of the intermediate values of the accumulator +when `--reduce' (which see) is called with the same arguments. +This is the anaphoric counterpart to `-reductions'." + (declare (debug (form form))) + (let ((lv (make-symbol "list-value"))) + `(let ((,lv ,list)) + (if ,lv + (--reductions-from ,form (car ,lv) (cdr ,lv)) + (let (acc it) + (ignore acc it) + (list ,form)))))) + +(defun -reductions (fn list) + "Return a list of FN's intermediate reductions across LIST. +That is, a list of the intermediate values of the accumulator +when `-reduce' (which see) is called with the same arguments. + +This function's anaphoric counterpart is `--reductions'. + +For other folds, see also `-reductions' and `-reductions-r'." + (if list + (--reductions-from (funcall fn acc it) (car list) (cdr list)) + (list (funcall fn)))) + +(defmacro --reductions-r-from (form init list) + "Return a list of FORM's intermediate reductions across reversed LIST. +That is, a list of the intermediate values of the accumulator +when `--reduce-r-from' (which see) is called with the same +arguments. +This is the anaphoric counterpart to `-reductions-r-from'." + (declare (debug (form form form))) + `(--reduce-r-from (cons (let ((acc (car acc))) (ignore acc) ,form) acc) + (list ,init) + ,list)) + +(defun -reductions-r-from (fn init list) + "Return a list of FN's intermediate reductions across reversed LIST. +That is, a list of the intermediate values of the accumulator +when `-reduce-r-from' (which see) is called with the same +arguments. + +This function's anaphoric counterpart is `--reductions-r-from'. + +For other folds, see also `-reductions' and `-reductions-r'." + (--reductions-r-from (funcall fn it acc) init list)) + +(defmacro --reductions-r (form list) + "Return a list of FORM's intermediate reductions across reversed LIST. +That is, a list of the intermediate values of the accumulator +when `--reduce-re' (which see) is called with the same arguments. +This is the anaphoric counterpart to `-reductions-r'." + (declare (debug (form list))) + (let ((lv (make-symbol "list-value"))) + `(let ((,lv (reverse ,list))) + (if ,lv + (--reduce-from (cons (let ((acc (car acc))) (ignore acc) ,form) acc) + (list (car ,lv)) + (cdr ,lv)) + ;; Explicit nil binding pacifies lexical "variable left uninitialized" + ;; warning. See issue #377 and upstream https://bugs.gnu.org/47080. + (let ((acc nil) (it nil)) + (ignore acc it) + (list ,form)))))) + +(defun -reductions-r (fn list) + "Return a list of FN's intermediate reductions across reversed LIST. +That is, a list of the intermediate values of the accumulator +when `-reduce-r' (which see) is called with the same arguments. + +This function's anaphoric counterpart is `--reductions-r'. + +For other folds, see also `-reductions-r-from' and +`-reductions'." + (if list + (--reductions-r (funcall fn it acc) list) + (list (funcall fn)))) + +(defmacro --filter (form list) + "Return a new list of the items in LIST for which FORM evals to non-nil. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. +This is the anaphoric counterpart to `-filter'. +For the opposite operation, see also `--remove'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each ,list (when ,form (push it ,r))) + (nreverse ,r)))) + +(defun -filter (pred list) + "Return a new list of the items in LIST for which PRED returns non-nil. + +Alias: `-select'. + +This function's anaphoric counterpart is `--filter'. + +For similar operations, see also `-keep' and `-remove'." + (--filter (funcall pred it) list)) + +(defalias '-select '-filter) +(defalias '--select '--filter) + +(defmacro --remove (form list) + "Return a new list of the items in LIST for which FORM evals to nil. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. +This is the anaphoric counterpart to `-remove'. +For the opposite operation, see also `--filter'." + (declare (debug (form form))) + `(--filter (not ,form) ,list)) + +(defun -remove (pred list) + "Return a new list of the items in LIST for which PRED returns nil. + +Alias: `-reject'. + +This function's anaphoric counterpart is `--remove'. + +For similar operations, see also `-keep' and `-filter'." + (--remove (funcall pred it) list)) + +(defalias '-reject '-remove) +(defalias '--reject '--remove) + +(defmacro --remove-first (form list) + "Remove the first item from LIST for which FORM evals to non-nil. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. This is a +non-destructive operation, but only the front of LIST leading up +to the removed item is a copy; the rest is LIST's original tail. +If no item is removed, then the result is a complete copy. +This is the anaphoric counterpart to `-remove-first'." + (declare (debug (form form))) + (let ((front (make-symbol "front")) + (tail (make-symbol "tail"))) + `(let ((,tail ,list) ,front) + (--each-while ,tail (not ,form) + (push (pop ,tail) ,front)) + (if ,tail + (nconc (nreverse ,front) (cdr ,tail)) + (nreverse ,front))))) + +(defun -remove-first (pred list) + "Remove the first item from LIST for which PRED returns non-nil. +This is a non-destructive operation, but only the front of LIST +leading up to the removed item is a copy; the rest is LIST's +original tail. If no item is removed, then the result is a +complete copy. + +Alias: `-reject-first'. + +This function's anaphoric counterpart is `--remove-first'. + +See also `-map-first', `-remove-item', and `-remove-last'." + (--remove-first (funcall pred it) list)) + +(defalias '-reject-first '-remove-first) +(defalias '--reject-first '--remove-first) + +(defmacro --remove-last (form list) + "Remove the last item from LIST for which FORM evals to non-nil. +Each element of LIST in turn is bound to `it' before evaluating +FORM. The result is a copy of LIST regardless of whether an +element is removed. +This is the anaphoric counterpart to `-remove-last'." + (declare (debug (form form))) + `(nreverse (--remove-first ,form (reverse ,list)))) + +(defun -remove-last (pred list) + "Remove the last item from LIST for which PRED returns non-nil. +The result is a copy of LIST regardless of whether an element is +removed. + +Alias: `-reject-last'. + +This function's anaphoric counterpart is `--remove-last'. + +See also `-map-last', `-remove-item', and `-remove-first'." + (--remove-last (funcall pred it) list)) + +(defalias '-reject-last '-remove-last) +(defalias '--reject-last '--remove-last) + +(defalias '-remove-item #'remove + "Return a copy of LIST with all occurrences of ITEM removed. +The comparison is done with `equal'. +\n(fn ITEM LIST)") + +(defmacro --keep (form list) + "Eval FORM for each item in LIST and return the non-nil results. +Like `--filter', but returns the non-nil results of FORM instead +of the corresponding elements of LIST. Each element of LIST in +turn is bound to `it' and its index within LIST to `it-index' +before evaluating FORM. +This is the anaphoric counterpart to `-keep'." + (declare (debug (form form))) + (let ((r (make-symbol "result")) + (m (make-symbol "mapped"))) + `(let (,r) + (--each ,list (let ((,m ,form)) (when ,m (push ,m ,r)))) + (nreverse ,r)))) + +(defun -keep (fn list) + "Return a new list of the non-nil results of applying FN to each item in LIST. +Like `-filter', but returns the non-nil results of FN instead of +the corresponding elements of LIST. + +Its anaphoric counterpart is `--keep'." + (--keep (funcall fn it) list)) + +(defun -non-nil (list) + "Return a copy of LIST with all nil items removed." + (declare (pure t) (side-effect-free t)) + (--filter it list)) + +(defmacro --map-indexed (form list) + "Eval FORM for each item in LIST and return the list of results. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. This is like +`--map', but additionally makes `it-index' available to FORM. + +This is the anaphoric counterpart to `-map-indexed'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each ,list + (push ,form ,r)) + (nreverse ,r)))) + +(defun -map-indexed (fn list) + "Apply FN to each index and item in LIST and return the list of results. +This is like `-map', but FN takes two arguments: the index of the +current element within LIST, and the element itself. + +This function's anaphoric counterpart is `--map-indexed'. + +For a side-effecting variant, see also `-each-indexed'." + (--map-indexed (funcall fn it-index it) list)) + +(defmacro --map-when (pred rep list) + "Anaphoric form of `-map-when'." + (declare (debug (form form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each ,list (!cons (if ,pred ,rep it) ,r)) + (nreverse ,r)))) + +(defun -map-when (pred rep list) + "Return a new list where the elements in LIST that do not match the PRED function +are unchanged, and where the elements in LIST that do match the PRED function are mapped +through the REP function. + +Alias: `-replace-where' + +See also: `-update-at'" + (--map-when (funcall pred it) (funcall rep it) list)) + +(defalias '-replace-where '-map-when) +(defalias '--replace-where '--map-when) + +(defun -map-first (pred rep list) + "Replace first item in LIST satisfying PRED with result of REP called on this item. + +See also: `-map-when', `-replace-first'" + (let (front) + (while (and list (not (funcall pred (car list)))) + (push (car list) front) + (!cdr list)) + (if list + (-concat (nreverse front) (cons (funcall rep (car list)) (cdr list))) + (nreverse front)))) + +(defmacro --map-first (pred rep list) + "Anaphoric form of `-map-first'." + (declare (debug (def-form def-form form))) + `(-map-first (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list)) + +(defun -map-last (pred rep list) + "Replace last item in LIST satisfying PRED with result of REP called on this item. + +See also: `-map-when', `-replace-last'" + (nreverse (-map-first pred rep (reverse list)))) + +(defmacro --map-last (pred rep list) + "Anaphoric form of `-map-last'." + (declare (debug (def-form def-form form))) + `(-map-last (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list)) + +(defun -replace (old new list) + "Replace all OLD items in LIST with NEW. + +Elements are compared using `equal'. + +See also: `-replace-at'" + (declare (pure t) (side-effect-free t)) + (--map-when (equal it old) new list)) + +(defun -replace-first (old new list) + "Replace the first occurrence of OLD with NEW in LIST. + +Elements are compared using `equal'. + +See also: `-map-first'" + (declare (pure t) (side-effect-free t)) + (--map-first (equal old it) new list)) + +(defun -replace-last (old new list) + "Replace the last occurrence of OLD with NEW in LIST. + +Elements are compared using `equal'. + +See also: `-map-last'" + (declare (pure t) (side-effect-free t)) + (--map-last (equal old it) new list)) + +(defmacro --mapcat (form list) + "Anaphoric form of `-mapcat'." + (declare (debug (form form))) + `(apply 'append (--map ,form ,list))) + +(defun -mapcat (fn list) + "Return the concatenation of the result of mapping FN over LIST. +Thus function FN should return a list." + (--mapcat (funcall fn it) list)) + +(defmacro --iterate (form init n) + "Anaphoric version of `-iterate'." + (declare (debug (form form form))) + (let ((res (make-symbol "result")) + (len (make-symbol "n"))) + `(let ((,len ,n)) + (when (> ,len 0) + (let* ((it ,init) + (,res (list it))) + (dotimes (_ (1- ,len)) + (push (setq it ,form) ,res)) + (nreverse ,res)))))) + +(defun -iterate (fun init n) + "Return a list of iterated applications of FUN to INIT. + +This means a list of the form: + + (INIT (FUN INIT) (FUN (FUN INIT)) ...) + +N is the length of the returned list." + (--iterate (funcall fun it) init n)) + +(defun -flatten (l) + "Take a nested list L and return its contents as a single, flat list. + +Note that because `nil' represents a list of zero elements (an +empty list), any mention of nil in L will disappear after +flattening. If you need to preserve nils, consider `-flatten-n' +or map them to some unique symbol and then map them back. + +Conses of two atoms are considered \"terminals\", that is, they +aren't flattened further. + +See also: `-flatten-n'" + (declare (pure t) (side-effect-free t)) + (if (and (listp l) (listp (cdr l))) + (-mapcat '-flatten l) + (list l))) + +(defun -flatten-n (num list) + "Flatten NUM levels of a nested LIST. + +See also: `-flatten'" + (declare (pure t) (side-effect-free t)) + (dotimes (_ num) + (setq list (apply #'append (mapcar #'-list list)))) + list) + +(defun -concat (&rest lists) + "Return a new list with the concatenation of the elements in the supplied LISTS." + (declare (pure t) (side-effect-free t)) + (apply 'append lists)) + +(defalias '-copy 'copy-sequence + "Create a shallow copy of LIST. + +\(fn LIST)") + +(defun -splice (pred fun list) + "Splice lists generated by FUN in place of elements matching PRED in LIST. + +FUN takes the element matching PRED as input. + +This function can be used as replacement for `,@' in case you +need to splice several lists at marked positions (for example +with keywords). + +See also: `-splice-list', `-insert-at'" + (let (r) + (--each list + (if (funcall pred it) + (let ((new (funcall fun it))) + (--each new (!cons it r))) + (!cons it r))) + (nreverse r))) + +(defmacro --splice (pred form list) + "Anaphoric form of `-splice'." + (declare (debug (def-form def-form form))) + `(-splice (lambda (it) ,pred) (lambda (it) ,form) ,list)) + +(defun -splice-list (pred new-list list) + "Splice NEW-LIST in place of elements matching PRED in LIST. + +See also: `-splice', `-insert-at'" + (-splice pred (lambda (_) new-list) list)) + +(defmacro --splice-list (pred new-list list) + "Anaphoric form of `-splice-list'." + (declare (debug (def-form form form))) + `(-splice-list (lambda (it) ,pred) ,new-list ,list)) + +(defun -cons* (&rest args) + "Make a new list from the elements of ARGS. +The last 2 elements of ARGS are used as the final cons of the +result, so if the final element of ARGS is not a list, the result +is a dotted list. With no ARGS, return nil." + (declare (pure t) (side-effect-free t)) + (let* ((len (length args)) + (tail (nthcdr (- len 2) args)) + (last (cdr tail))) + (if (null last) + (car args) + (setcdr tail (car last)) + args))) + +(defun -snoc (list elem &rest elements) + "Append ELEM to the end of the list. + +This is like `cons', but operates on the end of list. + +If ELEMENTS is non nil, append these to the list as well." + (-concat list (list elem) elements)) + +(defmacro --first (form list) + "Return the first item in LIST for which FORM evals to non-nil. +Return nil if no such element is found. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. +This is the anaphoric counterpart to `-first'." + (declare (debug (form form))) + (let ((n (make-symbol "needle"))) + `(let (,n) + (--each-while ,list (or (not ,form) + (ignore (setq ,n it)))) + ,n))) + +(defun -first (pred list) + "Return the first item in LIST for which PRED returns non-nil. +Return nil if no such element is found. +To get the first item in the list no questions asked, use `car'. + +Alias: `-find'. + +This function's anaphoric counterpart is `--first'." + (--first (funcall pred it) list)) + +(defalias '-find '-first) +(defalias '--find '--first) + +(defmacro --some (form list) + "Return non-nil if FORM evals to non-nil for at least one item in LIST. +If so, return the first such result of FORM. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. +This is the anaphoric counterpart to `-some'." + (declare (debug (form form))) + (let ((n (make-symbol "needle"))) + `(let (,n) + (--each-while ,list (not (setq ,n ,form))) + ,n))) + +(defun -some (pred list) + "Return (PRED x) for the first LIST item where (PRED x) is non-nil, else nil. + +Alias: `-any'. + +This function's anaphoric counterpart is `--some'." + (--some (funcall pred it) list)) + +(defalias '-any '-some) +(defalias '--any '--some) + +(defmacro --every (form list) + "Return non-nil if FORM evals to non-nil for all items in LIST. +If so, return the last such result of FORM. Otherwise, once an +item is reached for which FORM yields nil, return nil without +evaluating FORM for any further LIST elements. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. + +This macro is like `--every-p', but on success returns the last +non-nil result of FORM instead of just t. + +This is the anaphoric counterpart to `-every'." + (declare (debug (form form))) + (let ((a (make-symbol "all"))) + `(let ((,a t)) + (--each-while ,list (setq ,a ,form)) + ,a))) + +(defun -every (pred list) + "Return non-nil if PRED returns non-nil for all items in LIST. +If so, return the last such result of PRED. Otherwise, once an +item is reached for which PRED returns nil, return nil without +calling PRED on any further LIST elements. + +This function is like `-every-p', but on success returns the last +non-nil result of PRED instead of just t. + +This function's anaphoric counterpart is `--every'." + (--every (funcall pred it) list)) + +(defmacro --last (form list) + "Anaphoric form of `-last'." + (declare (debug (form form))) + (let ((n (make-symbol "needle"))) + `(let (,n) + (--each ,list + (when ,form (setq ,n it))) + ,n))) + +(defun -last (pred list) + "Return the last x in LIST where (PRED x) is non-nil, else nil." + (--last (funcall pred it) list)) + +(defalias '-first-item 'car + "Return the first item of LIST, or nil on an empty list. + +See also: `-second-item', `-last-item'. + +\(fn LIST)") + +;; Ensure that calls to `-first-item' are compiled to a single opcode, +;; just like `car'. +(put '-first-item 'byte-opcode 'byte-car) +(put '-first-item 'byte-compile 'byte-compile-one-arg) + +(defalias '-second-item 'cadr + "Return the second item of LIST, or nil if LIST is too short. + +See also: `-third-item'. + +\(fn LIST)") + +(defalias '-third-item + (if (fboundp 'caddr) + #'caddr + (lambda (list) (car (cddr list)))) + "Return the third item of LIST, or nil if LIST is too short. + +See also: `-fourth-item'. + +\(fn LIST)") + +(defun -fourth-item (list) + "Return the fourth item of LIST, or nil if LIST is too short. + +See also: `-fifth-item'." + (declare (pure t) (side-effect-free t)) + (car (cdr (cdr (cdr list))))) + +(defun -fifth-item (list) + "Return the fifth item of LIST, or nil if LIST is too short. + +See also: `-last-item'." + (declare (pure t) (side-effect-free t)) + (car (cdr (cdr (cdr (cdr list)))))) + +(defun -last-item (list) + "Return the last item of LIST, or nil on an empty list." + (declare (pure t) (side-effect-free t)) + (car (last list))) + +;; Use `with-no-warnings' to suppress unbound `-last-item' or +;; undefined `gv--defsetter' warnings arising from both +;; `gv-define-setter' and `defsetf' in certain Emacs versions. +(with-no-warnings + (if (fboundp 'gv-define-setter) + (gv-define-setter -last-item (val x) `(setcar (last ,x) ,val)) + (defsetf -last-item (x) (val) `(setcar (last ,x) ,val)))) + +(defun -butlast (list) + "Return a list of all items in list except for the last." + ;; no alias as we don't want magic optional argument + (declare (pure t) (side-effect-free t)) + (butlast list)) + +(defmacro --count (pred list) + "Anaphoric form of `-count'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let ((,r 0)) + (--each ,list (when ,pred (setq ,r (1+ ,r)))) + ,r))) + +(defun -count (pred list) + "Counts the number of items in LIST where (PRED item) is non-nil." + (--count (funcall pred it) list)) + +(defun ---truthy? (obj) + "Return OBJ as a boolean value (t or nil)." + (declare (pure t) (side-effect-free t)) + (and obj t)) + +(defmacro --any? (form list) + "Anaphoric form of `-any?'." + (declare (debug (form form))) + `(and (--some ,form ,list) t)) + +(defun -any? (pred list) + "Return t if (PRED x) is non-nil for any x in LIST, else nil. + +Alias: `-any-p', `-some?', `-some-p'" + (--any? (funcall pred it) list)) + +(defalias '-some? '-any?) +(defalias '--some? '--any?) +(defalias '-any-p '-any?) +(defalias '--any-p '--any?) +(defalias '-some-p '-any?) +(defalias '--some-p '--any?) + +(defmacro --all? (form list) + "Return t if FORM evals to non-nil for all items in LIST. +Otherwise, once an item is reached for which FORM yields nil, +return nil without evaluating FORM for any further LIST elements. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. + +The similar macro `--every' is more widely useful, since it +returns the last non-nil result of FORM instead of just t on +success. + +Alias: `--all-p', `--every-p', `--every?'. + +This is the anaphoric counterpart to `-all?'." + (declare (debug (form form))) + `(and (--every ,form ,list) t)) + +(defun -all? (pred list) + "Return t if (PRED X) is non-nil for all X in LIST, else nil. +In the latter case, stop after the first X for which (PRED X) is +nil, without calling PRED on any subsequent elements of LIST. + +The similar function `-every' is more widely useful, since it +returns the last non-nil result of PRED instead of just t on +success. + +Alias: `-all-p', `-every-p', `-every?'. + +This function's anaphoric counterpart is `--all?'." + (--all? (funcall pred it) list)) + +(defalias '-every? '-all?) +(defalias '--every? '--all?) +(defalias '-all-p '-all?) +(defalias '--all-p '--all?) +(defalias '-every-p '-all?) +(defalias '--every-p '--all?) + +(defmacro --none? (form list) + "Anaphoric form of `-none?'." + (declare (debug (form form))) + `(--all? (not ,form) ,list)) + +(defun -none? (pred list) + "Return t if (PRED x) is nil for all x in LIST, else nil. + +Alias: `-none-p'" + (--none? (funcall pred it) list)) + +(defalias '-none-p '-none?) +(defalias '--none-p '--none?) + +(defmacro --only-some? (form list) + "Anaphoric form of `-only-some?'." + (declare (debug (form form))) + (let ((y (make-symbol "yes")) + (n (make-symbol "no"))) + `(let (,y ,n) + (--each-while ,list (not (and ,y ,n)) + (if ,form (setq ,y t) (setq ,n t))) + (---truthy? (and ,y ,n))))) + +(defun -only-some? (pred list) + "Return `t` if at least one item of LIST matches PRED and at least one item of LIST does not match PRED. +Return `nil` both if all items match the predicate or if none of the items match the predicate. + +Alias: `-only-some-p'" + (--only-some? (funcall pred it) list)) + +(defalias '-only-some-p '-only-some?) +(defalias '--only-some-p '--only-some?) + +(defun -slice (list from &optional to step) + "Return copy of LIST, starting from index FROM to index TO. + +FROM or TO may be negative. These values are then interpreted +modulo the length of the list. + +If STEP is a number, only each STEPth item in the resulting +section is returned. Defaults to 1." + (declare (pure t) (side-effect-free t)) + (let ((length (length list)) + (new-list nil)) + ;; to defaults to the end of the list + (setq to (or to length)) + (setq step (or step 1)) + ;; handle negative indices + (when (< from 0) + (setq from (mod from length))) + (when (< to 0) + (setq to (mod to length))) + + ;; iterate through the list, keeping the elements we want + (--each-while list (< it-index to) + (when (and (>= it-index from) + (= (mod (- from it-index) step) 0)) + (push it new-list))) + (nreverse new-list))) + +(defmacro --take-while (form list) + "Take successive items from LIST for which FORM evals to non-nil. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. Return a new +list of the successive elements from the start of LIST for which +FORM evaluates to non-nil. +This is the anaphoric counterpart to `-take-while'." + (declare (debug (form form))) + (let ((r (make-symbol "result"))) + `(let (,r) + (--each-while ,list ,form (push it ,r)) + (nreverse ,r)))) + +(defun -take-while (pred list) + "Take successive items from LIST for which PRED returns non-nil. +PRED is a function of one argument. Return a new list of the +successive elements from the start of LIST for which PRED returns +non-nil. + +This function's anaphoric counterpart is `--take-while'. + +For another variant, see also `-drop-while'." + (--take-while (funcall pred it) list)) + +(defmacro --drop-while (form list) + "Drop successive items from LIST for which FORM evals to non-nil. +Each element of LIST in turn is bound to `it' and its index +within LIST to `it-index' before evaluating FORM. Return the +tail (not a copy) of LIST starting from its first element for +which FORM evaluates to nil. +This is the anaphoric counterpart to `-drop-while'." + (declare (debug (form form))) + (let ((l (make-symbol "list"))) + `(let ((,l ,list)) + (--each-while ,l ,form (pop ,l)) + ,l))) + +(defun -drop-while (pred list) + "Drop successive items from LIST for which PRED returns non-nil. +PRED is a function of one argument. Return the tail (not a copy) +of LIST starting from its first element for which PRED returns +nil. + +This function's anaphoric counterpart is `--drop-while'. + +For another variant, see also `-take-while'." + (--drop-while (funcall pred it) list)) + +(defun -take (n list) + "Return a copy of the first N items in LIST. +Return a copy of LIST if it contains N items or fewer. +Return nil if N is zero or less. + +See also: `-take-last'." + (declare (pure t) (side-effect-free t)) + (--take-while (< it-index n) list)) + +(defun -take-last (n list) + "Return a copy of the last N items of LIST in order. +Return a copy of LIST if it contains N items or fewer. +Return nil if N is zero or less. + +See also: `-take'." + (declare (pure t) (side-effect-free t)) + (copy-sequence (last list n))) + +(defalias '-drop #'nthcdr + "Return the tail (not a copy) of LIST without the first N items. +Return nil if LIST contains N items or fewer. +Return LIST if N is zero or less. + +For another variant, see also `-drop-last'. +\n(fn N LIST)") + +(defun -drop-last (n list) + "Return a copy of LIST without its last N items. +Return a copy of LIST if N is zero or less. +Return nil if LIST contains N items or fewer. + +See also: `-drop'." + (declare (pure t) (side-effect-free t)) + (nbutlast (copy-sequence list) n)) + +(defun -split-at (n list) + "Split LIST into two sublists after the Nth element. +The result is a list of two elements (TAKE DROP) where TAKE is a +new list of the first N elements of LIST, and DROP is the +remaining elements of LIST (not a copy). TAKE and DROP are like +the results of `-take' and `-drop', respectively, but the split +is done in a single list traversal." + (declare (pure t) (side-effect-free t)) + (let (result) + (--each-while list (< it-index n) + (push (pop list) result)) + (list (nreverse result) list))) + +(defun -rotate (n list) + "Rotate LIST N places to the right (left if N is negative). +The time complexity is O(n)." + (declare (pure t) (side-effect-free t)) + (cond ((null list) ()) + ((zerop n) (copy-sequence list)) + ((let* ((len (length list)) + (n-mod-len (mod n len)) + (new-tail-len (- len n-mod-len))) + (append (nthcdr new-tail-len list) (-take new-tail-len list)))))) + +(defun -insert-at (n x list) + "Return a list with X inserted into LIST at position N. + +See also: `-splice', `-splice-list'" + (declare (pure t) (side-effect-free t)) + (let ((split-list (-split-at n list))) + (nconc (car split-list) (cons x (cadr split-list))))) + +(defun -replace-at (n x list) + "Return a list with element at Nth position in LIST replaced with X. + +See also: `-replace'" + (declare (pure t) (side-effect-free t)) + (let ((split-list (-split-at n list))) + (nconc (car split-list) (cons x (cdr (cadr split-list)))))) + +(defun -update-at (n func list) + "Return a list with element at Nth position in LIST replaced with `(func (nth n list))`. + +See also: `-map-when'" + (let ((split-list (-split-at n list))) + (nconc (car split-list) (cons (funcall func (car (cadr split-list))) (cdr (cadr split-list)))))) + +(defmacro --update-at (n form list) + "Anaphoric version of `-update-at'." + (declare (debug (form def-form form))) + `(-update-at ,n (lambda (it) ,form) ,list)) + +(defun -remove-at (n list) + "Return a list with element at Nth position in LIST removed. + +See also: `-remove-at-indices', `-remove'" + (declare (pure t) (side-effect-free t)) + (-remove-at-indices (list n) list)) + +(defun -remove-at-indices (indices list) + "Return a list whose elements are elements from LIST without +elements selected as `(nth i list)` for all i +from INDICES. + +See also: `-remove-at', `-remove'" + (declare (pure t) (side-effect-free t)) + (let* ((indices (-sort '< indices)) + (diffs (cons (car indices) (-map '1- (-zip-with '- (cdr indices) indices)))) + r) + (--each diffs + (let ((split (-split-at it list))) + (!cons (car split) r) + (setq list (cdr (cadr split))))) + (!cons list r) + (apply '-concat (nreverse r)))) + +(defmacro --split-with (pred list) + "Anaphoric form of `-split-with'." + (declare (debug (form form))) + (let ((l (make-symbol "list")) + (r (make-symbol "result")) + (c (make-symbol "continue"))) + `(let ((,l ,list) + (,r nil) + (,c t)) + (while (and ,l ,c) + (let ((it (car ,l))) + (if (not ,pred) + (setq ,c nil) + (!cons it ,r) + (!cdr ,l)))) + (list (nreverse ,r) ,l)))) + +(defun -split-with (pred list) + "Return a list of ((-take-while PRED LIST) (-drop-while PRED LIST)), in no more than one pass through the list." + (--split-with (funcall pred it) list)) + +(defmacro -split-on (item list) + "Split the LIST each time ITEM is found. + +Unlike `-partition-by', the ITEM is discarded from the results. +Empty lists are also removed from the result. + +Comparison is done by `equal'. + +See also `-split-when'" + (declare (debug (def-form form))) + `(-split-when (lambda (it) (equal it ,item)) ,list)) + +(defmacro --split-when (form list) + "Anaphoric version of `-split-when'." + (declare (debug (def-form form))) + `(-split-when (lambda (it) ,form) ,list)) + +(defun -split-when (fn list) + "Split the LIST on each element where FN returns non-nil. + +Unlike `-partition-by', the \"matched\" element is discarded from +the results. Empty lists are also removed from the result. + +This function can be thought of as a generalization of +`split-string'." + (let (r s) + (while list + (if (not (funcall fn (car list))) + (push (car list) s) + (when s (push (nreverse s) r)) + (setq s nil)) + (!cdr list)) + (when s (push (nreverse s) r)) + (nreverse r))) + +(defmacro --separate (form list) + "Anaphoric form of `-separate'." + (declare (debug (form form))) + (let ((y (make-symbol "yes")) + (n (make-symbol "no"))) + `(let (,y ,n) + (--each ,list (if ,form (!cons it ,y) (!cons it ,n))) + (list (nreverse ,y) (nreverse ,n))))) + +(defun -separate (pred list) + "Return a list of ((-filter PRED LIST) (-remove PRED LIST)), in one pass through the list." + (--separate (funcall pred it) list)) + +(defun dash--partition-all-in-steps-reversed (n step list) + "Used by `-partition-all-in-steps' and `-partition-in-steps'." + (when (< step 1) + (signal 'wrong-type-argument + `("Step size < 1 results in juicy infinite loops" ,step))) + (let (result) + (while list + (push (-take n list) result) + (setq list (nthcdr step list))) + result)) + +(defun -partition-all-in-steps (n step list) + "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart. +The last groups may contain less than N items." + (declare (pure t) (side-effect-free t)) + (nreverse (dash--partition-all-in-steps-reversed n step list))) + +(defun -partition-in-steps (n step list) + "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart. +If there are not enough items to make the last group N-sized, +those items are discarded." + (declare (pure t) (side-effect-free t)) + (let ((result (dash--partition-all-in-steps-reversed n step list))) + (while (and result (< (length (car result)) n)) + (!cdr result)) + (nreverse result))) + +(defun -partition-all (n list) + "Return a new list with the items in LIST grouped into N-sized sublists. +The last group may contain less than N items." + (declare (pure t) (side-effect-free t)) + (-partition-all-in-steps n n list)) + +(defun -partition (n list) + "Return a new list with the items in LIST grouped into N-sized sublists. +If there are not enough items to make the last group N-sized, +those items are discarded." + (declare (pure t) (side-effect-free t)) + (-partition-in-steps n n list)) + +(defmacro --partition-by (form list) + "Anaphoric form of `-partition-by'." + (declare (debug (form form))) + (let ((r (make-symbol "result")) + (s (make-symbol "sublist")) + (v (make-symbol "value")) + (n (make-symbol "new-value")) + (l (make-symbol "list"))) + `(let ((,l ,list)) + (when ,l + (let* ((,r nil) + (it (car ,l)) + (,s (list it)) + (,v ,form) + (,l (cdr ,l))) + (while ,l + (let* ((it (car ,l)) + (,n ,form)) + (unless (equal ,v ,n) + (!cons (nreverse ,s) ,r) + (setq ,s nil) + (setq ,v ,n)) + (!cons it ,s) + (!cdr ,l))) + (!cons (nreverse ,s) ,r) + (nreverse ,r)))))) + +(defun -partition-by (fn list) + "Apply FN to each item in LIST, splitting it each time FN returns a new value." + (--partition-by (funcall fn it) list)) + +(defmacro --partition-by-header (form list) + "Anaphoric form of `-partition-by-header'." + (declare (debug (form form))) + (let ((r (make-symbol "result")) + (s (make-symbol "sublist")) + (h (make-symbol "header-value")) + (b (make-symbol "seen-body?")) + (n (make-symbol "new-value")) + (l (make-symbol "list"))) + `(let ((,l ,list)) + (when ,l + (let* ((,r nil) + (it (car ,l)) + (,s (list it)) + (,h ,form) + (,b nil) + (,l (cdr ,l))) + (while ,l + (let* ((it (car ,l)) + (,n ,form)) + (if (equal ,h ,n) + (when ,b + (!cons (nreverse ,s) ,r) + (setq ,s nil) + (setq ,b nil)) + (setq ,b t)) + (!cons it ,s) + (!cdr ,l))) + (!cons (nreverse ,s) ,r) + (nreverse ,r)))))) + +(defun -partition-by-header (fn list) + "Apply FN to the first item in LIST. That is the header +value. Apply FN to each item in LIST, splitting it each time FN +returns the header value, but only after seeing at least one +other value (the body)." + (--partition-by-header (funcall fn it) list)) + +(defmacro --partition-after-pred (form list) + "Partition LIST after each element for which FORM evaluates to non-nil. +Each element of LIST in turn is bound to `it' before evaluating +FORM. + +This is the anaphoric counterpart to `-partition-after-pred'." + (let ((l (make-symbol "list")) + (r (make-symbol "result")) + (s (make-symbol "sublist"))) + `(let ((,l ,list) ,r ,s) + (when ,l + (--each ,l + (push it ,s) + (when ,form + (push (nreverse ,s) ,r) + (setq ,s ()))) + (when ,s + (push (nreverse ,s) ,r)) + (nreverse ,r))))) + +(defun -partition-after-pred (pred list) + "Partition LIST after each element for which PRED returns non-nil. + +This function's anaphoric counterpart is `--partition-after-pred'." + (--partition-after-pred (funcall pred it) list)) + +(defun -partition-before-pred (pred list) + "Partition directly before each time PRED is true on an element of LIST." + (nreverse (-map #'reverse + (-partition-after-pred pred (reverse list))))) + +(defun -partition-after-item (item list) + "Partition directly after each time ITEM appears in LIST." + (-partition-after-pred (lambda (ele) (equal ele item)) + list)) + +(defun -partition-before-item (item list) + "Partition directly before each time ITEM appears in LIST." + (-partition-before-pred (lambda (ele) (equal ele item)) + list)) + +(defmacro --group-by (form list) + "Anaphoric form of `-group-by'." + (declare (debug t)) + (let ((n (make-symbol "n")) + (k (make-symbol "k")) + (grp (make-symbol "grp"))) + `(nreverse + (-map + (lambda (,n) + (cons (car ,n) + (nreverse (cdr ,n)))) + (--reduce-from + (let* ((,k (,@form)) + (,grp (assoc ,k acc))) + (if ,grp + (setcdr ,grp (cons it (cdr ,grp))) + (push + (list ,k it) + acc)) + acc) + nil ,list))))) + +(defun -group-by (fn list) + "Separate LIST into an alist whose keys are FN applied to the +elements of LIST. Keys are compared by `equal'." + (--group-by (funcall fn it) list)) + +(defun -interpose (sep list) + "Return a new list of all elements in LIST separated by SEP." + (declare (pure t) (side-effect-free t)) + (let (result) + (when list + (!cons (car list) result) + (!cdr list)) + (while list + (setq result (cons (car list) (cons sep result))) + (!cdr list)) + (nreverse result))) + +(defun -interleave (&rest lists) + "Return a new list of the first item in each list, then the second etc." + (declare (pure t) (side-effect-free t)) + (when lists + (let (result) + (while (-none? 'null lists) + (--each lists (!cons (car it) result)) + (setq lists (-map 'cdr lists))) + (nreverse result)))) + +(defmacro --zip-with (form list1 list2) + "Anaphoric form of `-zip-with'. + +The elements in list1 are bound as symbol `it', the elements in list2 as symbol `other'." + (declare (debug (form form form))) + (let ((r (make-symbol "result")) + (l1 (make-symbol "list1")) + (l2 (make-symbol "list2"))) + `(let ((,r nil) + (,l1 ,list1) + (,l2 ,list2)) + (while (and ,l1 ,l2) + (let ((it (car ,l1)) + (other (car ,l2))) + (!cons ,form ,r) + (!cdr ,l1) + (!cdr ,l2))) + (nreverse ,r)))) + +(defun -zip-with (fn list1 list2) + "Zip the two lists LIST1 and LIST2 using a function FN. This +function is applied pairwise taking as first argument element of +LIST1 and as second argument element of LIST2 at corresponding +position. + +The anaphoric form `--zip-with' binds the elements from LIST1 as symbol `it', +and the elements from LIST2 as symbol `other'." + (--zip-with (funcall fn it other) list1 list2)) + +(defun -zip-lists (&rest lists) + "Zip LISTS together. Group the head of each list, followed by the +second elements of each list, and so on. The lengths of the returned +groupings are equal to the length of the shortest input list. + +The return value is always list of lists, which is a difference +from `-zip-pair' which returns a cons-cell in case two input +lists are provided. + +See also: `-zip'" + (declare (pure t) (side-effect-free t)) + (when lists + (let (results) + (while (-none? 'null lists) + (setq results (cons (mapcar 'car lists) results)) + (setq lists (mapcar 'cdr lists))) + (nreverse results)))) + +(defun -zip (&rest lists) + "Zip LISTS together. Group the head of each list, followed by the +second elements of each list, and so on. The lengths of the returned +groupings are equal to the length of the shortest input list. + +If two lists are provided as arguments, return the groupings as a list +of cons cells. Otherwise, return the groupings as a list of lists. + +Use `-zip-lists' if you need the return value to always be a list +of lists. + +Alias: `-zip-pair' + +See also: `-zip-lists'" + (declare (pure t) (side-effect-free t)) + (when lists + (let (results) + (while (-none? 'null lists) + (setq results (cons (mapcar 'car lists) results)) + (setq lists (mapcar 'cdr lists))) + (setq results (nreverse results)) + (if (= (length lists) 2) + ;; to support backward compatibility, return + ;; a cons cell if two lists were provided + (--map (cons (car it) (cadr it)) results) + results)))) + +(defalias '-zip-pair '-zip) + +(defun -zip-fill (fill-value &rest lists) + "Zip LISTS, with FILL-VALUE padded onto the shorter lists. The +lengths of the returned groupings are equal to the length of the +longest input list." + (declare (pure t) (side-effect-free t)) + (apply '-zip (apply '-pad (cons fill-value lists)))) + +(defun -unzip (lists) + "Unzip LISTS. + +This works just like `-zip' but takes a list of lists instead of +a variable number of arguments, such that + + (-unzip (-zip L1 L2 L3 ...)) + +is identity (given that the lists are the same length). + +Note in particular that calling this on a list of two lists will +return a list of cons-cells such that the above identity works. + +See also: `-zip'" + (apply '-zip lists)) + +(defun -cycle (list) + "Return an infinite circular copy of LIST. +The returned list cycles through the elements of LIST and repeats +from the beginning." + (declare (pure t) (side-effect-free t)) + ;; Also works with sequences that aren't lists. + (let ((newlist (append list ()))) + (nconc newlist newlist))) + +(defun -pad (fill-value &rest lists) + "Appends FILL-VALUE to the end of each list in LISTS such that they +will all have the same length." + (let* ((annotations (-annotate 'length lists)) + (n (-max (-map 'car annotations)))) + (--map (append (cdr it) (-repeat (- n (car it)) fill-value)) annotations))) + +(defun -annotate (fn list) + "Return a list of cons cells where each cell is FN applied to each +element of LIST paired with the unmodified element of LIST." + (-zip (-map fn list) list)) + +(defmacro --annotate (form list) + "Anaphoric version of `-annotate'." + (declare (debug (def-form form))) + `(-annotate (lambda (it) ,form) ,list)) + +(defun dash--table-carry (lists restore-lists &optional re) + "Helper for `-table' and `-table-flat'. + +If a list overflows, carry to the right and reset the list." + (while (not (or (car lists) + (equal lists '(nil)))) + (setcar lists (car restore-lists)) + (pop (cadr lists)) + (!cdr lists) + (!cdr restore-lists) + (when re + (push (nreverse (car re)) (cadr re)) + (setcar re nil) + (!cdr re)))) + +(defun -table (fn &rest lists) + "Compute outer product of LISTS using function FN. + +The function FN should have the same arity as the number of +supplied lists. + +The outer product is computed by applying fn to all possible +combinations created by taking one element from each list in +order. The dimension of the result is (length lists). + +See also: `-table-flat'" + (let ((restore-lists (copy-sequence lists)) + (last-list (last lists)) + (re (make-list (length lists) nil))) + (while (car last-list) + (let ((item (apply fn (-map 'car lists)))) + (push item (car re)) + (setcar lists (cdar lists)) ;; silence byte compiler + (dash--table-carry lists restore-lists re))) + (nreverse (car (last re))))) + +(defun -table-flat (fn &rest lists) + "Compute flat outer product of LISTS using function FN. + +The function FN should have the same arity as the number of +supplied lists. + +The outer product is computed by applying fn to all possible +combinations created by taking one element from each list in +order. The results are flattened, ignoring the tensor structure +of the result. This is equivalent to calling: + + (-flatten-n (1- (length lists)) (apply \\='-table fn lists)) + +but the implementation here is much more efficient. + +See also: `-flatten-n', `-table'" + (let ((restore-lists (copy-sequence lists)) + (last-list (last lists)) + re) + (while (car last-list) + (let ((item (apply fn (-map 'car lists)))) + (push item re) + (setcar lists (cdar lists)) ;; silence byte compiler + (dash--table-carry lists restore-lists))) + (nreverse re))) + +(defun -elem-index (elem list) + "Return the index of the first element in the given LIST which +is equal to the query element ELEM, or nil if there is no +such element." + (declare (pure t) (side-effect-free t)) + (car (-elem-indices elem list))) + +(defun -elem-indices (elem list) + "Return the indices of all elements in LIST equal to the query +element ELEM, in ascending order." + (declare (pure t) (side-effect-free t)) + (-find-indices (-partial 'equal elem) list)) + +(defun -find-indices (pred list) + "Return the indices of all elements in LIST satisfying the +predicate PRED, in ascending order." + (apply 'append (--map-indexed (when (funcall pred it) (list it-index)) list))) + +(defmacro --find-indices (form list) + "Anaphoric version of `-find-indices'." + (declare (debug (def-form form))) + `(-find-indices (lambda (it) ,form) ,list)) + +(defun -find-index (pred list) + "Take a predicate PRED and a LIST and return the index of the +first element in the list satisfying the predicate, or nil if +there is no such element. + +See also `-first'." + (car (-find-indices pred list))) + +(defmacro --find-index (form list) + "Anaphoric version of `-find-index'." + (declare (debug (def-form form))) + `(-find-index (lambda (it) ,form) ,list)) + +(defun -find-last-index (pred list) + "Take a predicate PRED and a LIST and return the index of the +last element in the list satisfying the predicate, or nil if +there is no such element. + +See also `-last'." + (-last-item (-find-indices pred list))) + +(defmacro --find-last-index (form list) + "Anaphoric version of `-find-last-index'." + (declare (debug (def-form form))) + `(-find-last-index (lambda (it) ,form) ,list)) + +(defun -select-by-indices (indices list) + "Return a list whose elements are elements from LIST selected +as `(nth i list)` for all i from INDICES." + (declare (pure t) (side-effect-free t)) + (let (r) + (--each indices + (!cons (nth it list) r)) + (nreverse r))) + +(defun -select-columns (columns table) + "Select COLUMNS from TABLE. + +TABLE is a list of lists where each element represents one row. +It is assumed each row has the same length. + +Each row is transformed such that only the specified COLUMNS are +selected. + +See also: `-select-column', `-select-by-indices'" + (declare (pure t) (side-effect-free t)) + (--map (-select-by-indices columns it) table)) + +(defun -select-column (column table) + "Select COLUMN from TABLE. + +TABLE is a list of lists where each element represents one row. +It is assumed each row has the same length. + +The single selected column is returned as a list. + +See also: `-select-columns', `-select-by-indices'" + (declare (pure t) (side-effect-free t)) + (--mapcat (-select-by-indices (list column) it) table)) + +(defmacro -> (x &optional form &rest more) + "Thread the expr through the forms. Insert X as the second item +in the first form, making a list of it if it is not a list +already. If there are more forms, insert the first form as the +second item in second form, etc." + (declare (debug (form &rest [&or symbolp (sexp &rest form)]))) + (cond + ((null form) x) + ((null more) (if (listp form) + `(,(car form) ,x ,@(cdr form)) + (list form x))) + (:else `(-> (-> ,x ,form) ,@more)))) + +(defmacro ->> (x &optional form &rest more) + "Thread the expr through the forms. Insert X as the last item +in the first form, making a list of it if it is not a list +already. If there are more forms, insert the first form as the +last item in second form, etc." + (declare (debug ->)) + (cond + ((null form) x) + ((null more) (if (listp form) + `(,@form ,x) + (list form x))) + (:else `(->> (->> ,x ,form) ,@more)))) + +(defmacro --> (x &rest forms) + "Starting with the value of X, thread each expression through FORMS. + +Insert X at the position signified by the symbol `it' in the first +form. If there are more forms, insert the first form at the position +signified by `it' in in second form, etc." + (declare (debug (form body))) + `(-as-> ,x it ,@forms)) + +(defmacro -as-> (value variable &rest forms) + "Starting with VALUE, thread VARIABLE through FORMS. + +In the first form, bind VARIABLE to VALUE. In the second form, bind +VARIABLE to the result of the first form, and so forth." + (declare (debug (form symbolp body))) + (if (null forms) + `,value + `(let ((,variable ,value)) + (-as-> ,(if (symbolp (car forms)) + (list (car forms) variable) + (car forms)) + ,variable + ,@(cdr forms))))) + +(defmacro -some-> (x &optional form &rest more) + "When expr is non-nil, thread it through the first form (via `->'), +and when that result is non-nil, through the next form, etc." + (declare (debug ->) + (indent 1)) + (if (null form) x + (let ((result (make-symbol "result"))) + `(-some-> (-when-let (,result ,x) + (-> ,result ,form)) + ,@more)))) + +(defmacro -some->> (x &optional form &rest more) + "When expr is non-nil, thread it through the first form (via `->>'), +and when that result is non-nil, through the next form, etc." + (declare (debug ->) + (indent 1)) + (if (null form) x + (let ((result (make-symbol "result"))) + `(-some->> (-when-let (,result ,x) + (->> ,result ,form)) + ,@more)))) + +(defmacro -some--> (expr &rest forms) + "Thread EXPR through FORMS via `-->', while the result is non-nil. +When EXPR evaluates to non-nil, thread the result through the +first of FORMS, and when that result is non-nil, thread it +through the next form, etc." + (declare (debug (form &rest &or symbolp consp)) (indent 1)) + (if (null forms) expr + (let ((result (make-symbol "result"))) + `(-some--> (-when-let (,result ,expr) + (--> ,result ,(car forms))) + ,@(cdr forms))))) + +(defmacro -doto (init &rest forms) + "Evaluate INIT and pass it as argument to FORMS with `->'. +The RESULT of evaluating INIT is threaded through each of FORMS +individually using `->', which see. The return value is RESULT, +which FORMS may have modified by side effect." + (declare (debug (form &rest &or symbolp consp)) (indent 1)) + (let ((retval (make-symbol "result"))) + `(let ((,retval ,init)) + ,@(mapcar (lambda (form) `(-> ,retval ,form)) forms) + ,retval))) + +(defmacro --doto (init &rest forms) + "Anaphoric form of `-doto'. +This just evaluates INIT, binds the result to `it', evaluates +FORMS, and returns the final value of `it'. +Note: `it' need not be used in each form." + (declare (debug (form body)) (indent 1)) + `(let ((it ,init)) + ,@forms + it)) + +(defun -grade-up (comparator list) + "Grade elements of LIST using COMPARATOR relation. +This yields a permutation vector such that applying this +permutation to LIST sorts it in ascending order." + (->> (--map-indexed (cons it it-index) list) + (-sort (lambda (it other) (funcall comparator (car it) (car other)))) + (mapcar #'cdr))) + +(defun -grade-down (comparator list) + "Grade elements of LIST using COMPARATOR relation. +This yields a permutation vector such that applying this +permutation to LIST sorts it in descending order." + (->> (--map-indexed (cons it it-index) list) + (-sort (lambda (it other) (funcall comparator (car other) (car it)))) + (mapcar #'cdr))) + +(defvar dash--source-counter 0 + "Monotonic counter for generated symbols.") + +(defun dash--match-make-source-symbol () + "Generate a new dash-source symbol. + +All returned symbols are guaranteed to be unique." + (prog1 (make-symbol (format "--dash-source-%d--" dash--source-counter)) + (setq dash--source-counter (1+ dash--source-counter)))) + +(defun dash--match-ignore-place-p (symbol) + "Return non-nil if SYMBOL is a symbol and starts with _." + (and (symbolp symbol) + (eq (aref (symbol-name symbol) 0) ?_))) + +(defun dash--match-cons-skip-cdr (skip-cdr source) + "Helper function generating idiomatic shifting code." + (cond + ((= skip-cdr 0) + `(pop ,source)) + (t + `(prog1 ,(dash--match-cons-get-car skip-cdr source) + (setq ,source ,(dash--match-cons-get-cdr (1+ skip-cdr) source)))))) + +(defun dash--match-cons-get-car (skip-cdr source) + "Helper function generating idiomatic code to get nth car." + (cond + ((= skip-cdr 0) + `(car ,source)) + ((= skip-cdr 1) + `(cadr ,source)) + (t + `(nth ,skip-cdr ,source)))) + +(defun dash--match-cons-get-cdr (skip-cdr source) + "Helper function generating idiomatic code to get nth cdr." + (cond + ((= skip-cdr 0) + source) + ((= skip-cdr 1) + `(cdr ,source)) + (t + `(nthcdr ,skip-cdr ,source)))) + +(defun dash--match-cons (match-form source) + "Setup a cons matching environment and call the real matcher." + (let ((s (dash--match-make-source-symbol)) + (n 0) + (m match-form)) + (while (and (consp m) + (dash--match-ignore-place-p (car m))) + (setq n (1+ n)) (!cdr m)) + (cond + ;; when we only have one pattern in the list, we don't have to + ;; create a temporary binding (--dash-source--) for the source + ;; and just use the input directly + ((and (consp m) + (not (cdr m))) + (dash--match (car m) (dash--match-cons-get-car n source))) + ;; handle other special types + ((> n 0) + (dash--match m (dash--match-cons-get-cdr n source))) + ;; this is the only entry-point for dash--match-cons-1, that's + ;; why we can't simply use the above branch, it would produce + ;; infinite recursion + (t + (cons (list s source) (dash--match-cons-1 match-form s)))))) + +(defun dash--get-expand-function (type) + "Get expand function name for TYPE." + (intern-soft (format "dash-expand:%s" type))) + +(defun dash--match-cons-1 (match-form source &optional props) + "Match MATCH-FORM against SOURCE. + +MATCH-FORM is a proper or improper list. Each element of +MATCH-FORM is either a symbol, which gets bound to the respective +value in source or another match form which gets destructured +recursively. + +If the cdr of last cons cell in the list is `nil', matching stops +there. + +SOURCE is a proper or improper list." + (let ((skip-cdr (or (plist-get props :skip-cdr) 0))) + (cond + ((consp match-form) + (cond + ((cdr match-form) + (cond + ((and (symbolp (car match-form)) + (functionp (dash--get-expand-function (car match-form)))) + (dash--match-kv (dash--match-kv-normalize-match-form match-form) (dash--match-cons-get-cdr skip-cdr source))) + ((dash--match-ignore-place-p (car match-form)) + (dash--match-cons-1 (cdr match-form) source + (plist-put props :skip-cdr (1+ skip-cdr)))) + (t + (-concat (dash--match (car match-form) (dash--match-cons-skip-cdr skip-cdr source)) + (dash--match-cons-1 (cdr match-form) source))))) + (t ;; Last matching place, no need for shift + (dash--match (car match-form) (dash--match-cons-get-car skip-cdr source))))) + ((eq match-form nil) + nil) + (t ;; Handle improper lists. Last matching place, no need for shift + (dash--match match-form (dash--match-cons-get-cdr skip-cdr source)))))) + +(defun dash--match-vector (match-form source) + "Setup a vector matching environment and call the real matcher." + (let ((s (dash--match-make-source-symbol))) + (cond + ;; don't bind `s' if we only have one sub-pattern + ((= (length match-form) 1) + (dash--match (aref match-form 0) `(aref ,source 0))) + ;; if the source is a symbol, we don't need to re-bind it + ((symbolp source) + (dash--match-vector-1 match-form source)) + ;; don't bind `s' if we only have one sub-pattern which is not ignored + ((let* ((ignored-places (mapcar 'dash--match-ignore-place-p match-form)) + (ignored-places-n (length (-remove 'null ignored-places)))) + (when (= ignored-places-n (1- (length match-form))) + (let ((n (-find-index 'null ignored-places))) + (dash--match (aref match-form n) `(aref ,source ,n)))))) + (t + (cons (list s source) (dash--match-vector-1 match-form s)))))) + +(defun dash--match-vector-1 (match-form source) + "Match MATCH-FORM against SOURCE. + +MATCH-FORM is a vector. Each element of MATCH-FORM is either a +symbol, which gets bound to the respective value in source or +another match form which gets destructured recursively. + +If second-from-last place in MATCH-FORM is the symbol &rest, the +next element of the MATCH-FORM is matched against the tail of +SOURCE, starting at index of the &rest symbol. This is +conceptually the same as the (head . tail) match for improper +lists, where dot plays the role of &rest. + +SOURCE is a vector. + +If the MATCH-FORM vector is shorter than SOURCE vector, only +the (length MATCH-FORM) places are bound, the rest of the SOURCE +is discarded." + (let ((i 0) + (l (length match-form)) + (re)) + (while (< i l) + (let ((m (aref match-form i))) + (push (cond + ((and (symbolp m) + (eq m '&rest)) + (prog1 (dash--match + (aref match-form (1+ i)) + `(substring ,source ,i)) + (setq i l))) + ((and (symbolp m) + ;; do not match symbols starting with _ + (not (eq (aref (symbol-name m) 0) ?_))) + (list (list m `(aref ,source ,i)))) + ((not (symbolp m)) + (dash--match m `(aref ,source ,i)))) + re) + (setq i (1+ i)))) + (-flatten-n 1 (nreverse re)))) + +(defun dash--match-kv-normalize-match-form (pattern) + "Normalize kv PATTERN. + +This method normalizes PATTERN to the format expected by +`dash--match-kv'. See `-let' for the specification." + (let ((normalized (list (car pattern))) + (skip nil) + (fill-placeholder (make-symbol "--dash-fill-placeholder--"))) + (-each (apply '-zip (-pad fill-placeholder (cdr pattern) (cddr pattern))) + (lambda (pair) + (let ((current (car pair)) + (next (cdr pair))) + (if skip + (setq skip nil) + (if (or (eq fill-placeholder next) + (not (or (and (symbolp next) + (not (keywordp next)) + (not (eq next t)) + (not (eq next nil))) + (and (consp next) + (not (eq (car next) 'quote))) + (vectorp next)))) + (progn + (cond + ((keywordp current) + (push current normalized) + (push (intern (substring (symbol-name current) 1)) normalized)) + ((stringp current) + (push current normalized) + (push (intern current) normalized)) + ((and (consp current) + (eq (car current) 'quote)) + (push current normalized) + (push (cadr current) normalized)) + (t (error "-let: found key `%s' in kv destructuring but its pattern `%s' is invalid and can not be derived from the key" current next))) + (setq skip nil)) + (push current normalized) + (push next normalized) + (setq skip t)))))) + (nreverse normalized))) + +(defun dash--match-kv (match-form source) + "Setup a kv matching environment and call the real matcher. + +kv can be any key-value store, such as plist, alist or hash-table." + (let ((s (dash--match-make-source-symbol))) + (cond + ;; don't bind `s' if we only have one sub-pattern (&type key val) + ((= (length match-form) 3) + (dash--match-kv-1 (cdr match-form) source (car match-form))) + ;; if the source is a symbol, we don't need to re-bind it + ((symbolp source) + (dash--match-kv-1 (cdr match-form) source (car match-form))) + (t + (cons (list s source) (dash--match-kv-1 (cdr match-form) s (car match-form))))))) + +(defun dash-expand:&hash (key source) + "Generate extracting KEY from SOURCE for &hash destructuring." + `(gethash ,key ,source)) + +(defun dash-expand:&plist (key source) + "Generate extracting KEY from SOURCE for &plist destructuring." + `(plist-get ,source ,key)) + +(defun dash-expand:&alist (key source) + "Generate extracting KEY from SOURCE for &alist destructuring." + `(cdr (assoc ,key ,source))) + +(defun dash-expand:&hash? (key source) + "Generate extracting KEY from SOURCE for &hash? destructuring. +Similar to &hash but check whether the map is not nil." + (let ((src (make-symbol "src"))) + `(let ((,src ,source)) + (when ,src (gethash ,key ,src))))) + +(defalias 'dash-expand:&keys 'dash-expand:&plist) + +(defun dash--match-kv-1 (match-form source type) + "Match MATCH-FORM against SOURCE of type TYPE. + +MATCH-FORM is a proper list of the form (key1 place1 ... keyN +placeN). Each placeK is either a symbol, which gets bound to the +value of keyK retrieved from the key-value store, or another +match form which gets destructured recursively. + +SOURCE is a key-value store of type TYPE, which can be a plist, +an alist or a hash table. + +TYPE is a token specifying the type of the key-value store. +Valid values are &plist, &alist and &hash." + (-flatten-n 1 (-map + (lambda (kv) + (let* ((k (car kv)) + (v (cadr kv)) + (getter + (funcall (dash--get-expand-function type) k source))) + (cond + ((symbolp v) + (list (list v getter))) + (t (dash--match v getter))))) + (-partition 2 match-form)))) + +(defun dash--match-symbol (match-form source) + "Bind a symbol. + +This works just like `let', there is no destructuring." + (list (list match-form source))) + +(defun dash--match (match-form source) + "Match MATCH-FORM against SOURCE. + +This function tests the MATCH-FORM and dispatches to specific +matchers based on the type of the expression. + +Key-value stores are disambiguated by placing a token &plist, +&alist or &hash as a first item in the MATCH-FORM." + (cond + ((symbolp match-form) + (dash--match-symbol match-form source)) + ((consp match-form) + (cond + ;; Handle the "x &as" bindings first. + ((and (consp (cdr match-form)) + (symbolp (car match-form)) + (eq '&as (cadr match-form))) + (let ((s (car match-form))) + (cons (list s source) + (dash--match (cddr match-form) s)))) + ((functionp (dash--get-expand-function (car match-form))) + (dash--match-kv (dash--match-kv-normalize-match-form match-form) source)) + (t (dash--match-cons match-form source)))) + ((vectorp match-form) + ;; We support the &as binding in vectors too + (cond + ((and (> (length match-form) 2) + (symbolp (aref match-form 0)) + (eq '&as (aref match-form 1))) + (let ((s (aref match-form 0))) + (cons (list s source) + (dash--match (substring match-form 2) s)))) + (t (dash--match-vector match-form source)))))) + +(defun dash--normalize-let-varlist (varlist) + "Normalize VARLIST so that every binding is a list. + +`let' allows specifying a binding which is not a list but simply +the place which is then automatically bound to nil, such that all +three of the following are identical and evaluate to nil. + + (let (a) a) + (let ((a)) a) + (let ((a nil)) a) + +This function normalizes all of these to the last form." + (--map (if (consp it) it (list it nil)) varlist)) + +(defmacro -let* (varlist &rest body) + "Bind variables according to VARLIST then eval BODY. + +VARLIST is a list of lists of the form (PATTERN SOURCE). Each +PATTERN is matched against the SOURCE structurally. SOURCE is +only evaluated once for each PATTERN. + +Each SOURCE can refer to the symbols already bound by this +VARLIST. This is useful if you want to destructure SOURCE +recursively but also want to name the intermediate structures. + +See `-let' for the list of all possible patterns." + (declare (debug ((&rest [&or (sexp form) sexp]) body)) + (indent 1)) + (let* ((varlist (dash--normalize-let-varlist varlist)) + (bindings (--mapcat (dash--match (car it) (cadr it)) varlist))) + `(let* ,bindings + ,@body))) + +(defmacro -let (varlist &rest body) + "Bind variables according to VARLIST then eval BODY. + +VARLIST is a list of lists of the form (PATTERN SOURCE). Each +PATTERN is matched against the SOURCE \"structurally\". SOURCE +is only evaluated once for each PATTERN. Each PATTERN is matched +recursively, and can therefore contain sub-patterns which are +matched against corresponding sub-expressions of SOURCE. + +All the SOURCEs are evalled before any symbols are +bound (i.e. \"in parallel\"). + +If VARLIST only contains one (PATTERN SOURCE) element, you can +optionally specify it using a vector and discarding the +outer-most parens. Thus + + (-let ((PATTERN SOURCE)) ...) + +becomes + + (-let [PATTERN SOURCE] ...). + +`-let' uses a convention of not binding places (symbols) starting +with _ whenever it's possible. You can use this to skip over +entries you don't care about. However, this is not *always* +possible (as a result of implementation) and these symbols might +get bound to undefined values. + +Following is the overview of supported patterns. Remember that +patterns can be matched recursively, so every a, b, aK in the +following can be a matching construct and not necessarily a +symbol/variable. + +Symbol: + + a - bind the SOURCE to A. This is just like regular `let'. + +Conses and lists: + + (a) - bind `car' of cons/list to A + + (a . b) - bind car of cons to A and `cdr' to B + + (a b) - bind car of list to A and `cadr' to B + + (a1 a2 a3 ...) - bind 0th car of list to A1, 1st to A2, 2nd to A3... + + (a1 a2 a3 ... aN . rest) - as above, but bind the Nth cdr to REST. + +Vectors: + + [a] - bind 0th element of a non-list sequence to A (works with + vectors, strings, bit arrays...) + + [a1 a2 a3 ...] - bind 0th element of non-list sequence to A0, 1st to + A1, 2nd to A2, ... + If the PATTERN is shorter than SOURCE, the values at + places not in PATTERN are ignored. + If the PATTERN is longer than SOURCE, an `error' is + thrown. + + [a1 a2 a3 ... &rest rest] - as above, but bind the rest of + the sequence to REST. This is + conceptually the same as improper list + matching (a1 a2 ... aN . rest) + +Key/value stores: + + (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE plist to aK. If the + value is not found, aK is nil. + Uses `plist-get' to fetch values. + + (&alist key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE alist to aK. If the + value is not found, aK is nil. + Uses `assoc' to fetch values. + + (&hash key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE hash table to aK. If the + value is not found, aK is nil. + Uses `gethash' to fetch values. + +Further, special keyword &keys supports \"inline\" matching of +plist-like key-value pairs, similarly to &keys keyword of +`cl-defun'. + + (a1 a2 ... aN &keys key1 b1 ... keyN bK) + +This binds N values from the list to a1 ... aN, then interprets +the cdr as a plist (see key/value matching above). + +A shorthand notation for kv-destructuring exists which allows the +patterns be optionally left out and derived from the key name in +the following fashion: + +- a key :foo is converted into `foo' pattern, +- a key 'bar is converted into `bar' pattern, +- a key \"baz\" is converted into `baz' pattern. + +That is, the entire value under the key is bound to the derived +variable without any further destructuring. + +This is possible only when the form following the key is not a +valid pattern (i.e. not a symbol, a cons cell or a vector). +Otherwise the matching proceeds as usual and in case of an +invalid spec fails with an error. + +Thus the patterns are normalized as follows: + + ;; derive all the missing patterns + (&plist :foo 'bar \"baz\") => (&plist :foo foo 'bar bar \"baz\" baz) + + ;; we can specify some but not others + (&plist :foo 'bar explicit-bar) => (&plist :foo foo 'bar explicit-bar) + + ;; nothing happens, we store :foo in x + (&plist :foo x) => (&plist :foo x) + + ;; nothing happens, we match recursively + (&plist :foo (a b c)) => (&plist :foo (a b c)) + +You can name the source using the syntax SYMBOL &as PATTERN. +This syntax works with lists (proper or improper), vectors and +all types of maps. + + (list &as a b c) (list 1 2 3) + +binds A to 1, B to 2, C to 3 and LIST to (1 2 3). + +Similarly: + + (bounds &as beg . end) (cons 1 2) + +binds BEG to 1, END to 2 and BOUNDS to (1 . 2). + + (items &as first . rest) (list 1 2 3) + +binds FIRST to 1, REST to (2 3) and ITEMS to (1 2 3) + + [vect &as _ b c] [1 2 3] + +binds B to 2, C to 3 and VECT to [1 2 3] (_ avoids binding as usual). + + (plist &as &plist :b b) (list :a 1 :b 2 :c 3) + +binds B to 2 and PLIST to (:a 1 :b 2 :c 3). Same for &alist and &hash. + +This is especially useful when we want to capture the result of a +computation and destructure at the same time. Consider the +form (function-returning-complex-structure) returning a list of +two vectors with two items each. We want to capture this entire +result and pass it to another computation, but at the same time +we want to get the second item from each vector. We can achieve +it with pattern + + (result &as [_ a] [_ b]) (function-returning-complex-structure) + +Note: Clojure programmers may know this feature as the \":as +binding\". The difference is that we put the &as at the front +because we need to support improper list binding." + (declare (debug ([&or (&rest [&or (sexp form) sexp]) + (vector [&rest [sexp form]])] + body)) + (indent 1)) + (if (vectorp varlist) + `(let* ,(dash--match (aref varlist 0) (aref varlist 1)) + ,@body) + (let* ((varlist (dash--normalize-let-varlist varlist)) + (inputs (--map-indexed (list (make-symbol (format "input%d" it-index)) (cadr it)) varlist)) + (new-varlist (--map (list (caar it) (cadr it)) (-zip varlist inputs)))) + `(let ,inputs + (-let* ,new-varlist ,@body))))) + +(defmacro -lambda (match-form &rest body) + "Return a lambda which destructures its input as MATCH-FORM and executes BODY. + +Note that you have to enclose the MATCH-FORM in a pair of parens, +such that: + + (-lambda (x) body) + (-lambda (x y ...) body) + +has the usual semantics of `lambda'. Furthermore, these get +translated into normal `lambda', so there is no performance +penalty. + +See `-let' for a description of the destructuring mechanism." + (declare (doc-string 2) (indent defun) + (debug (&define sexp + [&optional stringp] + [&optional ("interactive" interactive)] + def-body))) + (cond + ((nlistp match-form) + (signal 'wrong-type-argument (list #'listp match-form))) + ;; No destructuring, so just return regular `lambda' for speed. + ((-all? #'symbolp match-form) + `(lambda ,match-form ,@body)) + ((let ((inputs (--map-indexed + (list it (make-symbol (format "input%d" it-index))) + match-form))) + ;; TODO: because inputs to the `lambda' are evaluated only once, + ;; `-let*' need not create the extra bindings to ensure that. + ;; We should find a way to optimize that. Not critical however. + `(lambda ,(mapcar #'cadr inputs) + (-let* ,inputs ,@body)))))) + +(defmacro -setq (&rest forms) + "Bind each MATCH-FORM to the value of its VAL. + +MATCH-FORM destructuring is done according to the rules of `-let'. + +This macro allows you to bind multiple variables by destructuring +the value, so for example: + + (-setq (a b) x + (&plist :c c) plist) + +expands roughly speaking to the following code + + (setq a (car x) + b (cadr x) + c (plist-get plist :c)) + +Care is taken to only evaluate each VAL once so that in case of +multiple assignments it does not cause unexpected side effects. + +\(fn [MATCH-FORM VAL]...)" + (declare (debug (&rest sexp form)) + (indent 1)) + (when (= (mod (length forms) 2) 1) + (signal 'wrong-number-of-arguments (list '-setq (1+ (length forms))))) + (let* ((forms-and-sources + ;; First get all the necessary mappings with all the + ;; intermediate bindings. + (-map (lambda (x) (dash--match (car x) (cadr x))) + (-partition 2 forms))) + ;; To preserve the logic of dynamic scoping we must ensure + ;; that we `setq' the variables outside of the `let*' form + ;; which holds the destructured intermediate values. For + ;; this we generate for each variable a placeholder which is + ;; bound to (lexically) the result of the destructuring. + ;; Then outside of the helper `let*' form we bind all the + ;; original variables to their respective placeholders. + ;; TODO: There is a lot of room for possible optimization, + ;; for start playing with `special-variable-p' to eliminate + ;; unnecessary re-binding. + (variables-to-placeholders + (-mapcat + (lambda (bindings) + (-map + (lambda (binding) + (let ((var (car binding))) + (list var (make-symbol (concat "--dash-binding-" (symbol-name var) "--"))))) + (--filter (not (string-prefix-p "--" (symbol-name (car it)))) bindings))) + forms-and-sources))) + `(let ,(-map 'cadr variables-to-placeholders) + (let* ,(-flatten-n 1 forms-and-sources) + (setq ,@(-flatten (-map 'reverse variables-to-placeholders)))) + (setq ,@(-flatten variables-to-placeholders))))) + +(defmacro -if-let* (vars-vals then &rest else) + "If all VALS evaluate to true, bind them to their corresponding +VARS and do THEN, otherwise do ELSE. VARS-VALS should be a list +of (VAR VAL) pairs. + +Note: binding is done according to `-let*'. VALS are evaluated +sequentially, and evaluation stops after the first nil VAL is +encountered." + (declare (debug ((&rest (sexp form)) form body)) + (indent 2)) + (->> vars-vals + (--mapcat (dash--match (car it) (cadr it))) + (--reduce-r-from + (let ((var (car it)) + (val (cadr it))) + `(let ((,var ,val)) + (if ,var ,acc ,@else))) + then))) + +(defmacro -if-let (var-val then &rest else) + "If VAL evaluates to non-nil, bind it to VAR and do THEN, +otherwise do ELSE. + +Note: binding is done according to `-let'. + +\(fn (VAR VAL) THEN &rest ELSE)" + (declare (debug ((sexp form) form body)) + (indent 2)) + `(-if-let* (,var-val) ,then ,@else)) + +(defmacro --if-let (val then &rest else) + "If VAL evaluates to non-nil, bind it to symbol `it' and do THEN, +otherwise do ELSE." + (declare (debug (form form body)) + (indent 2)) + `(-if-let (it ,val) ,then ,@else)) + +(defmacro -when-let* (vars-vals &rest body) + "If all VALS evaluate to true, bind them to their corresponding +VARS and execute body. VARS-VALS should be a list of (VAR VAL) +pairs. + +Note: binding is done according to `-let*'. VALS are evaluated +sequentially, and evaluation stops after the first nil VAL is +encountered." + (declare (debug ((&rest (sexp form)) body)) + (indent 1)) + `(-if-let* ,vars-vals (progn ,@body))) + +(defmacro -when-let (var-val &rest body) + "If VAL evaluates to non-nil, bind it to VAR and execute body. + +Note: binding is done according to `-let'. + +\(fn (VAR VAL) &rest BODY)" + (declare (debug ((sexp form) body)) + (indent 1)) + `(-if-let ,var-val (progn ,@body))) + +(defmacro --when-let (val &rest body) + "If VAL evaluates to non-nil, bind it to symbol `it' and +execute body." + (declare (debug (form body)) + (indent 1)) + `(--if-let ,val (progn ,@body))) + +(defvar -compare-fn nil + "Tests for equality use this function or `equal' if this is nil. +It should only be set using dynamic scope with a let, like: + + (let ((-compare-fn #\\='=)) (-union numbers1 numbers2 numbers3)") + +(defun -distinct (list) + "Return a new list with all duplicates removed. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil. + +Alias: `-uniq'" + ;; Implementation note: The speedup gained from hash table lookup + ;; starts to outweigh its overhead for lists of length greater than + ;; 32. See discussion in PR #305. + (let* ((len (length list)) + (lut (and (> len 32) + ;; Check that `-compare-fn' is a valid hash-table + ;; lookup function or `nil'. + (memq -compare-fn '(nil equal eq eql)) + (make-hash-table :test (or -compare-fn #'equal) + :size len)))) + (if lut + (--filter (unless (gethash it lut) + (puthash it t lut)) + list) + (--each list (unless (-contains? lut it) (!cons it lut))) + (nreverse lut)))) + +(defalias '-uniq '-distinct) + +(defun -union (list list2) + "Return a new list containing the elements of LIST and elements of LIST2 that are not in LIST. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil." + ;; We fall back to iteration implementation if the comparison + ;; function isn't one of `eq', `eql' or `equal'. + (let* ((result (reverse list)) + ;; TODO: get rid of this dynamic variable, pass it as an + ;; argument instead. + (-compare-fn (if (bound-and-true-p -compare-fn) + -compare-fn + 'equal))) + (if (memq -compare-fn '(eq eql equal)) + (let ((ht (make-hash-table :test -compare-fn))) + (--each list (puthash it t ht)) + (--each list2 (unless (gethash it ht) (!cons it result)))) + (--each list2 (unless (-contains? result it) (!cons it result)))) + (nreverse result))) + +(defun -intersection (list list2) + "Return a new list containing only the elements that are members of both LIST and LIST2. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil." + (--filter (-contains? list2 it) list)) + +(defun -difference (list list2) + "Return a new list with only the members of LIST that are not in LIST2. +The test for equality is done with `equal', +or with `-compare-fn' if that's non-nil." + (--filter (not (-contains? list2 it)) list)) + +(defun -powerset (list) + "Return the power set of LIST." + (if (null list) '(()) + (let ((last (-powerset (cdr list)))) + (append (mapcar (lambda (x) (cons (car list) x)) last) + last)))) + +(defun -permutations (list) + "Return the permutations of LIST." + (if (null list) '(()) + (apply #'append + (mapcar (lambda (x) + (mapcar (lambda (perm) (cons x perm)) + (-permutations (remove x list)))) + list)))) + +(defun -inits (list) + "Return all prefixes of LIST." + (let ((res (list list))) + (setq list (reverse list)) + (while list + (push (reverse (!cdr list)) res)) + res)) + +(defun -tails (list) + "Return all suffixes of LIST" + (-reductions-r-from 'cons nil list)) + +(defun -common-prefix (&rest lists) + "Return the longest common prefix of LISTS." + (declare (pure t) (side-effect-free t)) + (--reduce (--take-while (and acc (equal (pop acc) it)) it) + lists)) + +(defun -common-suffix (&rest lists) + "Return the longest common suffix of LISTS." + (nreverse (apply #'-common-prefix (mapcar #'reverse lists)))) + +(defun -contains? (list element) + "Return non-nil if LIST contains ELEMENT. + +The test for equality is done with `equal', or with `-compare-fn' +if that's non-nil. + +Alias: `-contains-p'" + (not + (null + (cond + ((null -compare-fn) (member element list)) + ((eq -compare-fn 'eq) (memq element list)) + ((eq -compare-fn 'eql) (memql element list)) + (t + (let ((lst list)) + (while (and lst + (not (funcall -compare-fn element (car lst)))) + (setq lst (cdr lst))) + lst)))))) + +(defalias '-contains-p '-contains?) + +(defun -same-items? (list list2) + "Return true if LIST and LIST2 has the same items. + +The order of the elements in the lists does not matter. + +Alias: `-same-items-p'" + (let ((length-a (length list)) + (length-b (length list2))) + (and + (= length-a length-b) + (= length-a (length (-intersection list list2)))))) + +(defalias '-same-items-p '-same-items?) + +(defun -is-prefix? (prefix list) + "Return non-nil if PREFIX is a prefix of LIST. + +Alias: `-is-prefix-p'." + (declare (pure t) (side-effect-free t)) + (--each-while list (and (equal (car prefix) it) + (!cdr prefix))) + (null prefix)) + +(defun -is-suffix? (suffix list) + "Return non-nil if SUFFIX is a suffix of LIST. + +Alias: `-is-suffix-p'." + (declare (pure t) (side-effect-free t)) + (cond ((null suffix)) + ((setq list (member (car suffix) list)) + (equal (cdr suffix) (cdr list))))) + +(defun -is-infix? (infix list) + "Return non-nil if INFIX is infix of LIST. + +This operation runs in O(n^2) time + +Alias: `-is-infix-p'" + (declare (pure t) (side-effect-free t)) + (let (done) + (while (and (not done) list) + (setq done (-is-prefix? infix list)) + (!cdr list)) + done)) + +(defalias '-is-prefix-p '-is-prefix?) +(defalias '-is-suffix-p '-is-suffix?) +(defalias '-is-infix-p '-is-infix?) + +(defun -sort (comparator list) + "Sort LIST, stably, comparing elements using COMPARATOR. +Return the sorted list. LIST is NOT modified by side effects. +COMPARATOR is called with two elements of LIST, and should return non-nil +if the first element should sort before the second." + (sort (copy-sequence list) comparator)) + +(defmacro --sort (form list) + "Anaphoric form of `-sort'." + (declare (debug (def-form form))) + `(-sort (lambda (it other) ,form) ,list)) + +(defun -list (&optional arg &rest args) + "Ensure ARG is a list. +If ARG is already a list, return it as is (not a copy). +Otherwise, return a new list with ARG as its only element. + +Another supported calling convention is (-list &rest ARGS). +In this case, if ARG is not a list, a new list with all of +ARGS as elements is returned. This use is supported for +backward compatibility and is otherwise deprecated." + (declare (advertised-calling-convention (arg) "2.18.0") + (pure t) (side-effect-free t)) + (if (listp arg) arg (cons arg args))) + +(defun -repeat (n x) + "Return a new list of length N with each element being X. +Return nil if N is less than 1." + (declare (pure t) (side-effect-free t)) + (and (natnump n) (make-list n x))) + +(defun -sum (list) + "Return the sum of LIST." + (declare (pure t) (side-effect-free t)) + (apply '+ list)) + +(defun -running-sum (list) + "Return a list with running sums of items in LIST. +LIST must be non-empty." + (declare (pure t) (side-effect-free t)) + (or list (signal 'wrong-type-argument (list #'consp list))) + (-reductions #'+ list)) + +(defun -product (list) + "Return the product of LIST." + (declare (pure t) (side-effect-free t)) + (apply '* list)) + +(defun -running-product (list) + "Return a list with running products of items in LIST. +LIST must be non-empty." + (declare (pure t) (side-effect-free t)) + (or list (signal 'wrong-type-argument (list #'consp list))) + (-reductions #'* list)) + +(defun -max (list) + "Return the largest value from LIST of numbers or markers." + (declare (pure t) (side-effect-free t)) + (apply 'max list)) + +(defun -min (list) + "Return the smallest value from LIST of numbers or markers." + (declare (pure t) (side-effect-free t)) + (apply 'min list)) + +(defun -max-by (comparator list) + "Take a comparison function COMPARATOR and a LIST and return +the greatest element of the list by the comparison function. + +See also combinator `-on' which can transform the values before +comparing them." + (--reduce (if (funcall comparator it acc) it acc) list)) + +(defun -min-by (comparator list) + "Take a comparison function COMPARATOR and a LIST and return +the least element of the list by the comparison function. + +See also combinator `-on' which can transform the values before +comparing them." + (--reduce (if (funcall comparator it acc) acc it) list)) + +(defmacro --max-by (form list) + "Anaphoric version of `-max-by'. + +The items for the comparator form are exposed as \"it\" and \"other\"." + (declare (debug (def-form form))) + `(-max-by (lambda (it other) ,form) ,list)) + +(defmacro --min-by (form list) + "Anaphoric version of `-min-by'. + +The items for the comparator form are exposed as \"it\" and \"other\"." + (declare (debug (def-form form))) + `(-min-by (lambda (it other) ,form) ,list)) + +(defun -iota (count &optional start step) + "Return a list containing COUNT numbers. +Starts from START and adds STEP each time. The default START is +zero, the default STEP is 1. +This function takes its name from the corresponding primitive in +the APL language." + (declare (pure t) (side-effect-free t)) + (unless (natnump count) + (signal 'wrong-type-argument (list #'natnump count))) + (or start (setq start 0)) + (or step (setq step 1)) + (if (zerop step) + (make-list count start) + (--iterate (+ it step) start count))) + +(defun -fix (fn list) + "Compute the (least) fixpoint of FN with initial input LIST. + +FN is called at least once, results are compared with `equal'." + (let ((re (funcall fn list))) + (while (not (equal list re)) + (setq list re) + (setq re (funcall fn re))) + re)) + +(defmacro --fix (form list) + "Anaphoric form of `-fix'." + (declare (debug (def-form form))) + `(-fix (lambda (it) ,form) ,list)) + +(defun -unfold (fun seed) + "Build a list from SEED using FUN. + +This is \"dual\" operation to `-reduce-r': while -reduce-r +consumes a list to produce a single value, `-unfold' takes a +seed value and builds a (potentially infinite!) list. + +FUN should return `nil' to stop the generating process, or a +cons (A . B), where A will be prepended to the result and B is +the new seed." + (let ((last (funcall fun seed)) r) + (while last + (push (car last) r) + (setq last (funcall fun (cdr last)))) + (nreverse r))) + +(defmacro --unfold (form seed) + "Anaphoric version of `-unfold'." + (declare (debug (def-form form))) + `(-unfold (lambda (it) ,form) ,seed)) + +(defun -cons-pair? (obj) + "Return non-nil if OBJ is a true cons pair. +That is, a cons (A . B) where B is not a list. + +Alias: `-cons-pair-p'." + (declare (pure t) (side-effect-free t)) + (nlistp (cdr-safe obj))) + +(defalias '-cons-pair-p '-cons-pair?) + +(defun -cons-to-list (con) + "Convert a cons pair to a list with `car' and `cdr' of the pair respectively." + (declare (pure t) (side-effect-free t)) + (list (car con) (cdr con))) + +(defun -value-to-list (val) + "Convert a value to a list. + +If the value is a cons pair, make a list with two elements, `car' +and `cdr' of the pair respectively. + +If the value is anything else, wrap it in a list." + (declare (pure t) (side-effect-free t)) + (cond + ((-cons-pair? val) (-cons-to-list val)) + (t (list val)))) + +(defun -tree-mapreduce-from (fn folder init-value tree) + "Apply FN to each element of TREE, and make a list of the results. +If elements of TREE are lists themselves, apply FN recursively to +elements of these nested lists. + +Then reduce the resulting lists using FOLDER and initial value +INIT-VALUE. See `-reduce-r-from'. + +This is the same as calling `-tree-reduce-from' after `-tree-map' +but is twice as fast as it only traverse the structure once." + (cond + ((not tree) nil) + ((-cons-pair? tree) (funcall fn tree)) + ((listp tree) + (-reduce-r-from folder init-value (mapcar (lambda (x) (-tree-mapreduce-from fn folder init-value x)) tree))) + (t (funcall fn tree)))) + +(defmacro --tree-mapreduce-from (form folder init-value tree) + "Anaphoric form of `-tree-mapreduce-from'." + (declare (debug (def-form def-form form form))) + `(-tree-mapreduce-from (lambda (it) ,form) (lambda (it acc) ,folder) ,init-value ,tree)) + +(defun -tree-mapreduce (fn folder tree) + "Apply FN to each element of TREE, and make a list of the results. +If elements of TREE are lists themselves, apply FN recursively to +elements of these nested lists. + +Then reduce the resulting lists using FOLDER and initial value +INIT-VALUE. See `-reduce-r-from'. + +This is the same as calling `-tree-reduce' after `-tree-map' +but is twice as fast as it only traverse the structure once." + (cond + ((not tree) nil) + ((-cons-pair? tree) (funcall fn tree)) + ((listp tree) + (-reduce-r folder (mapcar (lambda (x) (-tree-mapreduce fn folder x)) tree))) + (t (funcall fn tree)))) + +(defmacro --tree-mapreduce (form folder tree) + "Anaphoric form of `-tree-mapreduce'." + (declare (debug (def-form def-form form))) + `(-tree-mapreduce (lambda (it) ,form) (lambda (it acc) ,folder) ,tree)) + +(defun -tree-map (fn tree) + "Apply FN to each element of TREE while preserving the tree structure." + (cond + ((not tree) nil) + ((-cons-pair? tree) (funcall fn tree)) + ((listp tree) + (mapcar (lambda (x) (-tree-map fn x)) tree)) + (t (funcall fn tree)))) + +(defmacro --tree-map (form tree) + "Anaphoric form of `-tree-map'." + (declare (debug (def-form form))) + `(-tree-map (lambda (it) ,form) ,tree)) + +(defun -tree-reduce-from (fn init-value tree) + "Use FN to reduce elements of list TREE. +If elements of TREE are lists themselves, apply the reduction recursively. + +FN is first applied to INIT-VALUE and first element of the list, +then on this result and second element from the list etc. + +The initial value is ignored on cons pairs as they always contain +two elements." + (cond + ((not tree) nil) + ((-cons-pair? tree) tree) + ((listp tree) + (-reduce-r-from fn init-value (mapcar (lambda (x) (-tree-reduce-from fn init-value x)) tree))) + (t tree))) + +(defmacro --tree-reduce-from (form init-value tree) + "Anaphoric form of `-tree-reduce-from'." + (declare (debug (def-form form form))) + `(-tree-reduce-from (lambda (it acc) ,form) ,init-value ,tree)) + +(defun -tree-reduce (fn tree) + "Use FN to reduce elements of list TREE. +If elements of TREE are lists themselves, apply the reduction recursively. + +FN is first applied to first element of the list and second +element, then on this result and third element from the list etc. + +See `-reduce-r' for how exactly are lists of zero or one element handled." + (cond + ((not tree) nil) + ((-cons-pair? tree) tree) + ((listp tree) + (-reduce-r fn (mapcar (lambda (x) (-tree-reduce fn x)) tree))) + (t tree))) + +(defmacro --tree-reduce (form tree) + "Anaphoric form of `-tree-reduce'." + (declare (debug (def-form form))) + `(-tree-reduce (lambda (it acc) ,form) ,tree)) + +(defun -tree-map-nodes (pred fun tree) + "Call FUN on each node of TREE that satisfies PRED. + +If PRED returns nil, continue descending down this node. If PRED +returns non-nil, apply FUN to this node and do not descend +further." + (if (funcall pred tree) + (funcall fun tree) + (if (and (listp tree) + (not (-cons-pair? tree))) + (-map (lambda (x) (-tree-map-nodes pred fun x)) tree) + tree))) + +(defmacro --tree-map-nodes (pred form tree) + "Anaphoric form of `-tree-map-nodes'." + (declare (debug (def-form def-form form))) + `(-tree-map-nodes (lambda (it) ,pred) (lambda (it) ,form) ,tree)) + +(defun -tree-seq (branch children tree) + "Return a sequence of the nodes in TREE, in depth-first search order. + +BRANCH is a predicate of one argument that returns non-nil if the +passed argument is a branch, that is, a node that can have children. + +CHILDREN is a function of one argument that returns the children +of the passed branch node. + +Non-branch nodes are simply copied." + (cons tree + (when (funcall branch tree) + (-mapcat (lambda (x) (-tree-seq branch children x)) + (funcall children tree))))) + +(defmacro --tree-seq (branch children tree) + "Anaphoric form of `-tree-seq'." + (declare (debug (def-form def-form form))) + `(-tree-seq (lambda (it) ,branch) (lambda (it) ,children) ,tree)) + +(defun -clone (list) + "Create a deep copy of LIST. +The new list has the same elements and structure but all cons are +replaced with new ones. This is useful when you need to clone a +structure such as plist or alist." + (declare (pure t) (side-effect-free t)) + (-tree-map 'identity list)) + +;;; Combinators + +(defalias '-partial #'apply-partially) + +(defun -rpartial (fn &rest args) + "Return a function that is a partial application of FN to ARGS. +ARGS is a list of the last N arguments to pass to FN. The result +is a new function which does the same as FN, except that the last +N arguments are fixed at the values with which this function was +called. This is like `-partial', except the arguments are fixed +starting from the right rather than the left." + (declare (pure t) (side-effect-free t)) + (lambda (&rest args-before) (apply fn (append args-before args)))) + +(defun -juxt (&rest fns) + "Return a function that is the juxtaposition of FNS. +The returned function takes a variable number of ARGS, applies +each of FNS in turn to ARGS, and returns the list of results." + (declare (pure t) (side-effect-free t)) + (lambda (&rest args) (mapcar (lambda (x) (apply x args)) fns))) + +(defun -compose (&rest fns) + "Compose FNS into a single composite function. +Return a function that takes a variable number of ARGS, applies +the last function in FNS to ARGS, and returns the result of +calling each remaining function on the result of the previous +function, right-to-left. If no FNS are given, return a variadic +`identity' function." + (declare (pure t) (side-effect-free t)) + (let* ((fns (nreverse fns)) + (head (car fns)) + (tail (cdr fns))) + (cond (tail + (lambda (&rest args) + (--reduce-from (funcall it acc) (apply head args) tail))) + (fns head) + ((lambda (&optional arg &rest _) arg))))) + +(defun -applify (fn) + "Return a function that applies FN to a single list of args. +This changes the arity of FN from taking N distinct arguments to +taking 1 argument which is a list of N arguments." + (declare (pure t) (side-effect-free t)) + (lambda (args) (apply fn args))) + +(defun -on (op trans) + "Return a function that calls TRANS on each arg and OP on the results. +The returned function takes a variable number of arguments, calls +the function TRANS on each one in turn, and then passes those +results as the list of arguments to OP, in the same order. + +For example, the following pairs of expressions are morally +equivalent: + + (funcall (-on #\\='+ #\\='1+) 1 2 3) = (+ (1+ 1) (1+ 2) (1+ 3)) + (funcall (-on #\\='+ #\\='1+)) = (+)" + (declare (pure t) (side-effect-free t)) + (lambda (&rest args) + ;; This unrolling seems to be a relatively cheap way to keep the + ;; overhead of `mapcar' + `apply' in check. + (cond ((cddr args) + (apply op (mapcar trans args))) + ((cdr args) + (funcall op (funcall trans (car args)) (funcall trans (cadr args)))) + (args + (funcall op (funcall trans (car args)))) + ((funcall op))))) + +(defun -flip (fn) + "Return a function that calls FN with its arguments reversed. +The returned function takes the same number of arguments as FN. + +For example, the following two expressions are morally +equivalent: + + (funcall (-flip #\\='-) 1 2) = (- 2 1) + +See also: `-rotate-args'." + (declare (pure t) (side-effect-free t)) + (lambda (&rest args) ;; Open-code for speed. + (cond ((cddr args) (apply fn (nreverse args))) + ((cdr args) (funcall fn (cadr args) (car args))) + (args (funcall fn (car args))) + ((funcall fn))))) + +(defun -rotate-args (n fn) + "Return a function that calls FN with args rotated N places to the right. +The returned function takes the same number of arguments as FN, +rotates the list of arguments N places to the right (left if N is +negative) just like `-rotate', and applies FN to the result. + +See also: `-flip'." + (declare (pure t) (side-effect-free t)) + (if (zerop n) + fn + (let ((even (= (% n 2) 0))) + (lambda (&rest args) + (cond ((cddr args) ;; Open-code for speed. + (apply fn (-rotate n args))) + ((cdr args) + (let ((fst (car args)) + (snd (cadr args))) + (funcall fn (if even fst snd) (if even snd fst)))) + (args + (funcall fn (car args))) + ((funcall fn))))))) + +(defun -const (c) + "Return a function that returns C ignoring any additional arguments. + +In types: a -> b -> a" + (declare (pure t) (side-effect-free t)) + (lambda (&rest _) c)) + +(defmacro -cut (&rest params) + "Take n-ary function and n arguments and specialize some of them. +Arguments denoted by <> will be left unspecialized. + +See SRFI-26 for detailed description." + (declare (debug (&optional sexp &rest &or "<>" form))) + (let* ((i 0) + (args (--keep (when (eq it '<>) + (setq i (1+ i)) + (make-symbol (format "D%d" i))) + params))) + `(lambda ,args + ,(let ((body (--map (if (eq it '<>) (pop args) it) params))) + (if (eq (car params) '<>) + (cons #'funcall body) + body))))) + +(defun -not (pred) + "Return a predicate that negates the result of PRED. +The returned predicate passes its arguments to PRED. If PRED +returns nil, the result is non-nil; otherwise the result is nil. + +See also: `-andfn' and `-orfn'." + (declare (pure t) (side-effect-free t)) + (lambda (&rest args) (not (apply pred args)))) + +(defun -orfn (&rest preds) + "Return a predicate that returns the first non-nil result of PREDS. +The returned predicate takes a variable number of arguments, +passes them to each predicate in PREDS in turn until one of them +returns non-nil, and returns that non-nil result without calling +the remaining PREDS. If all PREDS return nil, or if no PREDS are +given, the returned predicate returns nil. + +See also: `-andfn' and `-not'." + (declare (pure t) (side-effect-free t)) + ;; Open-code for speed. + (cond ((cdr preds) (lambda (&rest args) (--some (apply it args) preds))) + (preds (car preds)) + (#'ignore))) + +(defun -andfn (&rest preds) + "Return a predicate that returns non-nil if all PREDS do so. +The returned predicate P takes a variable number of arguments and +passes them to each predicate in PREDS in turn. If any one of +PREDS returns nil, P also returns nil without calling the +remaining PREDS. If all PREDS return non-nil, P returns the last +such value. If no PREDS are given, P always returns non-nil. + +See also: `-orfn' and `-not'." + (declare (pure t) (side-effect-free t)) + ;; Open-code for speed. + (cond ((cdr preds) (lambda (&rest args) (--every (apply it args) preds))) + (preds (car preds)) + ;; As a `pure' function, this runtime check may generate + ;; backward-incompatible bytecode for `(-andfn)' at compile-time, + ;; but I doubt that's a problem in practice (famous last words). + ((fboundp 'always) #'always) + ((lambda (&rest _) t)))) + +(defun -iteratefn (fn n) + "Return a function FN composed N times with itself. + +FN is a unary function. If you need to use a function of higher +arity, use `-applify' first to turn it into a unary function. + +With n = 0, this acts as identity function. + +In types: (a -> a) -> Int -> a -> a. + +This function satisfies the following law: + + (funcall (-iteratefn fn n) init) = (-last-item (-iterate fn init (1+ n)))." + (lambda (x) (--dotimes n (setq x (funcall fn x))) x)) + +(defun -counter (&optional beg end inc) + "Return a closure that counts from BEG to END, with increment INC. + +The closure will return the next value in the counting sequence +each time it is called, and nil after END is reached. BEG +defaults to 0, INC defaults to 1, and if END is nil, the counter +will increment indefinitely. + +The closure accepts any number of arguments, which are discarded." + (let ((inc (or inc 1)) + (n (or beg 0))) + (lambda (&rest _) + (when (or (not end) (< n end)) + (prog1 n + (setq n (+ n inc))))))) + +(defvar -fixfn-max-iterations 1000 + "The default maximum number of iterations performed by `-fixfn' + unless otherwise specified.") + +(defun -fixfn (fn &optional equal-test halt-test) + "Return a function that computes the (least) fixpoint of FN. + +FN must be a unary function. The returned lambda takes a single +argument, X, the initial value for the fixpoint iteration. The +iteration halts when either of the following conditions is satisfied: + + 1. Iteration converges to the fixpoint, with equality being + tested using EQUAL-TEST. If EQUAL-TEST is not specified, + `equal' is used. For functions over the floating point + numbers, it may be necessary to provide an appropriate + approximate comparison test. + + 2. HALT-TEST returns a non-nil value. HALT-TEST defaults to a + simple counter that returns t after `-fixfn-max-iterations', + to guard against infinite iteration. Otherwise, HALT-TEST + must be a function that accepts a single argument, the + current value of X, and returns non-nil as long as iteration + should continue. In this way, a more sophisticated + convergence test may be supplied by the caller. + +The return value of the lambda is either the fixpoint or, if +iteration halted before converging, a cons with car `halted' and +cdr the final output from HALT-TEST. + +In types: (a -> a) -> a -> a." + (let ((eqfn (or equal-test 'equal)) + (haltfn (or halt-test + (-not + (-counter 0 -fixfn-max-iterations))))) + (lambda (x) + (let ((re (funcall fn x)) + (halt? (funcall haltfn x))) + (while (and (not halt?) (not (funcall eqfn x re))) + (setq x re + re (funcall fn re) + halt? (funcall haltfn re))) + (if halt? (cons 'halted halt?) + re))))) + +(defun -prodfn (&rest fns) + "Take a list of n functions and return a function that takes a +list of length n, applying i-th function to i-th element of the +input list. Returns a list of length n. + +In types (for n=2): ((a -> b), (c -> d)) -> (a, c) -> (b, d) + +This function satisfies the following laws: + + (-compose (-prodfn f g ...) (-prodfn f\\=' g\\=' ...)) = (-prodfn (-compose f f\\=') (-compose g g\\=') ...) + (-prodfn f g ...) = (-juxt (-compose f (-partial \\='nth 0)) (-compose g (-partial \\='nth 1)) ...) + (-compose (-prodfn f g ...) (-juxt f\\=' g\\=' ...)) = (-juxt (-compose f f\\=') (-compose g g\\=') ...) + (-compose (-partial \\='nth n) (-prod f1 f2 ...)) = (-compose fn (-partial \\='nth n))" + (lambda (x) (-zip-with 'funcall fns x))) + +;;; Font lock + +(defvar dash--keywords + `(;; TODO: Do not fontify the following automatic variables + ;; globally; detect and limit to their local anaphoric scope. + (,(rx symbol-start (| "acc" "it" "it-index" "other") symbol-end) + 0 font-lock-variable-name-face) + ;; Macros in dev/examples.el. Based on `lisp-mode-symbol-regexp'. + (,(rx ?\( (group (| "defexamples" "def-example-group")) symbol-end + (+ (in "\t ")) + (group (* (| (syntax word) (syntax symbol) (: ?\\ nonl))))) + (1 font-lock-keyword-face) + (2 font-lock-function-name-face)) + ;; Symbols in dev/examples.el. + ,(rx symbol-start (| "=>" "~>" "!!>") symbol-end) + ;; Elisp macro fontification was static prior to Emacs 25. + ,@(when (< emacs-major-version 25) + (let ((macs '("!cdr" + "!cons" + "-->" + "--all?" + "--annotate" + "--any?" + "--count" + "--dotimes" + "--doto" + "--drop-while" + "--each" + "--each-r" + "--each-r-while" + "--each-while" + "--filter" + "--find-index" + "--find-indices" + "--find-last-index" + "--first" + "--fix" + "--group-by" + "--if-let" + "--iterate" + "--keep" + "--last" + "--map" + "--map-first" + "--map-indexed" + "--map-last" + "--map-when" + "--mapcat" + "--max-by" + "--min-by" + "--none?" + "--only-some?" + "--partition-by" + "--partition-by-header" + "--reduce" + "--reduce-from" + "--reduce-r" + "--reduce-r-from" + "--reductions" + "--reductions-from" + "--reductions-r" + "--reductions-r-from" + "--remove" + "--remove-first" + "--remove-last" + "--separate" + "--some" + "--sort" + "--splice" + "--splice-list" + "--split-when" + "--split-with" + "--take-while" + "--tree-map" + "--tree-map-nodes" + "--tree-mapreduce" + "--tree-mapreduce-from" + "--tree-reduce" + "--tree-reduce-from" + "--tree-seq" + "--unfold" + "--update-at" + "--when-let" + "--zip-with" + "->" + "->>" + "-as->" + "-doto" + "-if-let" + "-if-let*" + "-lambda" + "-let" + "-let*" + "-setq" + "-some-->" + "-some->" + "-some->>" + "-split-on" + "-when-let" + "-when-let*"))) + `((,(concat "(" (regexp-opt macs 'symbols)) . 1))))) + "Font lock keywords for `dash-fontify-mode'.") + +(defcustom dash-fontify-mode-lighter nil + "Mode line lighter for `dash-fontify-mode'. +Either a string to display in the mode line when +`dash-fontify-mode' is on, or nil to display +nothing (the default)." + :package-version '(dash . "2.18.0") + :group 'dash + :type '(choice (string :tag "Lighter" :value " Dash") + (const :tag "Nothing" nil))) + +;;;###autoload +(define-minor-mode dash-fontify-mode + "Toggle fontification of Dash special variables. + +Dash-Fontify mode is a buffer-local minor mode intended for Emacs +Lisp buffers. Enabling it causes the special variables bound in +anaphoric Dash macros to be fontified. These anaphoras include +`it', `it-index', `acc', and `other'. In older Emacs versions +which do not dynamically detect macros, Dash-Fontify mode +additionally fontifies Dash macro calls. + +See also `dash-fontify-mode-lighter' and +`global-dash-fontify-mode'." + :group 'dash :lighter dash-fontify-mode-lighter + (if dash-fontify-mode + (font-lock-add-keywords nil dash--keywords t) + (font-lock-remove-keywords nil dash--keywords)) + (cond ((fboundp 'font-lock-flush) ;; Added in Emacs 25. + (font-lock-flush)) + ;; `font-lock-fontify-buffer' unconditionally enables + ;; `font-lock-mode' and is marked `interactive-only' in later + ;; Emacs versions which have `font-lock-flush', so we guard + ;; and pacify as needed, respectively. + (font-lock-mode + (with-no-warnings + (font-lock-fontify-buffer))))) + +(defun dash--turn-on-fontify-mode () + "Enable `dash-fontify-mode' if in an Emacs Lisp buffer." + (when (derived-mode-p #'emacs-lisp-mode) + (dash-fontify-mode))) + +;;;###autoload +(define-globalized-minor-mode global-dash-fontify-mode + dash-fontify-mode dash--turn-on-fontify-mode + :group 'dash) + +(defcustom dash-enable-fontlock nil + "If non-nil, fontify Dash macro calls and special variables." + :group 'dash + :set (lambda (sym val) + (set-default sym val) + (global-dash-fontify-mode (if val 1 0))) + :type 'boolean) + +(make-obsolete-variable + 'dash-enable-fontlock #'global-dash-fontify-mode "2.18.0") + +(define-obsolete-function-alias + 'dash-enable-font-lock #'global-dash-fontify-mode "2.18.0") + +;;; Info + +(defvar dash--info-doc-spec '("(dash) Index" nil "^ -+ .*: " "\\( \\|$\\)") + "The Dash :doc-spec entry for `info-lookup-alist'. +It is based on that for `emacs-lisp-mode'.") + +(defun dash--info-elisp-docs () + "Return the `emacs-lisp-mode' symbol docs from `info-lookup-alist'. +Specifically, return the cons containing their +`info-lookup->doc-spec' so that we can modify it." + (defvar info-lookup-alist) + (nthcdr 3 (assq #'emacs-lisp-mode (cdr (assq 'symbol info-lookup-alist))))) + +;;;###autoload +(defun dash-register-info-lookup () + "Register the Dash Info manual with `info-lookup-symbol'. +This allows Dash symbols to be looked up with \\[info-lookup-symbol]." + (interactive) + (require 'info-look) + (let ((docs (dash--info-elisp-docs))) + (setcar docs (append (car docs) (list dash--info-doc-spec))) + (info-lookup-reset))) + +(defun dash-unload-function () + "Remove Dash from `info-lookup-alist'. +Used by `unload-feature', which see." + (let ((docs (and (featurep 'info-look) + (dash--info-elisp-docs)))) + (when (member dash--info-doc-spec (car docs)) + (setcar docs (remove dash--info-doc-spec (car docs))) + (info-lookup-reset))) + nil) + +(provide 'dash) +;;; dash.el ends here diff --git a/emacs.d/elpa/dash-20210708.2009/dash.info b/emacs.d/elpa/dash-20210708.2009/dash.info new file mode 100644 index 0000000..48c1af7 --- /dev/null +++ b/emacs.d/elpa/dash-20210708.2009/dash.info @@ -0,0 +1,4738 @@ +This is dash.info, produced by makeinfo version 6.7 from dash.texi. + +This manual is for Dash version 2.19.0. + + Copyright © 2012–2021 Free Software Foundation, Inc. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.3 or any later version published by the Free Software + Foundation; with the Invariant Sections being “GNU General Public + License,†and no Front-Cover Texts or Back-Cover Texts. A copy of + the license is included in the section entitled “GNU Free + Documentation Licenseâ€. +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* Dash: (dash.info). A modern list library for GNU Emacs. +END-INFO-DIR-ENTRY + + +File: dash.info, Node: Top, Next: Installation, Up: (dir) + +Dash +**** + +This manual is for Dash version 2.19.0. + + Copyright © 2012–2021 Free Software Foundation, Inc. + + Permission is granted to copy, distribute and/or modify this + document under the terms of the GNU Free Documentation License, + Version 1.3 or any later version published by the Free Software + Foundation; with the Invariant Sections being “GNU General Public + License,†and no Front-Cover Texts or Back-Cover Texts. A copy of + the license is included in the section entitled “GNU Free + Documentation Licenseâ€. + +* Menu: + +* Installation:: Installing and configuring Dash. +* Functions:: Dash API reference. +* Development:: Contributing to Dash development. + +Appendices + +* FDL:: The license for this documentation. +* GPL:: Conditions for copying and changing Dash. +* Index:: Index including functions and macros. + + — The Detailed Node Listing — + +Installation + +* Using in a package:: Listing Dash as a package dependency. +* Fontification of special variables:: Font Lock of anaphoric macro variables. +* Info symbol lookup:: Looking up Dash symbols in this manual. + +Functions + +* Maps:: +* Sublist selection:: +* List to list:: +* Reductions:: +* Unfolding:: +* Predicates:: +* Partitioning:: +* Indexing:: +* Set operations:: +* Other list operations:: +* Tree operations:: +* Threading macros:: +* Binding:: +* Side effects:: +* Destructive operations:: +* Function combinators:: + +Development + +* Contribute:: How to contribute. +* Contributors:: List of contributors. + + +File: dash.info, Node: Installation, Next: Functions, Prev: Top, Up: Top + +1 Installation +************** + +Dash is available on GNU ELPA (https://elpa.gnu.org/), GNU-devel ELPA +(https://elpa.gnu.org/devel/), and MELPA (https://melpa.org/), and can +be installed with the standard command ‘package-install’ (*note +(emacs)Package Installation::). + +‘M-x package-install <RET> dash <RET>’ + Install the Dash library. + + Alternatively, you can just dump ‘dash.el’ in your ‘load-path’ +somewhere (*note (emacs)Lisp Libraries::). + +* Menu: + +* Using in a package:: Listing Dash as a package dependency. +* Fontification of special variables:: Font Lock of anaphoric macro variables. +* Info symbol lookup:: Looking up Dash symbols in this manual. + + +File: dash.info, Node: Using in a package, Next: Fontification of special variables, Up: Installation + +1.1 Using in a package +====================== + +If you use Dash in your own package, be sure to list it as a dependency +in the library’s headers as follows (*note (elisp)Library Headers::). + + ;; Package-Requires: ((dash "2.19.0")) + + +File: dash.info, Node: Fontification of special variables, Next: Info symbol lookup, Prev: Using in a package, Up: Installation + +1.2 Fontification of special variables +====================================== + +The autoloaded minor mode ‘dash-fontify-mode’ is provided for optional +fontification of anaphoric Dash variables (‘it’, ‘acc’, etc.) in Emacs +Lisp buffers using search-based Font Lock (*note (emacs)Font Lock::). +In older Emacs versions which do not dynamically detect macros, the +minor mode also fontifies calls to Dash macros. + + To automatically enable the minor mode in all Emacs Lisp buffers, +just call its autoloaded global counterpart ‘global-dash-fontify-mode’, +either interactively or from your ‘user-init-file’: + + (global-dash-fontify-mode) + + +File: dash.info, Node: Info symbol lookup, Prev: Fontification of special variables, Up: Installation + +1.3 Info symbol lookup +====================== + +While editing Elisp files, you can use ‘C-h S’ (‘info-lookup-symbol’) to +look up Elisp symbols in the relevant Info manuals (*note (emacs)Info +Lookup::). To enable the same for Dash symbols, use the command +‘dash-register-info-lookup’. It can be called directly when needed, or +automatically from your ‘user-init-file’. For example: + + (with-eval-after-load 'info-look + (dash-register-info-lookup)) + + +File: dash.info, Node: Functions, Next: Development, Prev: Installation, Up: Top + +2 Functions +*********** + +This chapter contains reference documentation for the Dash API +(Application Programming Interface). The names of all public functions +defined in the library are prefixed with a dash character (‘-’). + + The library also provides anaphoric macro versions of functions where +that makes sense. The names of these macros are prefixed with two +dashes (‘--’) instead of one. + + For instance, while the function ‘-map’ applies a function to each +element of a list, its anaphoric counterpart ‘--map’ evaluates a form +with the local variable ‘it’ temporarily bound to the current list +element instead. + + ;; Normal version. + (-map (lambda (n) (* n n)) '(1 2 3 4)) + ⇒ (1 4 9 16) + + ;; Anaphoric version. + (--map (* it it) '(1 2 3 4)) + ⇒ (1 4 9 16) + + The normal version can, of course, also be written as in the +following example, which demonstrates the utility of both versions. + + (defun my-square (n) + "Return N multiplied by itself." + (* n n)) + + (-map #'my-square '(1 2 3 4)) + ⇒ (1 4 9 16) + +* Menu: + +* Maps:: +* Sublist selection:: +* List to list:: +* Reductions:: +* Unfolding:: +* Predicates:: +* Partitioning:: +* Indexing:: +* Set operations:: +* Other list operations:: +* Tree operations:: +* Threading macros:: +* Binding:: +* Side effects:: +* Destructive operations:: +* Function combinators:: + + +File: dash.info, Node: Maps, Next: Sublist selection, Up: Functions + +2.1 Maps +======== + +Functions in this category take a transforming function, which is then +applied sequentially to each or selected elements of the input list. +The results are collected in order and returned as a new list. + + -- Function: -map (fn list) + Apply FN to each item in LIST and return the list of results. + + This function’s anaphoric counterpart is ‘--map’. + + (-map (lambda (num) (* num num)) '(1 2 3 4)) + ⇒ (1 4 9 16) + (-map #'1+ '(1 2 3 4)) + ⇒ (2 3 4 5) + (--map (* it it) '(1 2 3 4)) + ⇒ (1 4 9 16) + + -- Function: -map-when (pred rep list) + Return a new list where the elements in LIST that do not match the + PRED function are unchanged, and where the elements in LIST that do + match the PRED function are mapped through the REP function. + + Alias: ‘-replace-where’ + + See also: ‘-update-at’ (*note -update-at::) + + (-map-when 'even? 'square '(1 2 3 4)) + ⇒ (1 4 3 16) + (--map-when (> it 2) (* it it) '(1 2 3 4)) + ⇒ (1 2 9 16) + (--map-when (= it 2) 17 '(1 2 3 4)) + ⇒ (1 17 3 4) + + -- Function: -map-first (pred rep list) + Replace first item in LIST satisfying PRED with result of REP + called on this item. + + See also: ‘-map-when’ (*note -map-when::), ‘-replace-first’ (*note + -replace-first::) + + (-map-first 'even? 'square '(1 2 3 4)) + ⇒ (1 4 3 4) + (--map-first (> it 2) (* it it) '(1 2 3 4)) + ⇒ (1 2 9 4) + (--map-first (= it 2) 17 '(1 2 3 2)) + ⇒ (1 17 3 2) + + -- Function: -map-last (pred rep list) + Replace last item in LIST satisfying PRED with result of REP called + on this item. + + See also: ‘-map-when’ (*note -map-when::), ‘-replace-last’ (*note + -replace-last::) + + (-map-last 'even? 'square '(1 2 3 4)) + ⇒ (1 2 3 16) + (--map-last (> it 2) (* it it) '(1 2 3 4)) + ⇒ (1 2 3 16) + (--map-last (= it 2) 17 '(1 2 3 2)) + ⇒ (1 2 3 17) + + -- Function: -map-indexed (fn list) + Apply FN to each index and item in LIST and return the list of + results. This is like ‘-map’ (*note -map::), but FN takes two + arguments: the index of the current element within LIST, and the + element itself. + + This function’s anaphoric counterpart is ‘--map-indexed’. + + For a side-effecting variant, see also ‘-each-indexed’ (*note + -each-indexed::). + + (-map-indexed (lambda (index item) (- item index)) '(1 2 3 4)) + ⇒ (1 1 1 1) + (--map-indexed (- it it-index) '(1 2 3 4)) + ⇒ (1 1 1 1) + (-map-indexed #'* '(1 2 3 4)) + ⇒ (0 2 6 12) + + -- Function: -annotate (fn list) + Return a list of cons cells where each cell is FN applied to each + element of LIST paired with the unmodified element of LIST. + + (-annotate '1+ '(1 2 3)) + ⇒ ((2 . 1) (3 . 2) (4 . 3)) + (-annotate 'length '(("h" "e" "l" "l" "o") ("hello" "world"))) + ⇒ ((5 "h" "e" "l" "l" "o") (2 "hello" "world")) + (--annotate (< 1 it) '(0 1 2 3)) + ⇒ ((nil . 0) (nil . 1) (t . 2) (t . 3)) + + -- Function: -splice (pred fun list) + Splice lists generated by FUN in place of elements matching PRED in + LIST. + + FUN takes the element matching PRED as input. + + This function can be used as replacement for ‘,@’ in case you need + to splice several lists at marked positions (for example with + keywords). + + See also: ‘-splice-list’ (*note -splice-list::), ‘-insert-at’ + (*note -insert-at::) + + (-splice 'even? (lambda (x) (list x x)) '(1 2 3 4)) + ⇒ (1 2 2 3 4 4) + (--splice 't (list it it) '(1 2 3 4)) + ⇒ (1 1 2 2 3 3 4 4) + (--splice (equal it :magic) '((list of) (magical) (code)) '((foo) (bar) :magic (baz))) + ⇒ ((foo) (bar) (list of) (magical) (code) (baz)) + + -- Function: -splice-list (pred new-list list) + Splice NEW-LIST in place of elements matching PRED in LIST. + + See also: ‘-splice’ (*note -splice::), ‘-insert-at’ (*note + -insert-at::) + + (-splice-list 'keywordp '(a b c) '(1 :foo 2)) + ⇒ (1 a b c 2) + (-splice-list 'keywordp nil '(1 :foo 2)) + ⇒ (1 2) + (--splice-list (keywordp it) '(a b c) '(1 :foo 2)) + ⇒ (1 a b c 2) + + -- Function: -mapcat (fn list) + Return the concatenation of the result of mapping FN over LIST. + Thus function FN should return a list. + + (-mapcat 'list '(1 2 3)) + ⇒ (1 2 3) + (-mapcat (lambda (item) (list 0 item)) '(1 2 3)) + ⇒ (0 1 0 2 0 3) + (--mapcat (list 0 it) '(1 2 3)) + ⇒ (0 1 0 2 0 3) + + -- Function: -copy (list) + Create a shallow copy of LIST. + + (-copy '(1 2 3)) + ⇒ (1 2 3) + (let ((a '(1 2 3))) (eq a (-copy a))) + ⇒ nil + + +File: dash.info, Node: Sublist selection, Next: List to list, Prev: Maps, Up: Functions + +2.2 Sublist selection +===================== + +Functions returning a sublist of the original list. + + -- Function: -filter (pred list) + Return a new list of the items in LIST for which PRED returns + non-nil. + + Alias: ‘-select’. + + This function’s anaphoric counterpart is ‘--filter’. + + For similar operations, see also ‘-keep’ (*note -keep::) and + ‘-remove’ (*note -remove::). + + (-filter (lambda (num) (= 0 (% num 2))) '(1 2 3 4)) + ⇒ (2 4) + (-filter #'natnump '(-2 -1 0 1 2)) + ⇒ (0 1 2) + (--filter (= 0 (% it 2)) '(1 2 3 4)) + ⇒ (2 4) + + -- Function: -remove (pred list) + Return a new list of the items in LIST for which PRED returns nil. + + Alias: ‘-reject’. + + This function’s anaphoric counterpart is ‘--remove’. + + For similar operations, see also ‘-keep’ (*note -keep::) and + ‘-filter’ (*note -filter::). + + (-remove (lambda (num) (= 0 (% num 2))) '(1 2 3 4)) + ⇒ (1 3) + (-remove #'natnump '(-2 -1 0 1 2)) + ⇒ (-2 -1) + (--remove (= 0 (% it 2)) '(1 2 3 4)) + ⇒ (1 3) + + -- Function: -remove-first (pred list) + Remove the first item from LIST for which PRED returns non-nil. + This is a non-destructive operation, but only the front of LIST + leading up to the removed item is a copy; the rest is LIST’s + original tail. If no item is removed, then the result is a + complete copy. + + Alias: ‘-reject-first’. + + This function’s anaphoric counterpart is ‘--remove-first’. + + See also ‘-map-first’ (*note -map-first::), ‘-remove-item’ (*note + -remove-item::), and ‘-remove-last’ (*note -remove-last::). + + (-remove-first #'natnump '(-2 -1 0 1 2)) + ⇒ (-2 -1 1 2) + (-remove-first #'stringp '(1 2 "first" "second")) + ⇒ (1 2 "second") + (--remove-first (> it 3) '(1 2 3 4 5 6)) + ⇒ (1 2 3 5 6) + + -- Function: -remove-last (pred list) + Remove the last item from LIST for which PRED returns non-nil. The + result is a copy of LIST regardless of whether an element is + removed. + + Alias: ‘-reject-last’. + + This function’s anaphoric counterpart is ‘--remove-last’. + + See also ‘-map-last’ (*note -map-last::), ‘-remove-item’ (*note + -remove-item::), and ‘-remove-first’ (*note -remove-first::). + + (-remove-last #'natnump '(1 3 5 4 7 8 10 -11)) + ⇒ (1 3 5 4 7 8 -11) + (-remove-last #'stringp '(1 2 "last" "second")) + ⇒ (1 2 "last") + (--remove-last (> it 3) '(1 2 3 4 5 6 7 8 9 10)) + ⇒ (1 2 3 4 5 6 7 8 9) + + -- Function: -remove-item (item list) + Return a copy of LIST with all occurrences of ITEM removed. The + comparison is done with ‘equal’. + + (-remove-item 3 '(1 2 3 2 3 4 5 3)) + ⇒ (1 2 2 4 5) + (-remove-item 'foo '(foo bar baz foo)) + ⇒ (bar baz) + (-remove-item "bob" '("alice" "bob" "eve" "bob")) + ⇒ ("alice" "eve") + + -- Function: -non-nil (list) + Return a copy of LIST with all nil items removed. + + (-non-nil '(nil 1 nil 2 nil nil 3 4 nil 5 nil)) + ⇒ (1 2 3 4 5) + (-non-nil '((nil))) + ⇒ ((nil)) + (-non-nil ()) + ⇒ () + + -- Function: -slice (list from &optional to step) + Return copy of LIST, starting from index FROM to index TO. + + FROM or TO may be negative. These values are then interpreted + modulo the length of the list. + + If STEP is a number, only each STEPth item in the resulting section + is returned. Defaults to 1. + + (-slice '(1 2 3 4 5) 1) + ⇒ (2 3 4 5) + (-slice '(1 2 3 4 5) 0 3) + ⇒ (1 2 3) + (-slice '(1 2 3 4 5 6 7 8 9) 1 -1 2) + ⇒ (2 4 6 8) + + -- Function: -take (n list) + Return a copy of the first N items in LIST. Return a copy of LIST + if it contains N items or fewer. Return nil if N is zero or less. + + See also: ‘-take-last’ (*note -take-last::). + + (-take 3 '(1 2 3 4 5)) + ⇒ (1 2 3) + (-take 17 '(1 2 3 4 5)) + ⇒ (1 2 3 4 5) + (-take 0 '(1 2 3 4 5)) + ⇒ () + + -- Function: -take-last (n list) + Return a copy of the last N items of LIST in order. Return a copy + of LIST if it contains N items or fewer. Return nil if N is zero + or less. + + See also: ‘-take’ (*note -take::). + + (-take-last 3 '(1 2 3 4 5)) + ⇒ (3 4 5) + (-take-last 17 '(1 2 3 4 5)) + ⇒ (1 2 3 4 5) + (-take-last 1 '(1 2 3 4 5)) + ⇒ (5) + + -- Function: -drop (n list) + Return the tail (not a copy) of LIST without the first N items. + Return nil if LIST contains N items or fewer. Return LIST if N is + zero or less. + + For another variant, see also ‘-drop-last’ (*note -drop-last::). + + (-drop 3 '(1 2 3 4 5)) + ⇒ (4 5) + (-drop 17 '(1 2 3 4 5)) + ⇒ () + (-drop 0 '(1 2 3 4 5)) + ⇒ (1 2 3 4 5) + + -- Function: -drop-last (n list) + Return a copy of LIST without its last N items. Return a copy of + LIST if N is zero or less. Return nil if LIST contains N items or + fewer. + + See also: ‘-drop’ (*note -drop::). + + (-drop-last 3 '(1 2 3 4 5)) + ⇒ (1 2) + (-drop-last 17 '(1 2 3 4 5)) + ⇒ () + (-drop-last 0 '(1 2 3 4 5)) + ⇒ (1 2 3 4 5) + + -- Function: -take-while (pred list) + Take successive items from LIST for which PRED returns non-nil. + PRED is a function of one argument. Return a new list of the + successive elements from the start of LIST for which PRED returns + non-nil. + + This function’s anaphoric counterpart is ‘--take-while’. + + For another variant, see also ‘-drop-while’ (*note -drop-while::). + + (-take-while #'even? '(1 2 3 4)) + ⇒ () + (-take-while #'even? '(2 4 5 6)) + ⇒ (2 4) + (--take-while (< it 4) '(1 2 3 4 3 2 1)) + ⇒ (1 2 3) + + -- Function: -drop-while (pred list) + Drop successive items from LIST for which PRED returns non-nil. + PRED is a function of one argument. Return the tail (not a copy) + of LIST starting from its first element for which PRED returns nil. + + This function’s anaphoric counterpart is ‘--drop-while’. + + For another variant, see also ‘-take-while’ (*note -take-while::). + + (-drop-while #'even? '(1 2 3 4)) + ⇒ (1 2 3 4) + (-drop-while #'even? '(2 4 5 6)) + ⇒ (5 6) + (--drop-while (< it 4) '(1 2 3 4 3 2 1)) + ⇒ (4 3 2 1) + + -- Function: -select-by-indices (indices list) + Return a list whose elements are elements from LIST selected as + ‘(nth i list)‘ for all i from INDICES. + + (-select-by-indices '(4 10 2 3 6) '("v" "e" "l" "o" "c" "i" "r" "a" "p" "t" "o" "r")) + ⇒ ("c" "o" "l" "o" "r") + (-select-by-indices '(2 1 0) '("a" "b" "c")) + ⇒ ("c" "b" "a") + (-select-by-indices '(0 1 2 0 1 3 3 1) '("f" "a" "r" "l")) + ⇒ ("f" "a" "r" "f" "a" "l" "l" "a") + + -- Function: -select-columns (columns table) + Select COLUMNS from TABLE. + + TABLE is a list of lists where each element represents one row. It + is assumed each row has the same length. + + Each row is transformed such that only the specified COLUMNS are + selected. + + See also: ‘-select-column’ (*note -select-column::), + ‘-select-by-indices’ (*note -select-by-indices::) + + (-select-columns '(0 2) '((1 2 3) (a b c) (:a :b :c))) + ⇒ ((1 3) (a c) (:a :c)) + (-select-columns '(1) '((1 2 3) (a b c) (:a :b :c))) + ⇒ ((2) (b) (:b)) + (-select-columns nil '((1 2 3) (a b c) (:a :b :c))) + ⇒ (nil nil nil) + + -- Function: -select-column (column table) + Select COLUMN from TABLE. + + TABLE is a list of lists where each element represents one row. It + is assumed each row has the same length. + + The single selected column is returned as a list. + + See also: ‘-select-columns’ (*note -select-columns::), + ‘-select-by-indices’ (*note -select-by-indices::) + + (-select-column 1 '((1 2 3) (a b c) (:a :b :c))) + ⇒ (2 b :b) + + +File: dash.info, Node: List to list, Next: Reductions, Prev: Sublist selection, Up: Functions + +2.3 List to list +================ + +Functions returning a modified copy of the input list. + + -- Function: -keep (fn list) + Return a new list of the non-nil results of applying FN to each + item in LIST. Like ‘-filter’ (*note -filter::), but returns the + non-nil results of FN instead of the corresponding elements of + LIST. + + Its anaphoric counterpart is ‘--keep’. + + (-keep #'cdr '((1 2 3) (4 5) (6))) + ⇒ ((2 3) (5)) + (-keep (lambda (n) (and (> n 3) (* 10 n))) '(1 2 3 4 5 6)) + ⇒ (40 50 60) + (--keep (and (> it 3) (* 10 it)) '(1 2 3 4 5 6)) + ⇒ (40 50 60) + + -- Function: -concat (&rest lists) + Return a new list with the concatenation of the elements in the + supplied LISTS. + + (-concat '(1)) + ⇒ (1) + (-concat '(1) '(2)) + ⇒ (1 2) + (-concat '(1) '(2 3) '(4)) + ⇒ (1 2 3 4) + + -- Function: -flatten (l) + Take a nested list L and return its contents as a single, flat + list. + + Note that because ‘nil’ represents a list of zero elements (an + empty list), any mention of nil in L will disappear after + flattening. If you need to preserve nils, consider ‘-flatten-n’ + (*note -flatten-n::) or map them to some unique symbol and then map + them back. + + Conses of two atoms are considered "terminals", that is, they + aren’t flattened further. + + See also: ‘-flatten-n’ (*note -flatten-n::) + + (-flatten '((1))) + ⇒ (1) + (-flatten '((1 (2 3) (((4 (5))))))) + ⇒ (1 2 3 4 5) + (-flatten '(1 2 (3 . 4))) + ⇒ (1 2 (3 . 4)) + + -- Function: -flatten-n (num list) + Flatten NUM levels of a nested LIST. + + See also: ‘-flatten’ (*note -flatten::) + + (-flatten-n 1 '((1 2) ((3 4) ((5 6))))) + ⇒ (1 2 (3 4) ((5 6))) + (-flatten-n 2 '((1 2) ((3 4) ((5 6))))) + ⇒ (1 2 3 4 (5 6)) + (-flatten-n 3 '((1 2) ((3 4) ((5 6))))) + ⇒ (1 2 3 4 5 6) + + -- Function: -replace (old new list) + Replace all OLD items in LIST with NEW. + + Elements are compared using ‘equal’. + + See also: ‘-replace-at’ (*note -replace-at::) + + (-replace 1 "1" '(1 2 3 4 3 2 1)) + ⇒ ("1" 2 3 4 3 2 "1") + (-replace "foo" "bar" '("a" "nice" "foo" "sentence" "about" "foo")) + ⇒ ("a" "nice" "bar" "sentence" "about" "bar") + (-replace 1 2 nil) + ⇒ nil + + -- Function: -replace-first (old new list) + Replace the first occurrence of OLD with NEW in LIST. + + Elements are compared using ‘equal’. + + See also: ‘-map-first’ (*note -map-first::) + + (-replace-first 1 "1" '(1 2 3 4 3 2 1)) + ⇒ ("1" 2 3 4 3 2 1) + (-replace-first "foo" "bar" '("a" "nice" "foo" "sentence" "about" "foo")) + ⇒ ("a" "nice" "bar" "sentence" "about" "foo") + (-replace-first 1 2 nil) + ⇒ nil + + -- Function: -replace-last (old new list) + Replace the last occurrence of OLD with NEW in LIST. + + Elements are compared using ‘equal’. + + See also: ‘-map-last’ (*note -map-last::) + + (-replace-last 1 "1" '(1 2 3 4 3 2 1)) + ⇒ (1 2 3 4 3 2 "1") + (-replace-last "foo" "bar" '("a" "nice" "foo" "sentence" "about" "foo")) + ⇒ ("a" "nice" "foo" "sentence" "about" "bar") + (-replace-last 1 2 nil) + ⇒ nil + + -- Function: -insert-at (n x list) + Return a list with X inserted into LIST at position N. + + See also: ‘-splice’ (*note -splice::), ‘-splice-list’ (*note + -splice-list::) + + (-insert-at 1 'x '(a b c)) + ⇒ (a x b c) + (-insert-at 12 'x '(a b c)) + ⇒ (a b c x) + + -- Function: -replace-at (n x list) + Return a list with element at Nth position in LIST replaced with X. + + See also: ‘-replace’ (*note -replace::) + + (-replace-at 0 9 '(0 1 2 3 4 5)) + ⇒ (9 1 2 3 4 5) + (-replace-at 1 9 '(0 1 2 3 4 5)) + ⇒ (0 9 2 3 4 5) + (-replace-at 4 9 '(0 1 2 3 4 5)) + ⇒ (0 1 2 3 9 5) + + -- Function: -update-at (n func list) + Return a list with element at Nth position in LIST replaced with + ‘(func (nth n list))‘. + + See also: ‘-map-when’ (*note -map-when::) + + (-update-at 0 (lambda (x) (+ x 9)) '(0 1 2 3 4 5)) + ⇒ (9 1 2 3 4 5) + (-update-at 1 (lambda (x) (+ x 8)) '(0 1 2 3 4 5)) + ⇒ (0 9 2 3 4 5) + (--update-at 2 (length it) '("foo" "bar" "baz" "quux")) + ⇒ ("foo" "bar" 3 "quux") + + -- Function: -remove-at (n list) + Return a list with element at Nth position in LIST removed. + + See also: ‘-remove-at-indices’ (*note -remove-at-indices::), + ‘-remove’ (*note -remove::) + + (-remove-at 0 '("0" "1" "2" "3" "4" "5")) + ⇒ ("1" "2" "3" "4" "5") + (-remove-at 1 '("0" "1" "2" "3" "4" "5")) + ⇒ ("0" "2" "3" "4" "5") + (-remove-at 2 '("0" "1" "2" "3" "4" "5")) + ⇒ ("0" "1" "3" "4" "5") + + -- Function: -remove-at-indices (indices list) + Return a list whose elements are elements from LIST without + elements selected as ‘(nth i list)‘ for all i from INDICES. + + See also: ‘-remove-at’ (*note -remove-at::), ‘-remove’ (*note + -remove::) + + (-remove-at-indices '(0) '("0" "1" "2" "3" "4" "5")) + ⇒ ("1" "2" "3" "4" "5") + (-remove-at-indices '(0 2 4) '("0" "1" "2" "3" "4" "5")) + ⇒ ("1" "3" "5") + (-remove-at-indices '(0 5) '("0" "1" "2" "3" "4" "5")) + ⇒ ("1" "2" "3" "4") + + +File: dash.info, Node: Reductions, Next: Unfolding, Prev: List to list, Up: Functions + +2.4 Reductions +============== + +Functions reducing lists to a single value (which may also be a list). + + -- Function: -reduce-from (fn init list) + Reduce the function FN across LIST, starting with INIT. Return the + result of applying FN to INIT and the first element of LIST, then + applying FN to that result and the second element, etc. If LIST is + empty, return INIT without calling FN. + + This function’s anaphoric counterpart is ‘--reduce-from’. + + For other folds, see also ‘-reduce’ (*note -reduce::) and + ‘-reduce-r’ (*note -reduce-r::). + + (-reduce-from #'- 10 '(1 2 3)) + ⇒ 4 + (-reduce-from #'list 10 '(1 2 3)) + ⇒ (((10 1) 2) 3) + (--reduce-from (concat acc " " it) "START" '("a" "b" "c")) + ⇒ "START a b c" + + -- Function: -reduce-r-from (fn init list) + Reduce the function FN across LIST in reverse, starting with INIT. + Return the result of applying FN to the last element of LIST and + INIT, then applying FN to the second-to-last element and the + previous result of FN, etc. That is, the first argument of FN is + the current element, and its second argument the accumulated value. + If LIST is empty, return INIT without calling FN. + + This function is like ‘-reduce-from’ (*note -reduce-from::) but the + operation associates from the right rather than left. In other + words, it starts from the end of LIST and flips the arguments to + FN. Conceptually, it is like replacing the conses in LIST with + applications of FN, and its last link with INIT, and evaluating the + resulting expression. + + This function’s anaphoric counterpart is ‘--reduce-r-from’. + + For other folds, see also ‘-reduce-r’ (*note -reduce-r::) and + ‘-reduce’ (*note -reduce::). + + (-reduce-r-from #'- 10 '(1 2 3)) + ⇒ -8 + (-reduce-r-from #'list 10 '(1 2 3)) + ⇒ (1 (2 (3 10))) + (--reduce-r-from (concat it " " acc) "END" '("a" "b" "c")) + ⇒ "a b c END" + + -- Function: -reduce (fn list) + Reduce the function FN across LIST. Return the result of applying + FN to the first two elements of LIST, then applying FN to that + result and the third element, etc. If LIST contains a single + element, return it without calling FN. If LIST is empty, return + the result of calling FN with no arguments. + + This function’s anaphoric counterpart is ‘--reduce’. + + For other folds, see also ‘-reduce-from’ (*note -reduce-from::) and + ‘-reduce-r’ (*note -reduce-r::). + + (-reduce #'- '(1 2 3 4)) + ⇒ -8 + (-reduce #'list '(1 2 3 4)) + ⇒ (((1 2) 3) 4) + (--reduce (format "%s-%d" acc it) '(1 2 3)) + ⇒ "1-2-3" + + -- Function: -reduce-r (fn list) + Reduce the function FN across LIST in reverse. Return the result + of applying FN to the last two elements of LIST, then applying FN + to the third-to-last element and the previous result of FN, etc. + That is, the first argument of FN is the current element, and its + second argument the accumulated value. If LIST contains a single + element, return it without calling FN. If LIST is empty, return + the result of calling FN with no arguments. + + This function is like ‘-reduce’ (*note -reduce::) but the operation + associates from the right rather than left. In other words, it + starts from the end of LIST and flips the arguments to FN. + Conceptually, it is like replacing the conses in LIST with + applications of FN, ignoring its last link, and evaluating the + resulting expression. + + This function’s anaphoric counterpart is ‘--reduce-r’. + + For other folds, see also ‘-reduce-r-from’ (*note -reduce-r-from::) + and ‘-reduce’ (*note -reduce::). + + (-reduce-r #'- '(1 2 3 4)) + ⇒ -2 + (-reduce-r #'list '(1 2 3 4)) + ⇒ (1 (2 (3 4))) + (--reduce-r (format "%s-%d" acc it) '(1 2 3)) + ⇒ "3-2-1" + + -- Function: -reductions-from (fn init list) + Return a list of FN’s intermediate reductions across LIST. That + is, a list of the intermediate values of the accumulator when + ‘-reduce-from’ (*note -reduce-from::) (which see) is called with + the same arguments. + + This function’s anaphoric counterpart is ‘--reductions-from’. + + For other folds, see also ‘-reductions’ (*note -reductions::) and + ‘-reductions-r’ (*note -reductions-r::). + + (-reductions-from #'max 0 '(2 1 4 3)) + ⇒ (0 2 2 4 4) + (-reductions-from #'* 1 '(1 2 3 4)) + ⇒ (1 1 2 6 24) + (--reductions-from (format "(FN %s %d)" acc it) "INIT" '(1 2 3)) + ⇒ ("INIT" "(FN INIT 1)" "(FN (FN INIT 1) 2)" "(FN (FN (FN INIT 1) 2) 3)") + + -- Function: -reductions-r-from (fn init list) + Return a list of FN’s intermediate reductions across reversed LIST. + That is, a list of the intermediate values of the accumulator when + ‘-reduce-r-from’ (*note -reduce-r-from::) (which see) is called + with the same arguments. + + This function’s anaphoric counterpart is ‘--reductions-r-from’. + + For other folds, see also ‘-reductions’ (*note -reductions::) and + ‘-reductions-r’ (*note -reductions-r::). + + (-reductions-r-from #'max 0 '(2 1 4 3)) + ⇒ (4 4 4 3 0) + (-reductions-r-from #'* 1 '(1 2 3 4)) + ⇒ (24 24 12 4 1) + (--reductions-r-from (format "(FN %d %s)" it acc) "INIT" '(1 2 3)) + ⇒ ("(FN 1 (FN 2 (FN 3 INIT)))" "(FN 2 (FN 3 INIT))" "(FN 3 INIT)" "INIT") + + -- Function: -reductions (fn list) + Return a list of FN’s intermediate reductions across LIST. That + is, a list of the intermediate values of the accumulator when + ‘-reduce’ (*note -reduce::) (which see) is called with the same + arguments. + + This function’s anaphoric counterpart is ‘--reductions’. + + For other folds, see also ‘-reductions’ (*note -reductions::) and + ‘-reductions-r’ (*note -reductions-r::). + + (-reductions #'+ '(1 2 3 4)) + ⇒ (1 3 6 10) + (-reductions #'* '(1 2 3 4)) + ⇒ (1 2 6 24) + (--reductions (format "(FN %s %d)" acc it) '(1 2 3)) + ⇒ (1 "(FN 1 2)" "(FN (FN 1 2) 3)") + + -- Function: -reductions-r (fn list) + Return a list of FN’s intermediate reductions across reversed LIST. + That is, a list of the intermediate values of the accumulator when + ‘-reduce-r’ (*note -reduce-r::) (which see) is called with the same + arguments. + + This function’s anaphoric counterpart is ‘--reductions-r’. + + For other folds, see also ‘-reductions-r-from’ (*note + -reductions-r-from::) and ‘-reductions’ (*note -reductions::). + + (-reductions-r #'+ '(1 2 3 4)) + ⇒ (10 9 7 4) + (-reductions-r #'* '(1 2 3 4)) + ⇒ (24 24 12 4) + (--reductions-r (format "(FN %d %s)" it acc) '(1 2 3)) + ⇒ ("(FN 1 (FN 2 3))" "(FN 2 3)" 3) + + -- Function: -count (pred list) + Counts the number of items in LIST where (PRED item) is non-nil. + + (-count 'even? '(1 2 3 4 5)) + ⇒ 2 + (--count (< it 4) '(1 2 3 4)) + ⇒ 3 + + -- Function: -sum (list) + Return the sum of LIST. + + (-sum ()) + ⇒ 0 + (-sum '(1)) + ⇒ 1 + (-sum '(1 2 3 4)) + ⇒ 10 + + -- Function: -running-sum (list) + Return a list with running sums of items in LIST. LIST must be + non-empty. + + (-running-sum '(1 2 3 4)) + ⇒ (1 3 6 10) + (-running-sum '(1)) + ⇒ (1) + (-running-sum ()) + error→ Wrong type argument: consp, nil + + -- Function: -product (list) + Return the product of LIST. + + (-product ()) + ⇒ 1 + (-product '(1)) + ⇒ 1 + (-product '(1 2 3 4)) + ⇒ 24 + + -- Function: -running-product (list) + Return a list with running products of items in LIST. LIST must be + non-empty. + + (-running-product '(1 2 3 4)) + ⇒ (1 2 6 24) + (-running-product '(1)) + ⇒ (1) + (-running-product ()) + error→ Wrong type argument: consp, nil + + -- Function: -inits (list) + Return all prefixes of LIST. + + (-inits '(1 2 3 4)) + ⇒ (nil (1) (1 2) (1 2 3) (1 2 3 4)) + (-inits nil) + ⇒ (nil) + (-inits '(1)) + ⇒ (nil (1)) + + -- Function: -tails (list) + Return all suffixes of LIST + + (-tails '(1 2 3 4)) + ⇒ ((1 2 3 4) (2 3 4) (3 4) (4) nil) + (-tails nil) + ⇒ (nil) + (-tails '(1)) + ⇒ ((1) nil) + + -- Function: -common-prefix (&rest lists) + Return the longest common prefix of LISTS. + + (-common-prefix '(1)) + ⇒ (1) + (-common-prefix '(1 2) '(3 4) '(1 2)) + ⇒ () + (-common-prefix '(1 2) '(1 2 3) '(1 2 3 4)) + ⇒ (1 2) + + -- Function: -common-suffix (&rest lists) + Return the longest common suffix of LISTS. + + (-common-suffix '(1)) + ⇒ (1) + (-common-suffix '(1 2) '(3 4) '(1 2)) + ⇒ () + (-common-suffix '(1 2 3 4) '(2 3 4) '(3 4)) + ⇒ (3 4) + + -- Function: -min (list) + Return the smallest value from LIST of numbers or markers. + + (-min '(0)) + ⇒ 0 + (-min '(3 2 1)) + ⇒ 1 + (-min '(1 2 3)) + ⇒ 1 + + -- Function: -min-by (comparator list) + Take a comparison function COMPARATOR and a LIST and return the + least element of the list by the comparison function. + + See also combinator ‘-on’ (*note -on::) which can transform the + values before comparing them. + + (-min-by '> '(4 3 6 1)) + ⇒ 1 + (--min-by (> (car it) (car other)) '((1 2 3) (2) (3 2))) + ⇒ (1 2 3) + (--min-by (> (length it) (length other)) '((1 2 3) (2) (3 2))) + ⇒ (2) + + -- Function: -max (list) + Return the largest value from LIST of numbers or markers. + + (-max '(0)) + ⇒ 0 + (-max '(3 2 1)) + ⇒ 3 + (-max '(1 2 3)) + ⇒ 3 + + -- Function: -max-by (comparator list) + Take a comparison function COMPARATOR and a LIST and return the + greatest element of the list by the comparison function. + + See also combinator ‘-on’ (*note -on::) which can transform the + values before comparing them. + + (-max-by '> '(4 3 6 1)) + ⇒ 6 + (--max-by (> (car it) (car other)) '((1 2 3) (2) (3 2))) + ⇒ (3 2) + (--max-by (> (length it) (length other)) '((1 2 3) (2) (3 2))) + ⇒ (1 2 3) + + +File: dash.info, Node: Unfolding, Next: Predicates, Prev: Reductions, Up: Functions + +2.5 Unfolding +============= + +Operations dual to reductions, building lists from a seed value rather +than consuming a list to produce a single value. + + -- Function: -iterate (fun init n) + Return a list of iterated applications of FUN to INIT. + + This means a list of the form: + + (INIT (FUN INIT) (FUN (FUN INIT)) ...) + + N is the length of the returned list. + + (-iterate #'1+ 1 10) + ⇒ (1 2 3 4 5 6 7 8 9 10) + (-iterate (lambda (x) (+ x x)) 2 5) + ⇒ (2 4 8 16 32) + (--iterate (* it it) 2 5) + ⇒ (2 4 16 256 65536) + + -- Function: -unfold (fun seed) + Build a list from SEED using FUN. + + This is "dual" operation to ‘-reduce-r’ (*note -reduce-r::): while + -reduce-r consumes a list to produce a single value, ‘-unfold’ + (*note -unfold::) takes a seed value and builds a (potentially + infinite!) list. + + FUN should return ‘nil’ to stop the generating process, or a cons + (A . B), where A will be prepended to the result and B is the new + seed. + + (-unfold (lambda (x) (unless (= x 0) (cons x (1- x)))) 10) + ⇒ (10 9 8 7 6 5 4 3 2 1) + (--unfold (when it (cons it (cdr it))) '(1 2 3 4)) + ⇒ ((1 2 3 4) (2 3 4) (3 4) (4)) + (--unfold (when it (cons it (butlast it))) '(1 2 3 4)) + ⇒ ((1 2 3 4) (1 2 3) (1 2) (1)) + + +File: dash.info, Node: Predicates, Next: Partitioning, Prev: Unfolding, Up: Functions + +2.6 Predicates +============== + +Reductions of one or more lists to a boolean value. + + -- Function: -some (pred list) + Return (PRED x) for the first LIST item where (PRED x) is non-nil, + else nil. + + Alias: ‘-any’. + + This function’s anaphoric counterpart is ‘--some’. + + (-some #'stringp '(1 "2" 3)) + ⇒ t + (--some (string-match-p "x" it) '("foo" "axe" "xor")) + ⇒ 1 + (--some (= it-index 3) '(0 1 2)) + ⇒ nil + + -- Function: -every (pred list) + Return non-nil if PRED returns non-nil for all items in LIST. If + so, return the last such result of PRED. Otherwise, once an item + is reached for which PRED returns nil, return nil without calling + PRED on any further LIST elements. + + This function is like ‘-every-p’, but on success returns the last + non-nil result of PRED instead of just t. + + This function’s anaphoric counterpart is ‘--every’. + + (-every #'numberp '(1 2 3)) + ⇒ t + (--every (string-match-p "x" it) '("axe" "xor")) + ⇒ 0 + (--every (= it it-index) '(0 1 3)) + ⇒ nil + + -- Function: -any? (pred list) + Return t if (PRED x) is non-nil for any x in LIST, else nil. + + Alias: ‘-any-p’, ‘-some?’, ‘-some-p’ + + (-any? #'numberp '(nil 0 t)) + ⇒ t + (-any? #'numberp '(nil t t)) + ⇒ nil + (-any? #'null '(1 3 5)) + ⇒ nil + + -- Function: -all? (pred list) + Return t if (PRED X) is non-nil for all X in LIST, else nil. In + the latter case, stop after the first X for which (PRED X) is nil, + without calling PRED on any subsequent elements of LIST. + + The similar function ‘-every’ (*note -every::) is more widely + useful, since it returns the last non-nil result of PRED instead of + just t on success. + + Alias: ‘-all-p’, ‘-every-p’, ‘-every?’. + + This function’s anaphoric counterpart is ‘--all?’. + + (-all? #'numberp '(1 2 3)) + ⇒ t + (-all? #'numberp '(2 t 6)) + ⇒ nil + (--all? (= 0 (% it 2)) '(2 4 6)) + ⇒ t + + -- Function: -none? (pred list) + Return t if (PRED x) is nil for all x in LIST, else nil. + + Alias: ‘-none-p’ + + (-none? 'even? '(1 2 3)) + ⇒ nil + (-none? 'even? '(1 3 5)) + ⇒ t + (--none? (= 0 (% it 2)) '(1 2 3)) + ⇒ nil + + -- Function: -only-some? (pred list) + Return ‘t‘ if at least one item of LIST matches PRED and at least + one item of LIST does not match PRED. Return ‘nil‘ both if all + items match the predicate or if none of the items match the + predicate. + + Alias: ‘-only-some-p’ + + (-only-some? 'even? '(1 2 3)) + ⇒ t + (-only-some? 'even? '(1 3 5)) + ⇒ nil + (-only-some? 'even? '(2 4 6)) + ⇒ nil + + -- Function: -contains? (list element) + Return non-nil if LIST contains ELEMENT. + + The test for equality is done with ‘equal’, or with ‘-compare-fn’ + if that’s non-nil. + + Alias: ‘-contains-p’ + + (-contains? '(1 2 3) 1) + ⇒ t + (-contains? '(1 2 3) 2) + ⇒ t + (-contains? '(1 2 3) 4) + ⇒ nil + + -- Function: -same-items? (list list2) + Return true if LIST and LIST2 has the same items. + + The order of the elements in the lists does not matter. + + Alias: ‘-same-items-p’ + + (-same-items? '(1 2 3) '(1 2 3)) + ⇒ t + (-same-items? '(1 2 3) '(3 2 1)) + ⇒ t + (-same-items? '(1 2 3) '(1 2 3 4)) + ⇒ nil + + -- Function: -is-prefix? (prefix list) + Return non-nil if PREFIX is a prefix of LIST. + + Alias: ‘-is-prefix-p’. + + (-is-prefix? '(1 2 3) '(1 2 3 4 5)) + ⇒ t + (-is-prefix? '(1 2 3 4 5) '(1 2 3)) + ⇒ nil + (-is-prefix? '(1 3) '(1 2 3 4 5)) + ⇒ nil + + -- Function: -is-suffix? (suffix list) + Return non-nil if SUFFIX is a suffix of LIST. + + Alias: ‘-is-suffix-p’. + + (-is-suffix? '(3 4 5) '(1 2 3 4 5)) + ⇒ t + (-is-suffix? '(1 2 3 4 5) '(3 4 5)) + ⇒ nil + (-is-suffix? '(3 5) '(1 2 3 4 5)) + ⇒ nil + + -- Function: -is-infix? (infix list) + Return non-nil if INFIX is infix of LIST. + + This operation runs in O(n^2) time + + Alias: ‘-is-infix-p’ + + (-is-infix? '(1 2 3) '(1 2 3 4 5)) + ⇒ t + (-is-infix? '(2 3 4) '(1 2 3 4 5)) + ⇒ t + (-is-infix? '(3 4 5) '(1 2 3 4 5)) + ⇒ t + + -- Function: -cons-pair? (obj) + Return non-nil if OBJ is a true cons pair. That is, a cons (A . + B) where B is not a list. + + Alias: ‘-cons-pair-p’. + + (-cons-pair? '(1 . 2)) + ⇒ t + (-cons-pair? '(1 2)) + ⇒ nil + (-cons-pair? '(1)) + ⇒ nil + + +File: dash.info, Node: Partitioning, Next: Indexing, Prev: Predicates, Up: Functions + +2.7 Partitioning +================ + +Functions partitioning the input list into a list of lists. + + -- Function: -split-at (n list) + Split LIST into two sublists after the Nth element. The result is + a list of two elements (TAKE DROP) where TAKE is a new list of the + first N elements of LIST, and DROP is the remaining elements of + LIST (not a copy). TAKE and DROP are like the results of ‘-take’ + (*note -take::) and ‘-drop’ (*note -drop::), respectively, but the + split is done in a single list traversal. + + (-split-at 3 '(1 2 3 4 5)) + ⇒ ((1 2 3) (4 5)) + (-split-at 17 '(1 2 3 4 5)) + ⇒ ((1 2 3 4 5) nil) + (-split-at 0 '(1 2 3 4 5)) + ⇒ (nil (1 2 3 4 5)) + + -- Function: -split-with (pred list) + Return a list of ((-take-while PRED LIST) (-drop-while PRED LIST)), + in no more than one pass through the list. + + (-split-with 'even? '(1 2 3 4)) + ⇒ (nil (1 2 3 4)) + (-split-with 'even? '(2 4 5 6)) + ⇒ ((2 4) (5 6)) + (--split-with (< it 4) '(1 2 3 4 3 2 1)) + ⇒ ((1 2 3) (4 3 2 1)) + + -- Macro: -split-on (item list) + Split the LIST each time ITEM is found. + + Unlike ‘-partition-by’ (*note -partition-by::), the ITEM is + discarded from the results. Empty lists are also removed from the + result. + + Comparison is done by ‘equal’. + + See also ‘-split-when’ (*note -split-when::) + + (-split-on '| '(Nil | Leaf a | Node [Tree a])) + ⇒ ((Nil) (Leaf a) (Node [Tree a])) + (-split-on :endgroup '("a" "b" :endgroup "c" :endgroup "d" "e")) + ⇒ (("a" "b") ("c") ("d" "e")) + (-split-on :endgroup '("a" "b" :endgroup :endgroup "d" "e")) + ⇒ (("a" "b") ("d" "e")) + + -- Function: -split-when (fn list) + Split the LIST on each element where FN returns non-nil. + + Unlike ‘-partition-by’ (*note -partition-by::), the "matched" + element is discarded from the results. Empty lists are also + removed from the result. + + This function can be thought of as a generalization of + ‘split-string’. + + (-split-when 'even? '(1 2 3 4 5 6)) + ⇒ ((1) (3) (5)) + (-split-when 'even? '(1 2 3 4 6 8 9)) + ⇒ ((1) (3) (9)) + (--split-when (memq it '(&optional &rest)) '(a b &optional c d &rest args)) + ⇒ ((a b) (c d) (args)) + + -- Function: -separate (pred list) + Return a list of ((-filter PRED LIST) (-remove PRED LIST)), in one + pass through the list. + + (-separate (lambda (num) (= 0 (% num 2))) '(1 2 3 4 5 6 7)) + ⇒ ((2 4 6) (1 3 5 7)) + (--separate (< it 5) '(3 7 5 9 3 2 1 4 6)) + ⇒ ((3 3 2 1 4) (7 5 9 6)) + (-separate 'cdr '((1 2) (1) (1 2 3) (4))) + ⇒ (((1 2) (1 2 3)) ((1) (4))) + + -- Function: -partition (n list) + Return a new list with the items in LIST grouped into N-sized + sublists. If there are not enough items to make the last group + N-sized, those items are discarded. + + (-partition 2 '(1 2 3 4 5 6)) + ⇒ ((1 2) (3 4) (5 6)) + (-partition 2 '(1 2 3 4 5 6 7)) + ⇒ ((1 2) (3 4) (5 6)) + (-partition 3 '(1 2 3 4 5 6 7)) + ⇒ ((1 2 3) (4 5 6)) + + -- Function: -partition-all (n list) + Return a new list with the items in LIST grouped into N-sized + sublists. The last group may contain less than N items. + + (-partition-all 2 '(1 2 3 4 5 6)) + ⇒ ((1 2) (3 4) (5 6)) + (-partition-all 2 '(1 2 3 4 5 6 7)) + ⇒ ((1 2) (3 4) (5 6) (7)) + (-partition-all 3 '(1 2 3 4 5 6 7)) + ⇒ ((1 2 3) (4 5 6) (7)) + + -- Function: -partition-in-steps (n step list) + Return a new list with the items in LIST grouped into N-sized + sublists at offsets STEP apart. If there are not enough items to + make the last group N-sized, those items are discarded. + + (-partition-in-steps 2 1 '(1 2 3 4)) + ⇒ ((1 2) (2 3) (3 4)) + (-partition-in-steps 3 2 '(1 2 3 4)) + ⇒ ((1 2 3)) + (-partition-in-steps 3 2 '(1 2 3 4 5)) + ⇒ ((1 2 3) (3 4 5)) + + -- Function: -partition-all-in-steps (n step list) + Return a new list with the items in LIST grouped into N-sized + sublists at offsets STEP apart. The last groups may contain less + than N items. + + (-partition-all-in-steps 2 1 '(1 2 3 4)) + ⇒ ((1 2) (2 3) (3 4) (4)) + (-partition-all-in-steps 3 2 '(1 2 3 4)) + ⇒ ((1 2 3) (3 4)) + (-partition-all-in-steps 3 2 '(1 2 3 4 5)) + ⇒ ((1 2 3) (3 4 5) (5)) + + -- Function: -partition-by (fn list) + Apply FN to each item in LIST, splitting it each time FN returns a + new value. + + (-partition-by 'even? ()) + ⇒ () + (-partition-by 'even? '(1 1 2 2 2 3 4 6 8)) + ⇒ ((1 1) (2 2 2) (3) (4 6 8)) + (--partition-by (< it 3) '(1 2 3 4 3 2 1)) + ⇒ ((1 2) (3 4 3) (2 1)) + + -- Function: -partition-by-header (fn list) + Apply FN to the first item in LIST. That is the header value. + Apply FN to each item in LIST, splitting it each time FN returns + the header value, but only after seeing at least one other value + (the body). + + (--partition-by-header (= it 1) '(1 2 3 1 2 1 2 3 4)) + ⇒ ((1 2 3) (1 2) (1 2 3 4)) + (--partition-by-header (> it 0) '(1 2 0 1 0 1 2 3 0)) + ⇒ ((1 2 0) (1 0) (1 2 3 0)) + (-partition-by-header 'even? '(2 1 1 1 4 1 3 5 6 6 1)) + ⇒ ((2 1 1 1) (4 1 3 5) (6 6 1)) + + -- Function: -partition-after-pred (pred list) + Partition LIST after each element for which PRED returns non-nil. + + This function’s anaphoric counterpart is ‘--partition-after-pred’. + + (-partition-after-pred #'booleanp ()) + ⇒ () + (-partition-after-pred #'booleanp '(t t)) + ⇒ ((t) (t)) + (-partition-after-pred #'booleanp '(0 0 t t 0 t)) + ⇒ ((0 0 t) (t) (0 t)) + + -- Function: -partition-before-pred (pred list) + Partition directly before each time PRED is true on an element of + LIST. + + (-partition-before-pred #'booleanp ()) + ⇒ () + (-partition-before-pred #'booleanp '(0 t)) + ⇒ ((0) (t)) + (-partition-before-pred #'booleanp '(0 0 t 0 t t)) + ⇒ ((0 0) (t 0) (t) (t)) + + -- Function: -partition-before-item (item list) + Partition directly before each time ITEM appears in LIST. + + (-partition-before-item 3 ()) + ⇒ () + (-partition-before-item 3 '(1)) + ⇒ ((1)) + (-partition-before-item 3 '(3)) + ⇒ ((3)) + + -- Function: -partition-after-item (item list) + Partition directly after each time ITEM appears in LIST. + + (-partition-after-item 3 ()) + ⇒ () + (-partition-after-item 3 '(1)) + ⇒ ((1)) + (-partition-after-item 3 '(3)) + ⇒ ((3)) + + -- Function: -group-by (fn list) + Separate LIST into an alist whose keys are FN applied to the + elements of LIST. Keys are compared by ‘equal’. + + (-group-by 'even? ()) + ⇒ () + (-group-by 'even? '(1 1 2 2 2 3 4 6 8)) + ⇒ ((nil 1 1 3) (t 2 2 2 4 6 8)) + (--group-by (car (split-string it "/")) '("a/b" "c/d" "a/e")) + ⇒ (("a" "a/b" "a/e") ("c" "c/d")) + + +File: dash.info, Node: Indexing, Next: Set operations, Prev: Partitioning, Up: Functions + +2.8 Indexing +============ + +Functions retrieving or sorting based on list indices and related +predicates. + + -- Function: -elem-index (elem list) + Return the index of the first element in the given LIST which is + equal to the query element ELEM, or nil if there is no such + element. + + (-elem-index 2 '(6 7 8 2 3 4)) + ⇒ 3 + (-elem-index "bar" '("foo" "bar" "baz")) + ⇒ 1 + (-elem-index '(1 2) '((3) (5 6) (1 2) nil)) + ⇒ 2 + + -- Function: -elem-indices (elem list) + Return the indices of all elements in LIST equal to the query + element ELEM, in ascending order. + + (-elem-indices 2 '(6 7 8 2 3 4 2 1)) + ⇒ (3 6) + (-elem-indices "bar" '("foo" "bar" "baz")) + ⇒ (1) + (-elem-indices '(1 2) '((3) (1 2) (5 6) (1 2) nil)) + ⇒ (1 3) + + -- Function: -find-index (pred list) + Take a predicate PRED and a LIST and return the index of the first + element in the list satisfying the predicate, or nil if there is no + such element. + + See also ‘-first’ (*note -first::). + + (-find-index 'even? '(2 4 1 6 3 3 5 8)) + ⇒ 0 + (--find-index (< 5 it) '(2 4 1 6 3 3 5 8)) + ⇒ 3 + (-find-index (-partial 'string-lessp "baz") '("bar" "foo" "baz")) + ⇒ 1 + + -- Function: -find-last-index (pred list) + Take a predicate PRED and a LIST and return the index of the last + element in the list satisfying the predicate, or nil if there is no + such element. + + See also ‘-last’ (*note -last::). + + (-find-last-index 'even? '(2 4 1 6 3 3 5 8)) + ⇒ 7 + (--find-last-index (< 5 it) '(2 7 1 6 3 8 5 2)) + ⇒ 5 + (-find-last-index (-partial 'string-lessp "baz") '("q" "foo" "baz")) + ⇒ 1 + + -- Function: -find-indices (pred list) + Return the indices of all elements in LIST satisfying the predicate + PRED, in ascending order. + + (-find-indices 'even? '(2 4 1 6 3 3 5 8)) + ⇒ (0 1 3 7) + (--find-indices (< 5 it) '(2 4 1 6 3 3 5 8)) + ⇒ (3 7) + (-find-indices (-partial 'string-lessp "baz") '("bar" "foo" "baz")) + ⇒ (1) + + -- Function: -grade-up (comparator list) + Grade elements of LIST using COMPARATOR relation. This yields a + permutation vector such that applying this permutation to LIST + sorts it in ascending order. + + (-grade-up #'< '(3 1 4 2 1 3 3)) + ⇒ (1 4 3 0 5 6 2) + (let ((l '(3 1 4 2 1 3 3))) (-select-by-indices (-grade-up #'< l) l)) + ⇒ (1 1 2 3 3 3 4) + + -- Function: -grade-down (comparator list) + Grade elements of LIST using COMPARATOR relation. This yields a + permutation vector such that applying this permutation to LIST + sorts it in descending order. + + (-grade-down #'< '(3 1 4 2 1 3 3)) + ⇒ (2 0 5 6 3 1 4) + (let ((l '(3 1 4 2 1 3 3))) (-select-by-indices (-grade-down #'< l) l)) + ⇒ (4 3 3 3 2 1 1) + + +File: dash.info, Node: Set operations, Next: Other list operations, Prev: Indexing, Up: Functions + +2.9 Set operations +================== + +Operations pretending lists are sets. + + -- Function: -union (list list2) + Return a new list containing the elements of LIST and elements of + LIST2 that are not in LIST. The test for equality is done with + ‘equal’, or with ‘-compare-fn’ if that’s non-nil. + + (-union '(1 2 3) '(3 4 5)) + ⇒ (1 2 3 4 5) + (-union '(1 2 3 4) ()) + ⇒ (1 2 3 4) + (-union '(1 1 2 2) '(3 2 1)) + ⇒ (1 1 2 2 3) + + -- Function: -difference (list list2) + Return a new list with only the members of LIST that are not in + LIST2. The test for equality is done with ‘equal’, or with + ‘-compare-fn’ if that’s non-nil. + + (-difference () ()) + ⇒ () + (-difference '(1 2 3) '(4 5 6)) + ⇒ (1 2 3) + (-difference '(1 2 3 4) '(3 4 5 6)) + ⇒ (1 2) + + -- Function: -intersection (list list2) + Return a new list containing only the elements that are members of + both LIST and LIST2. The test for equality is done with ‘equal’, + or with ‘-compare-fn’ if that’s non-nil. + + (-intersection () ()) + ⇒ () + (-intersection '(1 2 3) '(4 5 6)) + ⇒ () + (-intersection '(1 2 3 4) '(3 4 5 6)) + ⇒ (3 4) + + -- Function: -powerset (list) + Return the power set of LIST. + + (-powerset ()) + ⇒ (nil) + (-powerset '(x y z)) + ⇒ ((x y z) (x y) (x z) (x) (y z) (y) (z) nil) + + -- Function: -permutations (list) + Return the permutations of LIST. + + (-permutations ()) + ⇒ (nil) + (-permutations '(1 2)) + ⇒ ((1 2) (2 1)) + (-permutations '(a b c)) + ⇒ ((a b c) (a c b) (b a c) (b c a) (c a b) (c b a)) + + -- Function: -distinct (list) + Return a new list with all duplicates removed. The test for + equality is done with ‘equal’, or with ‘-compare-fn’ if that’s + non-nil. + + Alias: ‘-uniq’ + + (-distinct ()) + ⇒ () + (-distinct '(1 2 2 4)) + ⇒ (1 2 4) + (-distinct '(t t t)) + ⇒ (t) + + +File: dash.info, Node: Other list operations, Next: Tree operations, Prev: Set operations, Up: Functions + +2.10 Other list operations +========================== + +Other list functions not fit to be classified elsewhere. + + -- Function: -rotate (n list) + Rotate LIST N places to the right (left if N is negative). The + time complexity is O(n). + + (-rotate 3 '(1 2 3 4 5 6 7)) + ⇒ (5 6 7 1 2 3 4) + (-rotate -3 '(1 2 3 4 5 6 7)) + ⇒ (4 5 6 7 1 2 3) + (-rotate 16 '(1 2 3 4 5 6 7)) + ⇒ (6 7 1 2 3 4 5) + + -- Function: -repeat (n x) + Return a new list of length N with each element being X. Return + nil if N is less than 1. + + (-repeat 3 :a) + ⇒ (:a :a :a) + (-repeat 1 :a) + ⇒ (:a) + (-repeat 0 :a) + ⇒ nil + + -- Function: -cons* (&rest args) + Make a new list from the elements of ARGS. The last 2 elements of + ARGS are used as the final cons of the result, so if the final + element of ARGS is not a list, the result is a dotted list. With + no ARGS, return nil. + + (-cons* 1 2) + ⇒ (1 . 2) + (-cons* 1 2 3) + ⇒ (1 2 . 3) + (-cons* 1) + ⇒ 1 + + -- Function: -snoc (list elem &rest elements) + Append ELEM to the end of the list. + + This is like ‘cons’, but operates on the end of list. + + If ELEMENTS is non nil, append these to the list as well. + + (-snoc '(1 2 3) 4) + ⇒ (1 2 3 4) + (-snoc '(1 2 3) 4 5 6) + ⇒ (1 2 3 4 5 6) + (-snoc '(1 2 3) '(4 5 6)) + ⇒ (1 2 3 (4 5 6)) + + -- Function: -interpose (sep list) + Return a new list of all elements in LIST separated by SEP. + + (-interpose "-" ()) + ⇒ () + (-interpose "-" '("a")) + ⇒ ("a") + (-interpose "-" '("a" "b" "c")) + ⇒ ("a" "-" "b" "-" "c") + + -- Function: -interleave (&rest lists) + Return a new list of the first item in each list, then the second + etc. + + (-interleave '(1 2) '("a" "b")) + ⇒ (1 "a" 2 "b") + (-interleave '(1 2) '("a" "b") '("A" "B")) + ⇒ (1 "a" "A" 2 "b" "B") + (-interleave '(1 2 3) '("a" "b")) + ⇒ (1 "a" 2 "b") + + -- Function: -iota (count &optional start step) + Return a list containing COUNT numbers. Starts from START and adds + STEP each time. The default START is zero, the default STEP is 1. + This function takes its name from the corresponding primitive in + the APL language. + + (-iota 6) + ⇒ (0 1 2 3 4 5) + (-iota 4 2.5 -2) + ⇒ (2.5 0.5 -1.5 -3.5) + (-iota -1) + error→ Wrong type argument: natnump, -1 + + -- Function: -zip-with (fn list1 list2) + Zip the two lists LIST1 and LIST2 using a function FN. This + function is applied pairwise taking as first argument element of + LIST1 and as second argument element of LIST2 at corresponding + position. + + The anaphoric form ‘--zip-with’ binds the elements from LIST1 as + symbol ‘it’, and the elements from LIST2 as symbol ‘other’. + + (-zip-with '+ '(1 2 3) '(4 5 6)) + ⇒ (5 7 9) + (-zip-with 'cons '(1 2 3) '(4 5 6)) + ⇒ ((1 . 4) (2 . 5) (3 . 6)) + (--zip-with (concat it " and " other) '("Batman" "Jekyll") '("Robin" "Hyde")) + ⇒ ("Batman and Robin" "Jekyll and Hyde") + + -- Function: -zip (&rest lists) + Zip LISTS together. Group the head of each list, followed by the + second elements of each list, and so on. The lengths of the + returned groupings are equal to the length of the shortest input + list. + + If two lists are provided as arguments, return the groupings as a + list of cons cells. Otherwise, return the groupings as a list of + lists. + + Use ‘-zip-lists’ (*note -zip-lists::) if you need the return value + to always be a list of lists. + + Alias: ‘-zip-pair’ + + See also: ‘-zip-lists’ (*note -zip-lists::) + + (-zip '(1 2 3) '(4 5 6)) + ⇒ ((1 . 4) (2 . 5) (3 . 6)) + (-zip '(1 2 3) '(4 5 6 7)) + ⇒ ((1 . 4) (2 . 5) (3 . 6)) + (-zip '(1 2) '(3 4 5) '(6)) + ⇒ ((1 3 6)) + + -- Function: -zip-lists (&rest lists) + Zip LISTS together. Group the head of each list, followed by the + second elements of each list, and so on. The lengths of the + returned groupings are equal to the length of the shortest input + list. + + The return value is always list of lists, which is a difference + from ‘-zip-pair’ which returns a cons-cell in case two input lists + are provided. + + See also: ‘-zip’ (*note -zip::) + + (-zip-lists '(1 2 3) '(4 5 6)) + ⇒ ((1 4) (2 5) (3 6)) + (-zip-lists '(1 2 3) '(4 5 6 7)) + ⇒ ((1 4) (2 5) (3 6)) + (-zip-lists '(1 2) '(3 4 5) '(6)) + ⇒ ((1 3 6)) + + -- Function: -zip-fill (fill-value &rest lists) + Zip LISTS, with FILL-VALUE padded onto the shorter lists. The + lengths of the returned groupings are equal to the length of the + longest input list. + + (-zip-fill 0 '(1 2 3 4 5) '(6 7 8 9)) + ⇒ ((1 . 6) (2 . 7) (3 . 8) (4 . 9) (5 . 0)) + + -- Function: -unzip (lists) + Unzip LISTS. + + This works just like ‘-zip’ (*note -zip::) but takes a list of + lists instead of a variable number of arguments, such that + + (-unzip (-zip L1 L2 L3 ...)) + + is identity (given that the lists are the same length). + + Note in particular that calling this on a list of two lists will + return a list of cons-cells such that the above identity works. + + See also: ‘-zip’ (*note -zip::) + + (-unzip (-zip '(1 2 3) '(a b c) '("e" "f" "g"))) + ⇒ ((1 2 3) (a b c) ("e" "f" "g")) + (-unzip '((1 2) (3 4) (5 6) (7 8) (9 10))) + ⇒ ((1 3 5 7 9) (2 4 6 8 10)) + (-unzip '((1 2) (3 4))) + ⇒ ((1 . 3) (2 . 4)) + + -- Function: -cycle (list) + Return an infinite circular copy of LIST. The returned list cycles + through the elements of LIST and repeats from the beginning. + + (-take 5 (-cycle '(1 2 3))) + ⇒ (1 2 3 1 2) + (-take 7 (-cycle '(1 "and" 3))) + ⇒ (1 "and" 3 1 "and" 3 1) + (-zip (-cycle '(1 2 3)) '(1 2)) + ⇒ ((1 . 1) (2 . 2)) + + -- Function: -pad (fill-value &rest lists) + Appends FILL-VALUE to the end of each list in LISTS such that they + will all have the same length. + + (-pad 0 ()) + ⇒ (nil) + (-pad 0 '(1)) + ⇒ ((1)) + (-pad 0 '(1 2 3) '(4 5)) + ⇒ ((1 2 3) (4 5 0)) + + -- Function: -table (fn &rest lists) + Compute outer product of LISTS using function FN. + + The function FN should have the same arity as the number of + supplied lists. + + The outer product is computed by applying fn to all possible + combinations created by taking one element from each list in order. + The dimension of the result is (length lists). + + See also: ‘-table-flat’ (*note -table-flat::) + + (-table '* '(1 2 3) '(1 2 3)) + ⇒ ((1 2 3) (2 4 6) (3 6 9)) + (-table (lambda (a b) (-sum (-zip-with '* a b))) '((1 2) (3 4)) '((1 3) (2 4))) + ⇒ ((7 15) (10 22)) + (apply '-table 'list (-repeat 3 '(1 2))) + ⇒ ((((1 1 1) (2 1 1)) ((1 2 1) (2 2 1))) (((1 1 2) (2 1 2)) ((1 2 2) (2 2 2)))) + + -- Function: -table-flat (fn &rest lists) + Compute flat outer product of LISTS using function FN. + + The function FN should have the same arity as the number of + supplied lists. + + The outer product is computed by applying fn to all possible + combinations created by taking one element from each list in order. + The results are flattened, ignoring the tensor structure of the + result. This is equivalent to calling: + + (-flatten-n (1- (length lists)) (apply ’-table fn lists)) + + but the implementation here is much more efficient. + + See also: ‘-flatten-n’ (*note -flatten-n::), ‘-table’ (*note + -table::) + + (-table-flat 'list '(1 2 3) '(a b c)) + ⇒ ((1 a) (2 a) (3 a) (1 b) (2 b) (3 b) (1 c) (2 c) (3 c)) + (-table-flat '* '(1 2 3) '(1 2 3)) + ⇒ (1 2 3 2 4 6 3 6 9) + (apply '-table-flat 'list (-repeat 3 '(1 2))) + ⇒ ((1 1 1) (2 1 1) (1 2 1) (2 2 1) (1 1 2) (2 1 2) (1 2 2) (2 2 2)) + + -- Function: -first (pred list) + Return the first item in LIST for which PRED returns non-nil. + Return nil if no such element is found. To get the first item in + the list no questions asked, use ‘car’. + + Alias: ‘-find’. + + This function’s anaphoric counterpart is ‘--first’. + + (-first #'natnump '(-1 0 1)) + ⇒ 0 + (-first #'null '(1 2 3)) + ⇒ nil + (--first (> it 2) '(1 2 3)) + ⇒ 3 + + -- Function: -last (pred list) + Return the last x in LIST where (PRED x) is non-nil, else nil. + + (-last 'even? '(1 2 3 4 5 6 3 3 3)) + ⇒ 6 + (-last 'even? '(1 3 7 5 9)) + ⇒ nil + (--last (> (length it) 3) '("a" "looong" "word" "and" "short" "one")) + ⇒ "short" + + -- Function: -first-item (list) + Return the first item of LIST, or nil on an empty list. + + See also: ‘-second-item’ (*note -second-item::), ‘-last-item’ + (*note -last-item::). + + (-first-item '(1 2 3)) + ⇒ 1 + (-first-item nil) + ⇒ nil + (let ((list (list 1 2 3))) (setf (-first-item list) 5) list) + ⇒ (5 2 3) + + -- Function: -second-item (list) + Return the second item of LIST, or nil if LIST is too short. + + See also: ‘-third-item’ (*note -third-item::). + + (-second-item '(1 2 3)) + ⇒ 2 + (-second-item nil) + ⇒ nil + + -- Function: -third-item (list) + Return the third item of LIST, or nil if LIST is too short. + + See also: ‘-fourth-item’ (*note -fourth-item::). + + (-third-item '(1 2 3)) + ⇒ 3 + (-third-item nil) + ⇒ nil + + -- Function: -fourth-item (list) + Return the fourth item of LIST, or nil if LIST is too short. + + See also: ‘-fifth-item’ (*note -fifth-item::). + + (-fourth-item '(1 2 3 4)) + ⇒ 4 + (-fourth-item nil) + ⇒ nil + + -- Function: -fifth-item (list) + Return the fifth item of LIST, or nil if LIST is too short. + + See also: ‘-last-item’ (*note -last-item::). + + (-fifth-item '(1 2 3 4 5)) + ⇒ 5 + (-fifth-item nil) + ⇒ nil + + -- Function: -last-item (list) + Return the last item of LIST, or nil on an empty list. + + (-last-item '(1 2 3)) + ⇒ 3 + (-last-item nil) + ⇒ nil + (let ((list (list 1 2 3))) (setf (-last-item list) 5) list) + ⇒ (1 2 5) + + -- Function: -butlast (list) + Return a list of all items in list except for the last. + + (-butlast '(1 2 3)) + ⇒ (1 2) + (-butlast '(1 2)) + ⇒ (1) + (-butlast '(1)) + ⇒ nil + + -- Function: -sort (comparator list) + Sort LIST, stably, comparing elements using COMPARATOR. Return the + sorted list. LIST is NOT modified by side effects. COMPARATOR is + called with two elements of LIST, and should return non-nil if the + first element should sort before the second. + + (-sort '< '(3 1 2)) + ⇒ (1 2 3) + (-sort '> '(3 1 2)) + ⇒ (3 2 1) + (--sort (< it other) '(3 1 2)) + ⇒ (1 2 3) + + -- Function: -list (arg) + Ensure ARG is a list. If ARG is already a list, return it as is + (not a copy). Otherwise, return a new list with ARG as its only + element. + + Another supported calling convention is (-list &rest ARGS). In + this case, if ARG is not a list, a new list with all of ARGS as + elements is returned. This use is supported for backward + compatibility and is otherwise deprecated. + + (-list 1) + ⇒ (1) + (-list ()) + ⇒ () + (-list '(1 2 3)) + ⇒ (1 2 3) + + -- Function: -fix (fn list) + Compute the (least) fixpoint of FN with initial input LIST. + + FN is called at least once, results are compared with ‘equal’. + + (-fix (lambda (l) (-non-nil (--mapcat (-split-at (/ (length it) 2) it) l))) '((1 2 3))) + ⇒ ((1) (2) (3)) + (let ((l '((starwars scifi) (jedi starwars warrior)))) (--fix (-uniq (--mapcat (cons it (cdr (assq it l))) it)) '(jedi book))) + ⇒ (jedi starwars warrior scifi book) + + +File: dash.info, Node: Tree operations, Next: Threading macros, Prev: Other list operations, Up: Functions + +2.11 Tree operations +==================== + +Functions pretending lists are trees. + + -- Function: -tree-seq (branch children tree) + Return a sequence of the nodes in TREE, in depth-first search + order. + + BRANCH is a predicate of one argument that returns non-nil if the + passed argument is a branch, that is, a node that can have + children. + + CHILDREN is a function of one argument that returns the children of + the passed branch node. + + Non-branch nodes are simply copied. + + (-tree-seq 'listp 'identity '(1 (2 3) 4 (5 (6 7)))) + ⇒ ((1 (2 3) 4 (5 (6 7))) 1 (2 3) 2 3 4 (5 (6 7)) 5 (6 7) 6 7) + (-tree-seq 'listp 'reverse '(1 (2 3) 4 (5 (6 7)))) + ⇒ ((1 (2 3) 4 (5 (6 7))) (5 (6 7)) (6 7) 7 6 5 4 (2 3) 3 2 1) + (--tree-seq (vectorp it) (append it nil) [1 [2 3] 4 [5 [6 7]]]) + ⇒ ([1 [2 3] 4 [5 [6 7]]] 1 [2 3] 2 3 4 [5 [6 7]] 5 [6 7] 6 7) + + -- Function: -tree-map (fn tree) + Apply FN to each element of TREE while preserving the tree + structure. + + (-tree-map '1+ '(1 (2 3) (4 (5 6) 7))) + ⇒ (2 (3 4) (5 (6 7) 8)) + (-tree-map '(lambda (x) (cons x (expt 2 x))) '(1 (2 3) 4)) + ⇒ ((1 . 2) ((2 . 4) (3 . 8)) (4 . 16)) + (--tree-map (length it) '("<body>" ("<p>" "text" "</p>") "</body>")) + ⇒ (6 (3 4 4) 7) + + -- Function: -tree-map-nodes (pred fun tree) + Call FUN on each node of TREE that satisfies PRED. + + If PRED returns nil, continue descending down this node. If PRED + returns non-nil, apply FUN to this node and do not descend further. + + (-tree-map-nodes 'vectorp (lambda (x) (-sum (append x nil))) '(1 [2 3] 4 (5 [6 7] 8))) + ⇒ (1 5 4 (5 13 8)) + (-tree-map-nodes 'keywordp (lambda (x) (symbol-name x)) '(1 :foo 4 ((5 6 :bar) :baz 8))) + ⇒ (1 ":foo" 4 ((5 6 ":bar") ":baz" 8)) + (--tree-map-nodes (eq (car-safe it) 'add-mode) (-concat it (list :mode 'emacs-lisp-mode)) '(with-mode emacs-lisp-mode (foo bar) (add-mode a b) (baz (add-mode c d)))) + ⇒ (with-mode emacs-lisp-mode (foo bar) (add-mode a b :mode emacs-lisp-mode) (baz (add-mode c d :mode emacs-lisp-mode))) + + -- Function: -tree-reduce (fn tree) + Use FN to reduce elements of list TREE. If elements of TREE are + lists themselves, apply the reduction recursively. + + FN is first applied to first element of the list and second + element, then on this result and third element from the list etc. + + See ‘-reduce-r’ (*note -reduce-r::) for how exactly are lists of + zero or one element handled. + + (-tree-reduce '+ '(1 (2 3) (4 5))) + ⇒ 15 + (-tree-reduce 'concat '("strings" (" on" " various") ((" levels")))) + ⇒ "strings on various levels" + (--tree-reduce (cond ((stringp it) (concat it " " acc)) (t (let ((sn (symbol-name it))) (concat "<" sn ">" acc "</" sn ">")))) '(body (p "some words") (div "more" (b "bold") "words"))) + ⇒ "<body><p>some words</p> <div>more <b>bold</b> words</div></body>" + + -- Function: -tree-reduce-from (fn init-value tree) + Use FN to reduce elements of list TREE. If elements of TREE are + lists themselves, apply the reduction recursively. + + FN is first applied to INIT-VALUE and first element of the list, + then on this result and second element from the list etc. + + The initial value is ignored on cons pairs as they always contain + two elements. + + (-tree-reduce-from '+ 1 '(1 (1 1) ((1)))) + ⇒ 8 + (--tree-reduce-from (-concat acc (list it)) nil '(1 (2 3 (4 5)) (6 7))) + ⇒ ((7 6) ((5 4) 3 2) 1) + + -- Function: -tree-mapreduce (fn folder tree) + Apply FN to each element of TREE, and make a list of the results. + If elements of TREE are lists themselves, apply FN recursively to + elements of these nested lists. + + Then reduce the resulting lists using FOLDER and initial value + INIT-VALUE. See ‘-reduce-r-from’ (*note -reduce-r-from::). + + This is the same as calling ‘-tree-reduce’ (*note -tree-reduce::) + after ‘-tree-map’ (*note -tree-map::) but is twice as fast as it + only traverse the structure once. + + (-tree-mapreduce 'list 'append '(1 (2 (3 4) (5 6)) (7 (8 9)))) + ⇒ (1 2 3 4 5 6 7 8 9) + (--tree-mapreduce 1 (+ it acc) '(1 (2 (4 9) (2 1)) (7 (4 3)))) + ⇒ 9 + (--tree-mapreduce 0 (max acc (1+ it)) '(1 (2 (4 9) (2 1)) (7 (4 3)))) + ⇒ 3 + + -- Function: -tree-mapreduce-from (fn folder init-value tree) + Apply FN to each element of TREE, and make a list of the results. + If elements of TREE are lists themselves, apply FN recursively to + elements of these nested lists. + + Then reduce the resulting lists using FOLDER and initial value + INIT-VALUE. See ‘-reduce-r-from’ (*note -reduce-r-from::). + + This is the same as calling ‘-tree-reduce-from’ (*note + -tree-reduce-from::) after ‘-tree-map’ (*note -tree-map::) but is + twice as fast as it only traverse the structure once. + + (-tree-mapreduce-from 'identity '* 1 '(1 (2 (3 4) (5 6)) (7 (8 9)))) + ⇒ 362880 + (--tree-mapreduce-from (+ it it) (cons it acc) nil '(1 (2 (4 9) (2 1)) (7 (4 3)))) + ⇒ (2 (4 (8 18) (4 2)) (14 (8 6))) + (concat "{" (--tree-mapreduce-from (cond ((-cons-pair? it) (concat (symbol-name (car it)) " -> " (symbol-name (cdr it)))) (t (concat (symbol-name it) " : {"))) (concat it (unless (or (equal acc "}") (equal (substring it (1- (length it))) "{")) ", ") acc) "}" '((elisp-mode (foo (bar . booze)) (baz . qux)) (c-mode (foo . bla) (bum . bam))))) + ⇒ "{elisp-mode : {foo : {bar -> booze}, baz -> qux}, c-mode : {foo -> bla, bum -> bam}}" + + -- Function: -clone (list) + Create a deep copy of LIST. The new list has the same elements and + structure but all cons are replaced with new ones. This is useful + when you need to clone a structure such as plist or alist. + + (let* ((a '(1 2 3)) (b (-clone a))) (nreverse a) b) + ⇒ (1 2 3) + + +File: dash.info, Node: Threading macros, Next: Binding, Prev: Tree operations, Up: Functions + +2.12 Threading macros +===================== + +Macros that conditionally combine sequential forms for brevity or +readability. + + -- Macro: -> (x &optional form &rest more) + Thread the expr through the forms. Insert X as the second item in + the first form, making a list of it if it is not a list already. + If there are more forms, insert the first form as the second item + in second form, etc. + + (-> '(2 3 5)) + ⇒ (2 3 5) + (-> '(2 3 5) (append '(8 13))) + ⇒ (2 3 5 8 13) + (-> '(2 3 5) (append '(8 13)) (-slice 1 -1)) + ⇒ (3 5 8) + + -- Macro: ->> (x &optional form &rest more) + Thread the expr through the forms. Insert X as the last item in + the first form, making a list of it if it is not a list already. + If there are more forms, insert the first form as the last item in + second form, etc. + + (->> '(1 2 3) (-map 'square)) + ⇒ (1 4 9) + (->> '(1 2 3) (-map 'square) (-remove 'even?)) + ⇒ (1 9) + (->> '(1 2 3) (-map 'square) (-reduce '+)) + ⇒ 14 + + -- Macro: --> (x &rest forms) + Starting with the value of X, thread each expression through FORMS. + + Insert X at the position signified by the symbol ‘it’ in the first + form. If there are more forms, insert the first form at the + position signified by ‘it’ in in second form, etc. + + (--> "def" (concat "abc" it "ghi")) + ⇒ "abcdefghi" + (--> "def" (concat "abc" it "ghi") (upcase it)) + ⇒ "ABCDEFGHI" + (--> "def" (concat "abc" it "ghi") upcase) + ⇒ "ABCDEFGHI" + + -- Macro: -as-> (value variable &rest forms) + Starting with VALUE, thread VARIABLE through FORMS. + + In the first form, bind VARIABLE to VALUE. In the second form, + bind VARIABLE to the result of the first form, and so forth. + + (-as-> 3 my-var (1+ my-var) (list my-var) (mapcar (lambda (ele) (* 2 ele)) my-var)) + ⇒ (8) + (-as-> 3 my-var 1+) + ⇒ 4 + (-as-> 3 my-var) + ⇒ 3 + + -- Macro: -some-> (x &optional form &rest more) + When expr is non-nil, thread it through the first form (via ‘->’ + (*note ->::)), and when that result is non-nil, through the next + form, etc. + + (-some-> '(2 3 5)) + ⇒ (2 3 5) + (-some-> 5 square) + ⇒ 25 + (-some-> 5 even? square) + ⇒ nil + + -- Macro: -some->> (x &optional form &rest more) + When expr is non-nil, thread it through the first form (via ‘->>’ + (*note ->>::)), and when that result is non-nil, through the next + form, etc. + + (-some->> '(1 2 3) (-map 'square)) + ⇒ (1 4 9) + (-some->> '(1 3 5) (-last 'even?) (+ 100)) + ⇒ nil + (-some->> '(2 4 6) (-last 'even?) (+ 100)) + ⇒ 106 + + -- Macro: -some--> (expr &rest forms) + Thread EXPR through FORMS via ‘-->’ (*note -->::), while the result + is non-nil. When EXPR evaluates to non-nil, thread the result + through the first of FORMS, and when that result is non-nil, thread + it through the next form, etc. + + (-some--> "def" (concat "abc" it "ghi")) + ⇒ "abcdefghi" + (-some--> nil (concat "abc" it "ghi")) + ⇒ nil + (-some--> '(0 1) (-remove #'natnump it) (append it it) (-map #'1+ it)) + ⇒ () + + -- Macro: -doto (init &rest forms) + Evaluate INIT and pass it as argument to FORMS with ‘->’ (*note + ->::). The RESULT of evaluating INIT is threaded through each of + FORMS individually using ‘->’ (*note ->::), which see. The return + value is RESULT, which FORMS may have modified by side effect. + + (-doto (list 1 2 3) pop pop) + ⇒ (3) + (-doto (cons 1 2) (setcar 3) (setcdr 4)) + ⇒ (3 . 4) + (gethash 'k (--doto (make-hash-table) (puthash 'k 'v it))) + ⇒ v + + +File: dash.info, Node: Binding, Next: Side effects, Prev: Threading macros, Up: Functions + +2.13 Binding +============ + +Macros that combine ‘let’ and ‘let*’ with destructuring and flow +control. + + -- Macro: -when-let ((var val) &rest body) + If VAL evaluates to non-nil, bind it to VAR and execute body. + + Note: binding is done according to ‘-let’ (*note -let::). + + (-when-let (match-index (string-match "d" "abcd")) (+ match-index 2)) + ⇒ 5 + (-when-let ((&plist :foo foo) (list :foo "foo")) foo) + ⇒ "foo" + (-when-let ((&plist :foo foo) (list :bar "bar")) foo) + ⇒ nil + + -- Macro: -when-let* (vars-vals &rest body) + If all VALS evaluate to true, bind them to their corresponding VARS + and execute body. VARS-VALS should be a list of (VAR VAL) pairs. + + Note: binding is done according to ‘-let*’ (*note -let*::). VALS + are evaluated sequentially, and evaluation stops after the first + nil VAL is encountered. + + (-when-let* ((x 5) (y 3) (z (+ y 4))) (+ x y z)) + ⇒ 15 + (-when-let* ((x 5) (y nil) (z 7)) (+ x y z)) + ⇒ nil + + -- Macro: -if-let ((var val) then &rest else) + If VAL evaluates to non-nil, bind it to VAR and do THEN, otherwise + do ELSE. + + Note: binding is done according to ‘-let’ (*note -let::). + + (-if-let (match-index (string-match "d" "abc")) (+ match-index 3) 7) + ⇒ 7 + (--if-let (even? 4) it nil) + ⇒ t + + -- Macro: -if-let* (vars-vals then &rest else) + If all VALS evaluate to true, bind them to their corresponding VARS + and do THEN, otherwise do ELSE. VARS-VALS should be a list of (VAR + VAL) pairs. + + Note: binding is done according to ‘-let*’ (*note -let*::). VALS + are evaluated sequentially, and evaluation stops after the first + nil VAL is encountered. + + (-if-let* ((x 5) (y 3) (z 7)) (+ x y z) "foo") + ⇒ 15 + (-if-let* ((x 5) (y nil) (z 7)) (+ x y z) "foo") + ⇒ "foo" + (-if-let* (((_ _ x) '(nil nil 7))) x) + ⇒ 7 + + -- Macro: -let (varlist &rest body) + Bind variables according to VARLIST then eval BODY. + + VARLIST is a list of lists of the form (PATTERN SOURCE). Each + PATTERN is matched against the SOURCE "structurally". SOURCE is + only evaluated once for each PATTERN. Each PATTERN is matched + recursively, and can therefore contain sub-patterns which are + matched against corresponding sub-expressions of SOURCE. + + All the SOURCEs are evalled before any symbols are bound (i.e. "in + parallel"). + + If VARLIST only contains one (PATTERN SOURCE) element, you can + optionally specify it using a vector and discarding the outer-most + parens. Thus + + (-let ((PATTERN SOURCE)) ...) + + becomes + + (-let [PATTERN SOURCE] ...). + + ‘-let’ (*note -let::) uses a convention of not binding places + (symbols) starting with _ whenever it’s possible. You can use this + to skip over entries you don’t care about. However, this is not + *always* possible (as a result of implementation) and these symbols + might get bound to undefined values. + + Following is the overview of supported patterns. Remember that + patterns can be matched recursively, so every a, b, aK in the + following can be a matching construct and not necessarily a + symbol/variable. + + Symbol: + + a - bind the SOURCE to A. This is just like regular ‘let’. + + Conses and lists: + + (a) - bind ‘car’ of cons/list to A + + (a . b) - bind car of cons to A and ‘cdr’ to B + + (a b) - bind car of list to A and ‘cadr’ to B + + (a1 a2 a3 ...) - bind 0th car of list to A1, 1st to A2, 2nd to + A3... + + (a1 a2 a3 ... aN . rest) - as above, but bind the Nth cdr to REST. + + Vectors: + + [a] - bind 0th element of a non-list sequence to A (works with + vectors, strings, bit arrays...) + + [a1 a2 a3 ...] - bind 0th element of non-list sequence to A0, 1st + to A1, 2nd to A2, ... If the PATTERN is shorter than SOURCE, the + values at places not in PATTERN are ignored. If the PATTERN is + longer than SOURCE, an ‘error’ is thrown. + + [a1 a2 a3 ... &rest rest] - as above, but bind the rest of the + sequence to REST. This is conceptually the same as improper list + matching (a1 a2 ... aN . rest) + + Key/value stores: + + (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE plist to aK. If the value is not found, aK is nil. Uses + ‘plist-get’ to fetch values. + + (&alist key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE alist to aK. If the value is not found, aK is nil. Uses + ‘assoc’ to fetch values. + + (&hash key0 a0 ... keyN aN) - bind value mapped by keyK in the + SOURCE hash table to aK. If the value is not found, aK is nil. + Uses ‘gethash’ to fetch values. + + Further, special keyword &keys supports "inline" matching of + plist-like key-value pairs, similarly to &keys keyword of + ‘cl-defun’. + + (a1 a2 ... aN &keys key1 b1 ... keyN bK) + + This binds N values from the list to a1 ... aN, then interprets the + cdr as a plist (see key/value matching above). + + A shorthand notation for kv-destructuring exists which allows the + patterns be optionally left out and derived from the key name in + the following fashion: + + - a key :foo is converted into ‘foo’ pattern, - a key ’bar is + converted into ‘bar’ pattern, - a key "baz" is converted into ‘baz’ + pattern. + + That is, the entire value under the key is bound to the derived + variable without any further destructuring. + + This is possible only when the form following the key is not a + valid pattern (i.e. not a symbol, a cons cell or a vector). + Otherwise the matching proceeds as usual and in case of an invalid + spec fails with an error. + + Thus the patterns are normalized as follows: + + ;; derive all the missing patterns (&plist :foo ’bar "baz") => + (&plist :foo foo ’bar bar "baz" baz) + + ;; we can specify some but not others (&plist :foo ’bar + explicit-bar) => (&plist :foo foo ’bar explicit-bar) + + ;; nothing happens, we store :foo in x (&plist :foo x) => (&plist + :foo x) + + ;; nothing happens, we match recursively (&plist :foo (a b c)) => + (&plist :foo (a b c)) + + You can name the source using the syntax SYMBOL &as PATTERN. This + syntax works with lists (proper or improper), vectors and all types + of maps. + + (list &as a b c) (list 1 2 3) + + binds A to 1, B to 2, C to 3 and LIST to (1 2 3). + + Similarly: + + (bounds &as beg . end) (cons 1 2) + + binds BEG to 1, END to 2 and BOUNDS to (1 . 2). + + (items &as first . rest) (list 1 2 3) + + binds FIRST to 1, REST to (2 3) and ITEMS to (1 2 3) + + [vect &as _ b c] [1 2 3] + + binds B to 2, C to 3 and VECT to [1 2 3] (_ avoids binding as + usual). + + (plist &as &plist :b b) (list :a 1 :b 2 :c 3) + + binds B to 2 and PLIST to (:a 1 :b 2 :c 3). Same for &alist and + &hash. + + This is especially useful when we want to capture the result of a + computation and destructure at the same time. Consider the form + (function-returning-complex-structure) returning a list of two + vectors with two items each. We want to capture this entire result + and pass it to another computation, but at the same time we want to + get the second item from each vector. We can achieve it with + pattern + + (result &as [_ a] [_ b]) (function-returning-complex-structure) + + Note: Clojure programmers may know this feature as the ":as + binding". The difference is that we put the &as at the front + because we need to support improper list binding. + + (-let (([a (b c) d] [1 (2 3) 4])) (list a b c d)) + ⇒ (1 2 3 4) + (-let [(a b c . d) (list 1 2 3 4 5 6)] (list a b c d)) + ⇒ (1 2 3 (4 5 6)) + (-let [(&plist :foo foo :bar bar) (list :baz 3 :foo 1 :qux 4 :bar 2)] (list foo bar)) + ⇒ (1 2) + + -- Macro: -let* (varlist &rest body) + Bind variables according to VARLIST then eval BODY. + + VARLIST is a list of lists of the form (PATTERN SOURCE). Each + PATTERN is matched against the SOURCE structurally. SOURCE is only + evaluated once for each PATTERN. + + Each SOURCE can refer to the symbols already bound by this VARLIST. + This is useful if you want to destructure SOURCE recursively but + also want to name the intermediate structures. + + See ‘-let’ (*note -let::) for the list of all possible patterns. + + (-let* (((a . b) (cons 1 2)) ((c . d) (cons 3 4))) (list a b c d)) + ⇒ (1 2 3 4) + (-let* (((a . b) (cons 1 (cons 2 3))) ((c . d) b)) (list a b c d)) + ⇒ (1 (2 . 3) 2 3) + (-let* (((&alist "foo" foo "bar" bar) (list (cons "foo" 1) (cons "bar" (list 'a 'b 'c)))) ((a b c) bar)) (list foo a b c bar)) + ⇒ (1 a b c (a b c)) + + -- Macro: -lambda (match-form &rest body) + Return a lambda which destructures its input as MATCH-FORM and + executes BODY. + + Note that you have to enclose the MATCH-FORM in a pair of parens, + such that: + + (-lambda (x) body) (-lambda (x y ...) body) + + has the usual semantics of ‘lambda’. Furthermore, these get + translated into normal ‘lambda’, so there is no performance + penalty. + + See ‘-let’ (*note -let::) for a description of the destructuring + mechanism. + + (-map (-lambda ((x y)) (+ x y)) '((1 2) (3 4) (5 6))) + ⇒ (3 7 11) + (-map (-lambda ([x y]) (+ x y)) '([1 2] [3 4] [5 6])) + ⇒ (3 7 11) + (funcall (-lambda ((_ . a) (_ . b)) (-concat a b)) '(1 2 3) '(4 5 6)) + ⇒ (2 3 5 6) + + -- Macro: -setq ([match-form val] ...) + Bind each MATCH-FORM to the value of its VAL. + + MATCH-FORM destructuring is done according to the rules of ‘-let’ + (*note -let::). + + This macro allows you to bind multiple variables by destructuring + the value, so for example: + + (-setq (a b) x (&plist :c c) plist) + + expands roughly speaking to the following code + + (setq a (car x) b (cadr x) c (plist-get plist :c)) + + Care is taken to only evaluate each VAL once so that in case of + multiple assignments it does not cause unexpected side effects. + + (let (a) (-setq a 1) a) + ⇒ 1 + (let (a b) (-setq (a b) (list 1 2)) (list a b)) + ⇒ (1 2) + (let (c) (-setq (&plist :c c) (list :c "c")) c) + ⇒ "c" + + +File: dash.info, Node: Side effects, Next: Destructive operations, Prev: Binding, Up: Functions + +2.14 Side effects +================= + +Functions iterating over lists for side effect only. + + -- Function: -each (list fn) + Call FN on each element of LIST. Return nil; this function is + intended for side effects. + + Its anaphoric counterpart is ‘--each’. + + For access to the current element’s index in LIST, see + ‘-each-indexed’ (*note -each-indexed::). + + (let (l) (-each '(1 2 3) (lambda (x) (push x l))) l) + ⇒ (3 2 1) + (let (l) (--each '(1 2 3) (push it l)) l) + ⇒ (3 2 1) + (-each '(1 2 3) #'identity) + ⇒ nil + + -- Function: -each-while (list pred fn) + Call FN on each ITEM in LIST, while (PRED ITEM) is non-nil. Once + an ITEM is reached for which PRED returns nil, FN is no longer + called. Return nil; this function is intended for side effects. + + Its anaphoric counterpart is ‘--each-while’. + + (let (l) (-each-while '(2 4 5 6) #'even? (lambda (x) (push x l))) l) + ⇒ (4 2) + (let (l) (--each-while '(1 2 3 4) (< it 3) (push it l)) l) + ⇒ (2 1) + (let ((s 0)) (--each-while '(1 3 4 5) (< it 5) (setq s (+ s it))) s) + ⇒ 8 + + -- Function: -each-indexed (list fn) + Call FN on each index and element of LIST. For each ITEM at INDEX + in LIST, call (funcall FN INDEX ITEM). Return nil; this function + is intended for side effects. + + See also: ‘-map-indexed’ (*note -map-indexed::). + + (let (l) (-each-indexed '(a b c) (lambda (i x) (push (list x i) l))) l) + ⇒ ((c 2) (b 1) (a 0)) + (let (l) (--each-indexed '(a b c) (push (list it it-index) l)) l) + ⇒ ((c 2) (b 1) (a 0)) + (let (l) (--each-indexed () (push it l)) l) + ⇒ () + + -- Function: -each-r (list fn) + Call FN on each element of LIST in reversed order. Return nil; + this function is intended for side effects. + + Its anaphoric counterpart is ‘--each-r’. + + (let (l) (-each-r '(1 2 3) (lambda (x) (push x l))) l) + ⇒ (1 2 3) + (let (l) (--each-r '(1 2 3) (push it l)) l) + ⇒ (1 2 3) + (-each-r '(1 2 3) #'identity) + ⇒ nil + + -- Function: -each-r-while (list pred fn) + Call FN on each ITEM in reversed LIST, while (PRED ITEM) is + non-nil. Once an ITEM is reached for which PRED returns nil, FN is + no longer called. Return nil; this function is intended for side + effects. + + Its anaphoric counterpart is ‘--each-r-while’. + + (let (l) (-each-r-while '(2 4 5 6) #'even? (lambda (x) (push x l))) l) + ⇒ (6) + (let (l) (--each-r-while '(1 2 3 4) (>= it 3) (push it l)) l) + ⇒ (3 4) + (let ((s 0)) (--each-r-while '(1 2 3 5) (> it 1) (setq s (+ s it))) s) + ⇒ 10 + + -- Function: -dotimes (num fn) + Call FN NUM times, presumably for side effects. FN is called with + a single argument on successive integers running from 0, inclusive, + to NUM, exclusive. FN is not called if NUM is less than 1. + + This function’s anaphoric counterpart is ‘--dotimes’. + + (let (s) (-dotimes 3 (lambda (n) (push n s))) s) + ⇒ (2 1 0) + (let (s) (-dotimes 0 (lambda (n) (push n s))) s) + ⇒ () + (let (s) (--dotimes 5 (push it s)) s) + ⇒ (4 3 2 1 0) + + +File: dash.info, Node: Destructive operations, Next: Function combinators, Prev: Side effects, Up: Functions + +2.15 Destructive operations +=========================== + +Macros that modify variables holding lists. + + -- Macro: !cons (car cdr) + Destructive: Set CDR to the cons of CAR and CDR. + + (let (l) (!cons 5 l) l) + ⇒ (5) + (let ((l '(3))) (!cons 5 l) l) + ⇒ (5 3) + + -- Macro: !cdr (list) + Destructive: Set LIST to the cdr of LIST. + + (let ((l '(3))) (!cdr l) l) + ⇒ () + (let ((l '(3 5))) (!cdr l) l) + ⇒ (5) + + +File: dash.info, Node: Function combinators, Prev: Destructive operations, Up: Functions + +2.16 Function combinators +========================= + +Functions that manipulate and compose other functions. + + -- Function: -partial (fun &rest args) + Return a function that is a partial application of FUN to ARGS. + ARGS is a list of the first N arguments to pass to FUN. The result + is a new function which does the same as FUN, except that the first + N arguments are fixed at the values with which this function was + called. + + (funcall (-partial #'+ 5)) + ⇒ 5 + (funcall (-partial #'- 5) 3) + ⇒ 2 + (funcall (-partial #'+ 5 2) 3) + ⇒ 10 + + -- Function: -rpartial (fn &rest args) + Return a function that is a partial application of FN to ARGS. + ARGS is a list of the last N arguments to pass to FN. The result + is a new function which does the same as FN, except that the last N + arguments are fixed at the values with which this function was + called. This is like ‘-partial’ (*note -partial::), except the + arguments are fixed starting from the right rather than the left. + + (funcall (-rpartial #'- 5)) + ⇒ -5 + (funcall (-rpartial #'- 5) 8) + ⇒ 3 + (funcall (-rpartial #'- 5 2) 10) + ⇒ 3 + + -- Function: -juxt (&rest fns) + Return a function that is the juxtaposition of FNS. The returned + function takes a variable number of ARGS, applies each of FNS in + turn to ARGS, and returns the list of results. + + (funcall (-juxt) 1 2) + ⇒ () + (funcall (-juxt #'+ #'- #'* #'/) 7 5) + ⇒ (12 2 35 1) + (mapcar (-juxt #'number-to-string #'1+) '(1 2)) + ⇒ (("1" 2) ("2" 3)) + + -- Function: -compose (&rest fns) + Compose FNS into a single composite function. Return a function + that takes a variable number of ARGS, applies the last function in + FNS to ARGS, and returns the result of calling each remaining + function on the result of the previous function, right-to-left. If + no FNS are given, return a variadic ‘identity’ function. + + (funcall (-compose #'- #'1+ #'+) 1 2 3) + ⇒ -7 + (funcall (-compose #'identity #'1+) 3) + ⇒ 4 + (mapcar (-compose #'not #'stringp) '(nil "")) + ⇒ (t nil) + + -- Function: -applify (fn) + Return a function that applies FN to a single list of args. This + changes the arity of FN from taking N distinct arguments to taking + 1 argument which is a list of N arguments. + + (funcall (-applify #'+) nil) + ⇒ 0 + (mapcar (-applify #'+) '((1 1 1) (1 2 3) (5 5 5))) + ⇒ (3 6 15) + (funcall (-applify #'<) '(3 6)) + ⇒ t + + -- Function: -on (op trans) + Return a function that calls TRANS on each arg and OP on the + results. The returned function takes a variable number of + arguments, calls the function TRANS on each one in turn, and then + passes those results as the list of arguments to OP, in the same + order. + + For example, the following pairs of expressions are morally + equivalent: + + (funcall (-on #’+ #’1+) 1 2 3) = (+ (1+ 1) (1+ 2) (1+ 3)) (funcall + (-on #’+ #’1+)) = (+) + + (-sort (-on #'< #'length) '((1 2 3) (1) (1 2))) + ⇒ ((1) (1 2) (1 2 3)) + (funcall (-on #'min #'string-to-number) "22" "2" "1" "12") + ⇒ 1 + (-min-by (-on #'> #'length) '((1 2 3) (4) (1 2))) + ⇒ (4) + + -- Function: -flip (fn) + Return a function that calls FN with its arguments reversed. The + returned function takes the same number of arguments as FN. + + For example, the following two expressions are morally equivalent: + + (funcall (-flip #’-) 1 2) = (- 2 1) + + See also: ‘-rotate-args’ (*note -rotate-args::). + + (-sort (-flip #'<) '(4 3 6 1)) + ⇒ (6 4 3 1) + (funcall (-flip #'-) 3 2 1 10) + ⇒ 4 + (funcall (-flip #'1+) 1) + ⇒ 2 + + -- Function: -rotate-args (n fn) + Return a function that calls FN with args rotated N places to the + right. The returned function takes the same number of arguments as + FN, rotates the list of arguments N places to the right (left if N + is negative) just like ‘-rotate’ (*note -rotate::), and applies FN + to the result. + + See also: ‘-flip’ (*note -flip::). + + (funcall (-rotate-args -1 #'list) 1 2 3 4) + ⇒ (2 3 4 1) + (funcall (-rotate-args 1 #'-) 1 10 100) + ⇒ 89 + (funcall (-rotate-args 2 #'list) 3 4 5 1 2) + ⇒ (1 2 3 4 5) + + -- Function: -const (c) + Return a function that returns C ignoring any additional arguments. + + In types: a -> b -> a + + (funcall (-const 2) 1 3 "foo") + ⇒ 2 + (mapcar (-const 1) '("a" "b" "c" "d")) + ⇒ (1 1 1 1) + (-sum (mapcar (-const 1) '("a" "b" "c" "d"))) + ⇒ 4 + + -- Macro: -cut (&rest params) + Take n-ary function and n arguments and specialize some of them. + Arguments denoted by <> will be left unspecialized. + + See SRFI-26 for detailed description. + + (funcall (-cut list 1 <> 3 <> 5) 2 4) + ⇒ (1 2 3 4 5) + (-map (-cut funcall <> 5) `(1+ 1- ,(lambda (x) (/ 1.0 x)))) + ⇒ (6 4 0.2) + (-map (-cut <> 1 2 3) '(list vector string)) + ⇒ ((1 2 3) [1 2 3] "\1\2\3") + + -- Function: -not (pred) + Return a predicate that negates the result of PRED. The returned + predicate passes its arguments to PRED. If PRED returns nil, the + result is non-nil; otherwise the result is nil. + + See also: ‘-andfn’ (*note -andfn::) and ‘-orfn’ (*note -orfn::). + + (funcall (-not #'numberp) "5") + ⇒ t + (-sort (-not #'<) '(5 2 1 0 6)) + ⇒ (6 5 2 1 0) + (-filter (-not (-partial #'< 4)) '(1 2 3 4 5 6 7 8)) + ⇒ (1 2 3 4) + + -- Function: -orfn (&rest preds) + Return a predicate that returns the first non-nil result of PREDS. + The returned predicate takes a variable number of arguments, passes + them to each predicate in PREDS in turn until one of them returns + non-nil, and returns that non-nil result without calling the + remaining PREDS. If all PREDS return nil, or if no PREDS are + given, the returned predicate returns nil. + + See also: ‘-andfn’ (*note -andfn::) and ‘-not’ (*note -not::). + + (-filter (-orfn #'natnump #'booleanp) '(1 nil "a" -4 b c t)) + ⇒ (1 nil t) + (funcall (-orfn #'symbolp (-cut string-match-p "x" <>)) "axe") + ⇒ 1 + (funcall (-orfn #'= #'+) 1 1) + ⇒ t + + -- Function: -andfn (&rest preds) + Return a predicate that returns non-nil if all PREDS do so. The + returned predicate P takes a variable number of arguments and + passes them to each predicate in PREDS in turn. If any one of + PREDS returns nil, P also returns nil without calling the remaining + PREDS. If all PREDS return non-nil, P returns the last such value. + If no PREDS are given, P always returns non-nil. + + See also: ‘-orfn’ (*note -orfn::) and ‘-not’ (*note -not::). + + (-filter (-andfn #'numberp (-cut < <> 5)) '(a 1 b 6 c 2)) + ⇒ (1 2) + (mapcar (-andfn #'numberp #'1+) '(a 1 b 6)) + ⇒ (nil 2 nil 7) + (funcall (-andfn #'= #'+) 1 1) + ⇒ 2 + + -- Function: -iteratefn (fn n) + Return a function FN composed N times with itself. + + FN is a unary function. If you need to use a function of higher + arity, use ‘-applify’ (*note -applify::) first to turn it into a + unary function. + + With n = 0, this acts as identity function. + + In types: (a -> a) -> Int -> a -> a. + + This function satisfies the following law: + + (funcall (-iteratefn fn n) init) = (-last-item (-iterate fn init + (1+ n))). + + (funcall (-iteratefn (lambda (x) (* x x)) 3) 2) + ⇒ 256 + (funcall (-iteratefn '1+ 3) 1) + ⇒ 4 + (funcall (-iteratefn 'cdr 3) '(1 2 3 4 5)) + ⇒ (4 5) + + -- Function: -fixfn (fn &optional equal-test halt-test) + Return a function that computes the (least) fixpoint of FN. + + FN must be a unary function. The returned lambda takes a single + argument, X, the initial value for the fixpoint iteration. The + iteration halts when either of the following conditions is + satisfied: + + 1. Iteration converges to the fixpoint, with equality being tested + using EQUAL-TEST. If EQUAL-TEST is not specified, ‘equal’ is used. + For functions over the floating point numbers, it may be necessary + to provide an appropriate approximate comparison test. + + 2. HALT-TEST returns a non-nil value. HALT-TEST defaults to a + simple counter that returns t after ‘-fixfn-max-iterations’, to + guard against infinite iteration. Otherwise, HALT-TEST must be a + function that accepts a single argument, the current value of X, + and returns non-nil as long as iteration should continue. In this + way, a more sophisticated convergence test may be supplied by the + caller. + + The return value of the lambda is either the fixpoint or, if + iteration halted before converging, a cons with car ‘halted’ and + cdr the final output from HALT-TEST. + + In types: (a -> a) -> a -> a. + + (funcall (-fixfn #'cos #'approx=) 0.7) + ⇒ 0.7390851332151607 + (funcall (-fixfn (lambda (x) (expt (+ x 10) 0.25))) 2.0) + ⇒ 1.8555845286409378 + (funcall (-fixfn #'sin #'approx=) 0.1) + ⇒ (halted . t) + + -- Function: -prodfn (&rest fns) + Take a list of n functions and return a function that takes a list + of length n, applying i-th function to i-th element of the input + list. Returns a list of length n. + + In types (for n=2): ((a -> b), (c -> d)) -> (a, c) -> (b, d) + + This function satisfies the following laws: + + (-compose (-prodfn f g ...) (-prodfn f’ g’ ...)) = (-prodfn + (-compose f f’) (-compose g g’) ...) (-prodfn f g ...) = (-juxt + (-compose f (-partial ’nth 0)) (-compose g (-partial ’nth 1)) ...) + (-compose (-prodfn f g ...) (-juxt f’ g’ ...)) = (-juxt (-compose f + f’) (-compose g g’) ...) (-compose (-partial ’nth n) (-prod f1 f2 + ...)) = (-compose fn (-partial ’nth n)) + + (funcall (-prodfn '1+ '1- 'number-to-string) '(1 2 3)) + ⇒ (2 1 "3") + (-map (-prodfn '1+ '1-) '((1 2) (3 4) (5 6) (7 8))) + ⇒ ((2 1) (4 3) (6 5) (8 7)) + (apply '+ (funcall (-prodfn 'length 'string-to-number) '((1 2 3) "15"))) + ⇒ 18 + + +File: dash.info, Node: Development, Next: FDL, Prev: Functions, Up: Top + +3 Development +************* + +The Dash repository is hosted on GitHub at +<https://github.com/magnars/dash.el>. + +* Menu: + +* Contribute:: How to contribute. +* Contributors:: List of contributors. + + +File: dash.info, Node: Contribute, Next: Contributors, Up: Development + +3.1 Contribute +============== + +Yes, please do. Pure functions in the list manipulation realm only, +please. There’s a suite of examples/tests in ‘dev/examples.el’, so +remember to add tests for your additions, or they may get broken later. + + Run the tests with ‘make check’. Regenerate the docs with ‘make +docs’. Contributors are encouraged to install these commands as a Git +pre-commit hook, so that the tests are always running and the docs are +always in sync: + + $ cp dev/pre-commit.sh .git/hooks/pre-commit + + Oh, and don’t edit ‘README.md’ or ‘dash.texi’ directly, as they are +auto-generated. Instead, change their respective templates +‘readme-template.md’ or ‘dash-template.texi’. + + To ensure that Dash can be distributed with GNU ELPA or Emacs, we +require that all contributors assign copyright to the Free Software +Foundation. For more on this, *note (emacs)Copyright Assignment::. + + +File: dash.info, Node: Contributors, Prev: Contribute, Up: Development + +3.2 Contributors +================ + + • Matus Goljer (https://github.com/Fuco1) contributed lots of + features and functions. + • Takafumi Arakaki (https://github.com/tkf) contributed ‘-group-by’. + • tali713 (https://github.com/tali713) is the author of ‘-applify’. + • VÃctor M. Valenzuela (https://github.com/vemv) contributed + ‘-repeat’. + • Nic Ferrier (https://github.com/nicferrier) contributed ‘-cons*’. + • Wilfred Hughes (https://github.com/Wilfred) contributed ‘-slice’, + ‘-first-item’, and ‘-last-item’. + • Emanuel Evans (https://github.com/shosti) contributed ‘-if-let’, + ‘-when-let’, and ‘-insert-at’. + • Johan Andersson (https://github.com/rejeep) contributed ‘-sum’, + ‘-product’, and ‘-same-items?’. + • Christina Whyte (https://github.com/kurisuwhyte) contributed + ‘-compose’. + • Steve Lamb (https://github.com/steventlamb) contributed ‘-cycle’, + ‘-pad’, ‘-annotate’, ‘-zip-fill’, and a variadic version of ‘-zip’. + • Fredrik Bergroth (https://github.com/fbergroth) made the ‘-if-let’ + family use ‘-let’ destructuring and improved the script for + generating documentation. + • Mark Oteiza (https://github.com/holomorph) contributed ‘-iota’ and + the script to create an Info manual. + • Vasilij Schneidermann (https://github.com/wasamasa) contributed + ‘-some’. + • William West (https://github.com/occidens) made ‘-fixfn’ more + robust at handling floats. + • Cam Saul (https://github.com/camsaul) contributed ‘-some->’, + ‘-some->>’, and ‘-some-->’. + • Basil L. Contovounesios (https://github.com/basil-conto) + contributed ‘-common-prefix’, ‘-common-suffix’, and various other + improvements. + • Paul Pogonyshev (https://github.com/doublep) contributed ‘-each-r’ + and ‘-each-r-while’. + + Thanks! + + New contributors are very welcome. *Note Contribute::. + + +File: dash.info, Node: FDL, Next: GPL, Prev: Development, Up: Top + +Appendix A GNU Free Documentation License +***************************************** + + Version 1.3, 3 November 2008 + + Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. + <https://fsf.org/> + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + 0. PREAMBLE + + The purpose of this License is to make a manual, textbook, or other + functional and useful document “free†in the sense of freedom: to + assure everyone the effective freedom to copy and redistribute it, + with or without modifying it, either commercially or + noncommercially. Secondarily, this License preserves for the + author and publisher a way to get credit for their work, while not + being considered responsible for modifications made by others. + + This License is a kind of “copyleftâ€, which means that derivative + works of the document must themselves be free in the same sense. + It complements the GNU General Public License, which is a copyleft + license designed for free software. + + We have designed this License in order to use it for manuals for + free software, because free software needs free documentation: a + free program should come with manuals providing the same freedoms + that the software does. But this License is not limited to + software manuals; it can be used for any textual work, regardless + of subject matter or whether it is published as a printed book. We + recommend this License principally for works whose purpose is + instruction or reference. + + 1. APPLICABILITY AND DEFINITIONS + + This License applies to any manual or other work, in any medium, + that contains a notice placed by the copyright holder saying it can + be distributed under the terms of this License. Such a notice + grants a world-wide, royalty-free license, unlimited in duration, + to use that work under the conditions stated herein. The + “Documentâ€, below, refers to any such manual or work. Any member + of the public is a licensee, and is addressed as “youâ€. You accept + the license if you copy, modify or distribute the work in a way + requiring permission under copyright law. + + A “Modified Version†of the Document means any work containing the + Document or a portion of it, either copied verbatim, or with + modifications and/or translated into another language. + + A “Secondary Section†is a named appendix or a front-matter section + of the Document that deals exclusively with the relationship of the + publishers or authors of the Document to the Document’s overall + subject (or to related matters) and contains nothing that could + fall directly within that overall subject. (Thus, if the Document + is in part a textbook of mathematics, a Secondary Section may not + explain any mathematics.) The relationship could be a matter of + historical connection with the subject or with related matters, or + of legal, commercial, philosophical, ethical or political position + regarding them. + + The “Invariant Sections†are certain Secondary Sections whose + titles are designated, as being those of Invariant Sections, in the + notice that says that the Document is released under this License. + If a section does not fit the above definition of Secondary then it + is not allowed to be designated as Invariant. The Document may + contain zero Invariant Sections. If the Document does not identify + any Invariant Sections then there are none. + + The “Cover Texts†are certain short passages of text that are + listed, as Front-Cover Texts or Back-Cover Texts, in the notice + that says that the Document is released under this License. A + Front-Cover Text may be at most 5 words, and a Back-Cover Text may + be at most 25 words. + + A “Transparent†copy of the Document means a machine-readable copy, + represented in a format whose specification is available to the + general public, that is suitable for revising the document + straightforwardly with generic text editors or (for images composed + of pixels) generic paint programs or (for drawings) some widely + available drawing editor, and that is suitable for input to text + formatters or for automatic translation to a variety of formats + suitable for input to text formatters. A copy made in an otherwise + Transparent file format whose markup, or absence of markup, has + been arranged to thwart or discourage subsequent modification by + readers is not Transparent. An image format is not Transparent if + used for any substantial amount of text. A copy that is not + “Transparent†is called “Opaqueâ€. + + Examples of suitable formats for Transparent copies include plain + ASCII without markup, Texinfo input format, LaTeX input format, + SGML or XML using a publicly available DTD, and standard-conforming + simple HTML, PostScript or PDF designed for human modification. + Examples of transparent image formats include PNG, XCF and JPG. + Opaque formats include proprietary formats that can be read and + edited only by proprietary word processors, SGML or XML for which + the DTD and/or processing tools are not generally available, and + the machine-generated HTML, PostScript or PDF produced by some word + processors for output purposes only. + + The “Title Page†means, for a printed book, the title page itself, + plus such following pages as are needed to hold, legibly, the + material this License requires to appear in the title page. For + works in formats which do not have any title page as such, “Title + Page†means the text near the most prominent appearance of the + work’s title, preceding the beginning of the body of the text. + + The “publisher†means any person or entity that distributes copies + of the Document to the public. + + A section “Entitled XYZ†means a named subunit of the Document + whose title either is precisely XYZ or contains XYZ in parentheses + following text that translates XYZ in another language. (Here XYZ + stands for a specific section name mentioned below, such as + “Acknowledgementsâ€, “Dedicationsâ€, “Endorsementsâ€, or “Historyâ€.) + To “Preserve the Title†of such a section when you modify the + Document means that it remains a section “Entitled XYZ†according + to this definition. + + The Document may include Warranty Disclaimers next to the notice + which states that this License applies to the Document. These + Warranty Disclaimers are considered to be included by reference in + this License, but only as regards disclaiming warranties: any other + implication that these Warranty Disclaimers may have is void and + has no effect on the meaning of this License. + + 2. VERBATIM COPYING + + You may copy and distribute the Document in any medium, either + commercially or noncommercially, provided that this License, the + copyright notices, and the license notice saying this License + applies to the Document are reproduced in all copies, and that you + add no other conditions whatsoever to those of this License. You + may not use technical measures to obstruct or control the reading + or further copying of the copies you make or distribute. However, + you may accept compensation in exchange for copies. If you + distribute a large enough number of copies you must also follow the + conditions in section 3. + + You may also lend copies, under the same conditions stated above, + and you may publicly display copies. + + 3. COPYING IN QUANTITY + + If you publish printed copies (or copies in media that commonly + have printed covers) of the Document, numbering more than 100, and + the Document’s license notice requires Cover Texts, you must + enclose the copies in covers that carry, clearly and legibly, all + these Cover Texts: Front-Cover Texts on the front cover, and + Back-Cover Texts on the back cover. Both covers must also clearly + and legibly identify you as the publisher of these copies. The + front cover must present the full title with all words of the title + equally prominent and visible. You may add other material on the + covers in addition. Copying with changes limited to the covers, as + long as they preserve the title of the Document and satisfy these + conditions, can be treated as verbatim copying in other respects. + + If the required texts for either cover are too voluminous to fit + legibly, you should put the first ones listed (as many as fit + reasonably) on the actual cover, and continue the rest onto + adjacent pages. + + If you publish or distribute Opaque copies of the Document + numbering more than 100, you must either include a machine-readable + Transparent copy along with each Opaque copy, or state in or with + each Opaque copy a computer-network location from which the general + network-using public has access to download using public-standard + network protocols a complete Transparent copy of the Document, free + of added material. If you use the latter option, you must take + reasonably prudent steps, when you begin distribution of Opaque + copies in quantity, to ensure that this Transparent copy will + remain thus accessible at the stated location until at least one + year after the last time you distribute an Opaque copy (directly or + through your agents or retailers) of that edition to the public. + + It is requested, but not required, that you contact the authors of + the Document well before redistributing any large number of copies, + to give them a chance to provide you with an updated version of the + Document. + + 4. MODIFICATIONS + + You may copy and distribute a Modified Version of the Document + under the conditions of sections 2 and 3 above, provided that you + release the Modified Version under precisely this License, with the + Modified Version filling the role of the Document, thus licensing + distribution and modification of the Modified Version to whoever + possesses a copy of it. In addition, you must do these things in + the Modified Version: + + A. Use in the Title Page (and on the covers, if any) a title + distinct from that of the Document, and from those of previous + versions (which should, if there were any, be listed in the + History section of the Document). You may use the same title + as a previous version if the original publisher of that + version gives permission. + + B. List on the Title Page, as authors, one or more persons or + entities responsible for authorship of the modifications in + the Modified Version, together with at least five of the + principal authors of the Document (all of its principal + authors, if it has fewer than five), unless they release you + from this requirement. + + C. State on the Title page the name of the publisher of the + Modified Version, as the publisher. + + D. Preserve all the copyright notices of the Document. + + E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices. + + F. Include, immediately after the copyright notices, a license + notice giving the public permission to use the Modified + Version under the terms of this License, in the form shown in + the Addendum below. + + G. Preserve in that license notice the full lists of Invariant + Sections and required Cover Texts given in the Document’s + license notice. + + H. Include an unaltered copy of this License. + + I. Preserve the section Entitled “Historyâ€, Preserve its Title, + and add to it an item stating at least the title, year, new + authors, and publisher of the Modified Version as given on the + Title Page. If there is no section Entitled “History†in the + Document, create one stating the title, year, authors, and + publisher of the Document as given on its Title Page, then add + an item describing the Modified Version as stated in the + previous sentence. + + J. Preserve the network location, if any, given in the Document + for public access to a Transparent copy of the Document, and + likewise the network locations given in the Document for + previous versions it was based on. These may be placed in the + “History†section. You may omit a network location for a work + that was published at least four years before the Document + itself, or if the original publisher of the version it refers + to gives permission. + + K. For any section Entitled “Acknowledgements†or “Dedicationsâ€, + Preserve the Title of the section, and preserve in the section + all the substance and tone of each of the contributor + acknowledgements and/or dedications given therein. + + L. Preserve all the Invariant Sections of the Document, unaltered + in their text and in their titles. Section numbers or the + equivalent are not considered part of the section titles. + + M. Delete any section Entitled “Endorsementsâ€. Such a section + may not be included in the Modified Version. + + N. Do not retitle any existing section to be Entitled + “Endorsements†or to conflict in title with any Invariant + Section. + + O. Preserve any Warranty Disclaimers. + + If the Modified Version includes new front-matter sections or + appendices that qualify as Secondary Sections and contain no + material copied from the Document, you may at your option designate + some or all of these sections as invariant. To do this, add their + titles to the list of Invariant Sections in the Modified Version’s + license notice. These titles must be distinct from any other + section titles. + + You may add a section Entitled “Endorsementsâ€, provided it contains + nothing but endorsements of your Modified Version by various + parties—for example, statements of peer review or that the text has + been approved by an organization as the authoritative definition of + a standard. + + You may add a passage of up to five words as a Front-Cover Text, + and a passage of up to 25 words as a Back-Cover Text, to the end of + the list of Cover Texts in the Modified Version. Only one passage + of Front-Cover Text and one of Back-Cover Text may be added by (or + through arrangements made by) any one entity. If the Document + already includes a cover text for the same cover, previously added + by you or by arrangement made by the same entity you are acting on + behalf of, you may not add another; but you may replace the old + one, on explicit permission from the previous publisher that added + the old one. + + The author(s) and publisher(s) of the Document do not by this + License give permission to use their names for publicity for or to + assert or imply endorsement of any Modified Version. + + 5. COMBINING DOCUMENTS + + You may combine the Document with other documents released under + this License, under the terms defined in section 4 above for + modified versions, provided that you include in the combination all + of the Invariant Sections of all of the original documents, + unmodified, and list them all as Invariant Sections of your + combined work in its license notice, and that you preserve all + their Warranty Disclaimers. + + The combined work need only contain one copy of this License, and + multiple identical Invariant Sections may be replaced with a single + copy. If there are multiple Invariant Sections with the same name + but different contents, make the title of each such section unique + by adding at the end of it, in parentheses, the name of the + original author or publisher of that section if known, or else a + unique number. Make the same adjustment to the section titles in + the list of Invariant Sections in the license notice of the + combined work. + + In the combination, you must combine any sections Entitled + “History†in the various original documents, forming one section + Entitled “Historyâ€; likewise combine any sections Entitled + “Acknowledgementsâ€, and any sections Entitled “Dedicationsâ€. You + must delete all sections Entitled “Endorsements.†+ + 6. COLLECTIONS OF DOCUMENTS + + You may make a collection consisting of the Document and other + documents released under this License, and replace the individual + copies of this License in the various documents with a single copy + that is included in the collection, provided that you follow the + rules of this License for verbatim copying of each of the documents + in all other respects. + + You may extract a single document from such a collection, and + distribute it individually under this License, provided you insert + a copy of this License into the extracted document, and follow this + License in all other respects regarding verbatim copying of that + document. + + 7. AGGREGATION WITH INDEPENDENT WORKS + + A compilation of the Document or its derivatives with other + separate and independent documents or works, in or on a volume of a + storage or distribution medium, is called an “aggregate†if the + copyright resulting from the compilation is not used to limit the + legal rights of the compilation’s users beyond what the individual + works permit. When the Document is included in an aggregate, this + License does not apply to the other works in the aggregate which + are not themselves derivative works of the Document. + + If the Cover Text requirement of section 3 is applicable to these + copies of the Document, then if the Document is less than one half + of the entire aggregate, the Document’s Cover Texts may be placed + on covers that bracket the Document within the aggregate, or the + electronic equivalent of covers if the Document is in electronic + form. Otherwise they must appear on printed covers that bracket + the whole aggregate. + + 8. TRANSLATION + + Translation is considered a kind of modification, so you may + distribute translations of the Document under the terms of section + 4. Replacing Invariant Sections with translations requires special + permission from their copyright holders, but you may include + translations of some or all Invariant Sections in addition to the + original versions of these Invariant Sections. You may include a + translation of this License, and all the license notices in the + Document, and any Warranty Disclaimers, provided that you also + include the original English version of this License and the + original versions of those notices and disclaimers. In case of a + disagreement between the translation and the original version of + this License or a notice or disclaimer, the original version will + prevail. + + If a section in the Document is Entitled “Acknowledgementsâ€, + “Dedicationsâ€, or “Historyâ€, the requirement (section 4) to + Preserve its Title (section 1) will typically require changing the + actual title. + + 9. TERMINATION + + You may not copy, modify, sublicense, or distribute the Document + except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense, or distribute it is void, + and will automatically terminate your rights under this License. + + However, if you cease all violation of this License, then your + license from a particular copyright holder is reinstated (a) + provisionally, unless and until the copyright holder explicitly and + finally terminates your license, and (b) permanently, if the + copyright holder fails to notify you of the violation by some + reasonable means prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is + reinstated permanently if the copyright holder notifies you of the + violation by some reasonable means, this is the first time you have + received notice of violation of this License (for any work) from + that copyright holder, and you cure the violation prior to 30 days + after your receipt of the notice. + + Termination of your rights under this section does not terminate + the licenses of parties who have received copies or rights from you + under this License. If your rights have been terminated and not + permanently reinstated, receipt of a copy of some or all of the + same material does not give you any rights to use it. + + 10. FUTURE REVISIONS OF THIS LICENSE + + The Free Software Foundation may publish new, revised versions of + the GNU Free Documentation License from time to time. Such new + versions will be similar in spirit to the present version, but may + differ in detail to address new problems or concerns. See + <https://www.gnu.org/licenses/>. + + Each version of the License is given a distinguishing version + number. If the Document specifies that a particular numbered + version of this License “or any later version†applies to it, you + have the option of following the terms and conditions either of + that specified version or of any later version that has been + published (not as a draft) by the Free Software Foundation. If the + Document does not specify a version number of this License, you may + choose any version ever published (not as a draft) by the Free + Software Foundation. If the Document specifies that a proxy can + decide which future versions of this License can be used, that + proxy’s public statement of acceptance of a version permanently + authorizes you to choose that version for the Document. + + 11. RELICENSING + + “Massive Multiauthor Collaboration Site†(or “MMC Siteâ€) means any + World Wide Web server that publishes copyrightable works and also + provides prominent facilities for anybody to edit those works. A + public wiki that anybody can edit is an example of such a server. + A “Massive Multiauthor Collaboration†(or “MMCâ€) contained in the + site means any set of copyrightable works thus published on the MMC + site. + + “CC-BY-SA†means the Creative Commons Attribution-Share Alike 3.0 + license published by Creative Commons Corporation, a not-for-profit + corporation with a principal place of business in San Francisco, + California, as well as future copyleft versions of that license + published by that same organization. + + “Incorporate†means to publish or republish a Document, in whole or + in part, as part of another Document. + + An MMC is “eligible for relicensing†if it is licensed under this + License, and if all works that were first published under this + License somewhere other than this MMC, and subsequently + incorporated in whole or in part into the MMC, (1) had no cover + texts or invariant sections, and (2) were thus incorporated prior + to November 1, 2008. + + The operator of an MMC Site may republish an MMC contained in the + site under CC-BY-SA on the same site at any time before August 1, + 2009, provided the MMC is eligible for relicensing. + +ADDENDUM: How to use this License for your documents +==================================================== + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and license +notices just after the title page: + + Copyright (C) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.3 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover + Texts. A copy of the license is included in the section entitled ``GNU + Free Documentation License''. + + If you have Invariant Sections, Front-Cover Texts and Back-Cover +Texts, replace the “with...Texts.†line with this: + + with the Invariant Sections being LIST THEIR TITLES, with + the Front-Cover Texts being LIST, and with the Back-Cover Texts + being LIST. + + If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + + If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of free +software license, such as the GNU General Public License, to permit +their use in free software. + + +File: dash.info, Node: GPL, Next: Index, Prev: FDL, Up: Top + +Appendix B GNU General Public License +************************************* + + Version 3, 29 June 2007 + + Copyright © 2007 Free Software Foundation, Inc. <https://fsf.org/> + + Everyone is permitted to copy and distribute verbatim copies of this + license document, but changing it is not allowed. + +Preamble +======== + +The GNU General Public License is a free, copyleft license for software +and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program—to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers’ and authors’ protection, the GPL clearly explains +that there is no warranty for this free software. For both users’ and +authors’ sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users’ freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + +TERMS AND CONDITIONS +==================== + + 0. Definitions. + + “This License†refers to version 3 of the GNU General Public + License. + + “Copyright†also means copyright-like laws that apply to other + kinds of works, such as semiconductor masks. + + “The Program†refers to any copyrightable work licensed under this + License. Each licensee is addressed as “youâ€. “Licensees†and + “recipients†may be individuals or organizations. + + To “modify†a work means to copy from or adapt all or part of the + work in a fashion requiring copyright permission, other than the + making of an exact copy. The resulting work is called a “modified + version†of the earlier work or a work “based on†the earlier work. + + A “covered work†means either the unmodified Program or a work + based on the Program. + + To “propagate†a work means to do anything with it that, without + permission, would make you directly or secondarily liable for + infringement under applicable copyright law, except executing it on + a computer or modifying a private copy. Propagation includes + copying, distribution (with or without modification), making + available to the public, and in some countries other activities as + well. + + To “convey†a work means any kind of propagation that enables other + parties to make or receive copies. Mere interaction with a user + through a computer network, with no transfer of a copy, is not + conveying. + + An interactive user interface displays “Appropriate Legal Notices†+ to the extent that it includes a convenient and prominently visible + feature that (1) displays an appropriate copyright notice, and (2) + tells the user that there is no warranty for the work (except to + the extent that warranties are provided), that licensees may convey + the work under this License, and how to view a copy of this + License. If the interface presents a list of user commands or + options, such as a menu, a prominent item in the list meets this + criterion. + + 1. Source Code. + + The “source code†for a work means the preferred form of the work + for making modifications to it. “Object code†means any non-source + form of a work. + + A “Standard Interface†means an interface that either is an + official standard defined by a recognized standards body, or, in + the case of interfaces specified for a particular programming + language, one that is widely used among developers working in that + language. + + The “System Libraries†of an executable work include anything, + other than the work as a whole, that (a) is included in the normal + form of packaging a Major Component, but which is not part of that + Major Component, and (b) serves only to enable use of the work with + that Major Component, or to implement a Standard Interface for + which an implementation is available to the public in source code + form. A “Major Componentâ€, in this context, means a major + essential component (kernel, window system, and so on) of the + specific operating system (if any) on which the executable work + runs, or a compiler used to produce the work, or an object code + interpreter used to run it. + + The “Corresponding Source†for a work in object code form means all + the source code needed to generate, install, and (for an executable + work) run the object code and to modify the work, including scripts + to control those activities. However, it does not include the + work’s System Libraries, or general-purpose tools or generally + available free programs which are used unmodified in performing + those activities but which are not part of the work. For example, + Corresponding Source includes interface definition files associated + with source files for the work, and the source code for shared + libraries and dynamically linked subprograms that the work is + specifically designed to require, such as by intimate data + communication or control flow between those subprograms and other + parts of the work. + + The Corresponding Source need not include anything that users can + regenerate automatically from other parts of the Corresponding + Source. + + The Corresponding Source for a work in source code form is that + same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of + copyright on the Program, and are irrevocable provided the stated + conditions are met. This License explicitly affirms your unlimited + permission to run the unmodified Program. The output from running + a covered work is covered by this License only if the output, given + its content, constitutes a covered work. This License acknowledges + your rights of fair use or other equivalent, as provided by + copyright law. + + You may make, run and propagate covered works that you do not + convey, without conditions so long as your license otherwise + remains in force. You may convey covered works to others for the + sole purpose of having them make modifications exclusively for you, + or provide you with facilities for running those works, provided + that you comply with the terms of this License in conveying all + material for which you do not control copyright. Those thus making + or running the covered works for you must do so exclusively on your + behalf, under your direction and control, on terms that prohibit + them from making any copies of your copyrighted material outside + their relationship with you. + + Conveying under any other circumstances is permitted solely under + the conditions stated below. Sublicensing is not allowed; section + 10 makes it unnecessary. + + 3. Protecting Users’ Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological + measure under any applicable law fulfilling obligations under + article 11 of the WIPO copyright treaty adopted on 20 December + 1996, or similar laws prohibiting or restricting circumvention of + such measures. + + When you convey a covered work, you waive any legal power to forbid + circumvention of technological measures to the extent such + circumvention is effected by exercising rights under this License + with respect to the covered work, and you disclaim any intention to + limit operation or modification of the work as a means of + enforcing, against the work’s users, your or third parties’ legal + rights to forbid circumvention of technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program’s source code as you + receive it, in any medium, provided that you conspicuously and + appropriately publish on each copy an appropriate copyright notice; + keep intact all notices stating that this License and any + non-permissive terms added in accord with section 7 apply to the + code; keep intact all notices of the absence of any warranty; and + give all recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, + and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to + produce it from the Program, in the form of source code under the + terms of section 4, provided that you also meet all of these + conditions: + + a. The work must carry prominent notices stating that you + modified it, and giving a relevant date. + + b. The work must carry prominent notices stating that it is + released under this License and any conditions added under + section 7. This requirement modifies the requirement in + section 4 to “keep intact all noticesâ€. + + c. You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable + section 7 additional terms, to the whole of the work, and all + its parts, regardless of how they are packaged. This License + gives no permission to license the work in any other way, but + it does not invalidate such permission if you have separately + received it. + + d. If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has + interactive interfaces that do not display Appropriate Legal + Notices, your work need not make them do so. + + A compilation of a covered work with other separate and independent + works, which are not by their nature extensions of the covered + work, and which are not combined with it such as to form a larger + program, in or on a volume of a storage or distribution medium, is + called an “aggregate†if the compilation and its resulting + copyright are not used to limit the access or legal rights of the + compilation’s users beyond what the individual works permit. + Inclusion of a covered work in an aggregate does not cause this + License to apply to the other parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms + of sections 4 and 5, provided that you also convey the + machine-readable Corresponding Source under the terms of this + License, in one of these ways: + + a. Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b. Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that + product model, to give anyone who possesses the object code + either (1) a copy of the Corresponding Source for all the + software in the product that is covered by this License, on a + durable physical medium customarily used for software + interchange, for a price no more than your reasonable cost of + physically performing this conveying of source, or (2) access + to copy the Corresponding Source from a network server at no + charge. + + c. Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, + and only if you received the object code with such an offer, + in accord with subsection 6b. + + d. Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to + the Corresponding Source in the same way through the same + place at no further charge. You need not require recipients + to copy the Corresponding Source along with the object code. + If the place to copy the object code is a network server, the + Corresponding Source may be on a different server (operated by + you or a third party) that supports equivalent copying + facilities, provided you maintain clear directions next to the + object code saying where to find the Corresponding Source. + Regardless of what server hosts the Corresponding Source, you + remain obligated to ensure that it is available for as long as + needed to satisfy these requirements. + + e. Convey the object code using peer-to-peer transmission, + provided you inform other peers where the object code and + Corresponding Source of the work are being offered to the + general public at no charge under subsection 6d. + + A separable portion of the object code, whose source code is + excluded from the Corresponding Source as a System Library, need + not be included in conveying the object code work. + + A “User Product†is either (1) a “consumer productâ€, which means + any tangible personal property which is normally used for personal, + family, or household purposes, or (2) anything designed or sold for + incorporation into a dwelling. In determining whether a product is + a consumer product, doubtful cases shall be resolved in favor of + coverage. For a particular product received by a particular user, + “normally used†refers to a typical or common use of that class of + product, regardless of the status of the particular user or of the + way in which the particular user actually uses, or expects or is + expected to use, the product. A product is a consumer product + regardless of whether the product has substantial commercial, + industrial or non-consumer uses, unless such uses represent the + only significant mode of use of the product. + + “Installation Information†for a User Product means any methods, + procedures, authorization keys, or other information required to + install and execute modified versions of a covered work in that + User Product from a modified version of its Corresponding Source. + The information must suffice to ensure that the continued + functioning of the modified object code is in no case prevented or + interfered with solely because modification has been made. + + If you convey an object code work under this section in, or with, + or specifically for use in, a User Product, and the conveying + occurs as part of a transaction in which the right of possession + and use of the User Product is transferred to the recipient in + perpetuity or for a fixed term (regardless of how the transaction + is characterized), the Corresponding Source conveyed under this + section must be accompanied by the Installation Information. But + this requirement does not apply if neither you nor any third party + retains the ability to install modified object code on the User + Product (for example, the work has been installed in ROM). + + The requirement to provide Installation Information does not + include a requirement to continue to provide support service, + warranty, or updates for a work that has been modified or installed + by the recipient, or for the User Product in which it has been + modified or installed. Access to a network may be denied when the + modification itself materially and adversely affects the operation + of the network or violates the rules and protocols for + communication across the network. + + Corresponding Source conveyed, and Installation Information + provided, in accord with this section must be in a format that is + publicly documented (and with an implementation available to the + public in source code form), and must require no special password + or key for unpacking, reading or copying. + + 7. Additional Terms. + + “Additional permissions†are terms that supplement the terms of + this License by making exceptions from one or more of its + conditions. Additional permissions that are applicable to the + entire Program shall be treated as though they were included in + this License, to the extent that they are valid under applicable + law. If additional permissions apply only to part of the Program, + that part may be used separately under those permissions, but the + entire Program remains governed by this License without regard to + the additional permissions. + + When you convey a copy of a covered work, you may at your option + remove any additional permissions from that copy, or from any part + of it. (Additional permissions may be written to require their own + removal in certain cases when you modify the work.) You may place + additional permissions on material, added by you to a covered work, + for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material + you add to a covered work, you may (if authorized by the copyright + holders of that material) supplement the terms of this License with + terms: + + a. Disclaiming warranty or limiting liability differently from + the terms of sections 15 and 16 of this License; or + + b. Requiring preservation of specified reasonable legal notices + or author attributions in that material or in the Appropriate + Legal Notices displayed by works containing it; or + + c. Prohibiting misrepresentation of the origin of that material, + or requiring that modified versions of such material be marked + in reasonable ways as different from the original version; or + + d. Limiting the use for publicity purposes of names of licensors + or authors of the material; or + + e. Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f. Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified + versions of it) with contractual assumptions of liability to + the recipient, for any liability that these contractual + assumptions directly impose on those licensors and authors. + + All other non-permissive additional terms are considered “further + restrictions†within the meaning of section 10. If the Program as + you received it, or any part of it, contains a notice stating that + it is governed by this License along with a term that is a further + restriction, you may remove that term. If a license document + contains a further restriction but permits relicensing or conveying + under this License, you may add to a covered work material governed + by the terms of that license document, provided that the further + restriction does not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you + must place, in the relevant source files, a statement of the + additional terms that apply to those files, or a notice indicating + where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in + the form of a separately written license, or stated as exceptions; + the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly + provided under this License. Any attempt otherwise to propagate or + modify it is void, and will automatically terminate your rights + under this License (including any patent licenses granted under the + third paragraph of section 11). + + However, if you cease all violation of this License, then your + license from a particular copyright holder is reinstated (a) + provisionally, unless and until the copyright holder explicitly and + finally terminates your license, and (b) permanently, if the + copyright holder fails to notify you of the violation by some + reasonable means prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is + reinstated permanently if the copyright holder notifies you of the + violation by some reasonable means, this is the first time you have + received notice of violation of this License (for any work) from + that copyright holder, and you cure the violation prior to 30 days + after your receipt of the notice. + + Termination of your rights under this section does not terminate + the licenses of parties who have received copies or rights from you + under this License. If your rights have been terminated and not + permanently reinstated, you do not qualify to receive new licenses + for the same material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or + run a copy of the Program. Ancillary propagation of a covered work + occurring solely as a consequence of using peer-to-peer + transmission to receive a copy likewise does not require + acceptance. However, nothing other than this License grants you + permission to propagate or modify any covered work. These actions + infringe copyright if you do not accept this License. Therefore, + by modifying or propagating a covered work, you indicate your + acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically + receives a license from the original licensors, to run, modify and + propagate that work, subject to this License. You are not + responsible for enforcing compliance by third parties with this + License. + + An “entity transaction†is a transaction transferring control of an + organization, or substantially all assets of one, or subdividing an + organization, or merging organizations. If propagation of a + covered work results from an entity transaction, each party to that + transaction who receives a copy of the work also receives whatever + licenses to the work the party’s predecessor in interest had or + could give under the previous paragraph, plus a right to possession + of the Corresponding Source of the work from the predecessor in + interest, if the predecessor has it or can get it with reasonable + efforts. + + You may not impose any further restrictions on the exercise of the + rights granted or affirmed under this License. For example, you + may not impose a license fee, royalty, or other charge for exercise + of rights granted under this License, and you may not initiate + litigation (including a cross-claim or counterclaim in a lawsuit) + alleging that any patent claim is infringed by making, using, + selling, offering for sale, or importing the Program or any portion + of it. + + 11. Patents. + + A “contributor†is a copyright holder who authorizes use under this + License of the Program or a work on which the Program is based. + The work thus licensed is called the contributor’s “contributor + versionâ€. + + A contributor’s “essential patent claims†are all patent claims + owned or controlled by the contributor, whether already acquired or + hereafter acquired, that would be infringed by some manner, + permitted by this License, of making, using, or selling its + contributor version, but do not include claims that would be + infringed only as a consequence of further modification of the + contributor version. For purposes of this definition, “control†+ includes the right to grant patent sublicenses in a manner + consistent with the requirements of this License. + + Each contributor grants you a non-exclusive, worldwide, + royalty-free patent license under the contributor’s essential + patent claims, to make, use, sell, offer for sale, import and + otherwise run, modify and propagate the contents of its contributor + version. + + In the following three paragraphs, a “patent license†is any + express agreement or commitment, however denominated, not to + enforce a patent (such as an express permission to practice a + patent or covenant not to sue for patent infringement). To “grant†+ such a patent license to a party means to make such an agreement or + commitment not to enforce a patent against the party. + + If you convey a covered work, knowingly relying on a patent + license, and the Corresponding Source of the work is not available + for anyone to copy, free of charge and under the terms of this + License, through a publicly available network server or other + readily accessible means, then you must either (1) cause the + Corresponding Source to be so available, or (2) arrange to deprive + yourself of the benefit of the patent license for this particular + work, or (3) arrange, in a manner consistent with the requirements + of this License, to extend the patent license to downstream + recipients. “Knowingly relying†means you have actual knowledge + that, but for the patent license, your conveying the covered work + in a country, or your recipient’s use of the covered work in a + country, would infringe one or more identifiable patents in that + country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or + arrangement, you convey, or propagate by procuring conveyance of, a + covered work, and grant a patent license to some of the parties + receiving the covered work authorizing them to use, propagate, + modify or convey a specific copy of the covered work, then the + patent license you grant is automatically extended to all + recipients of the covered work and works based on it. + + A patent license is “discriminatory†if it does not include within + the scope of its coverage, prohibits the exercise of, or is + conditioned on the non-exercise of one or more of the rights that + are specifically granted under this License. You may not convey a + covered work if you are a party to an arrangement with a third + party that is in the business of distributing software, under which + you make payment to the third party based on the extent of your + activity of conveying the work, and under which the third party + grants, to any of the parties who would receive the covered work + from you, a discriminatory patent license (a) in connection with + copies of the covered work conveyed by you (or copies made from + those copies), or (b) primarily for and in connection with specific + products or compilations that contain the covered work, unless you + entered into that arrangement, or that patent license was granted, + prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting + any implied license or other defenses to infringement that may + otherwise be available to you under applicable patent law. + + 12. No Surrender of Others’ Freedom. + + If conditions are imposed on you (whether by court order, agreement + or otherwise) that contradict the conditions of this License, they + do not excuse you from the conditions of this License. If you + cannot convey a covered work so as to satisfy simultaneously your + obligations under this License and any other pertinent obligations, + then as a consequence you may not convey it at all. For example, + if you agree to terms that obligate you to collect a royalty for + further conveying from those to whom you convey the Program, the + only way you could satisfy both those terms and this License would + be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have + permission to link or combine any covered work with a work licensed + under version 3 of the GNU Affero General Public License into a + single combined work, and to convey the resulting work. The terms + of this License will continue to apply to the part which is the + covered work, but the special requirements of the GNU Affero + General Public License, section 13, concerning interaction through + a network will apply to the combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new + versions of the GNU General Public License from time to time. Such + new versions will be similar in spirit to the present version, but + may differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the + Program specifies that a certain numbered version of the GNU + General Public License “or any later version†applies to it, you + have the option of following the terms and conditions either of + that numbered version or of any later version published by the Free + Software Foundation. If the Program does not specify a version + number of the GNU General Public License, you may choose any + version ever published by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future + versions of the GNU General Public License can be used, that + proxy’s public statement of acceptance of a version permanently + authorizes you to choose that version for the Program. + + Later license versions may give you additional or different + permissions. However, no additional obligations are imposed on any + author or copyright holder as a result of your choosing to follow a + later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY + APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE + COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS†+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE + RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. + SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL + NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN + WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES + AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR + DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR + CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE + THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA + BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD + PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER + PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF + THE POSSIBILITY OF SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided + above cannot be given local legal effect according to their terms, + reviewing courts shall apply local law that most closely + approximates an absolute waiver of all civil liability in + connection with the Program, unless a warranty or assumption of + liability accompanies a copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS +=========================== + +How to Apply These Terms to Your New Programs +============================================= + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least the +“copyright†line and a pointer to where the full notice is found. + + ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES. + Copyright (C) YEAR NAME OF AUTHOR + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + + Also add information on how to contact you by electronic and paper +mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + PROGRAM Copyright (C) YEAR NAME OF AUTHOR + This program comes with ABSOLUTELY NO WARRANTY; for details type ‘show w’. + This is free software, and you are welcome to redistribute it + under certain conditions; type ‘show c’ for details. + + The hypothetical commands ‘show w’ and ‘show c’ should show the +appropriate parts of the General Public License. Of course, your +program’s commands might be different; for a GUI interface, you would +use an “about boxâ€. + + You should also get your employer (if you work as a programmer) or +school, if any, to sign a “copyright disclaimer†for the program, if +necessary. For more information on this, and how to apply and follow +the GNU GPL, see <https://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your +program into proprietary programs. If your program is a subroutine +library, you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use the +GNU Lesser General Public License instead of this License. But first, +please read <https://www.gnu.org/licenses/why-not-lgpl.html>. + + +File: dash.info, Node: Index, Prev: GPL, Up: Top + +Index +***** + + +* Menu: + +* !cdr: Destructive operations. + (line 16) +* !cons: Destructive operations. + (line 8) +* -->: Threading macros. (line 35) +* ->: Threading macros. (line 9) +* ->>: Threading macros. (line 22) +* -all?: Predicates. (line 53) +* -andfn: Function combinators. + (line 184) +* -annotate: Maps. (line 84) +* -any?: Predicates. (line 41) +* -applify: Function combinators. + (line 63) +* -as->: Threading macros. (line 49) +* -butlast: Other list operations. + (line 335) +* -clone: Tree operations. (line 122) +* -common-prefix: Reductions. (line 242) +* -common-suffix: Reductions. (line 252) +* -compose: Function combinators. + (line 49) +* -concat: List to list. (line 23) +* -cons*: Other list operations. + (line 30) +* -cons-pair?: Predicates. (line 167) +* -const: Function combinators. + (line 128) +* -contains?: Predicates. (line 100) +* -copy: Maps. (line 139) +* -count: Reductions. (line 172) +* -cut: Function combinators. + (line 140) +* -cycle: Other list operations. + (line 180) +* -difference: Set operations. (line 20) +* -distinct: Set operations. (line 62) +* -dotimes: Side effects. (line 80) +* -doto: Threading macros. (line 99) +* -drop: Sublist selection. (line 147) +* -drop-last: Sublist selection. (line 161) +* -drop-while: Sublist selection. (line 192) +* -each: Side effects. (line 8) +* -each-indexed: Side effects. (line 38) +* -each-r: Side effects. (line 52) +* -each-r-while: Side effects. (line 65) +* -each-while: Side effects. (line 24) +* -elem-index: Indexing. (line 9) +* -elem-indices: Indexing. (line 21) +* -every: Predicates. (line 23) +* -fifth-item: Other list operations. + (line 315) +* -filter: Sublist selection. (line 8) +* -find-index: Indexing. (line 32) +* -find-indices: Indexing. (line 60) +* -find-last-index: Indexing. (line 46) +* -first: Other list operations. + (line 246) +* -first-item: Other list operations. + (line 272) +* -fix: Other list operations. + (line 375) +* -fixfn: Function combinators. + (line 224) +* -flatten: List to list. (line 34) +* -flatten-n: List to list. (line 56) +* -flip: Function combinators. + (line 95) +* -fourth-item: Other list operations. + (line 305) +* -grade-down: Indexing. (line 81) +* -grade-up: Indexing. (line 71) +* -group-by: Partitioning. (line 194) +* -if-let: Binding. (line 34) +* -if-let*: Binding. (line 45) +* -inits: Reductions. (line 222) +* -insert-at: List to list. (line 110) +* -interleave: Other list operations. + (line 67) +* -interpose: Other list operations. + (line 57) +* -intersection: Set operations. (line 32) +* -iota: Other list operations. + (line 78) +* -is-infix?: Predicates. (line 153) +* -is-prefix?: Predicates. (line 129) +* -is-suffix?: Predicates. (line 141) +* -iterate: Unfolding. (line 9) +* -iteratefn: Function combinators. + (line 201) +* -juxt: Function combinators. + (line 37) +* -keep: List to list. (line 8) +* -lambda: Binding. (line 247) +* -last: Other list operations. + (line 262) +* -last-item: Other list operations. + (line 325) +* -let: Binding. (line 61) +* -let*: Binding. (line 227) +* -list: Other list operations. + (line 358) +* -map: Maps. (line 10) +* -map-first: Maps. (line 38) +* -map-indexed: Maps. (line 66) +* -map-last: Maps. (line 52) +* -map-when: Maps. (line 22) +* -mapcat: Maps. (line 128) +* -max: Reductions. (line 286) +* -max-by: Reductions. (line 296) +* -min: Reductions. (line 262) +* -min-by: Reductions. (line 272) +* -non-nil: Sublist selection. (line 94) +* -none?: Predicates. (line 73) +* -not: Function combinators. + (line 153) +* -on: Function combinators. + (line 75) +* -only-some?: Predicates. (line 85) +* -orfn: Function combinators. + (line 167) +* -pad: Other list operations. + (line 191) +* -partial: Function combinators. + (line 8) +* -partition: Partitioning. (line 80) +* -partition-after-item: Partitioning. (line 184) +* -partition-after-pred: Partitioning. (line 151) +* -partition-all: Partitioning. (line 92) +* -partition-all-in-steps: Partitioning. (line 115) +* -partition-before-item: Partitioning. (line 174) +* -partition-before-pred: Partitioning. (line 163) +* -partition-by: Partitioning. (line 127) +* -partition-by-header: Partitioning. (line 138) +* -partition-in-steps: Partitioning. (line 103) +* -permutations: Set operations. (line 52) +* -powerset: Set operations. (line 44) +* -prodfn: Function combinators. + (line 258) +* -product: Reductions. (line 201) +* -reduce: Reductions. (line 53) +* -reduce-from: Reductions. (line 8) +* -reduce-r: Reductions. (line 72) +* -reduce-r-from: Reductions. (line 26) +* -reductions: Reductions. (line 136) +* -reductions-from: Reductions. (line 100) +* -reductions-r: Reductions. (line 154) +* -reductions-r-from: Reductions. (line 118) +* -remove: Sublist selection. (line 26) +* -remove-at: List to list. (line 146) +* -remove-at-indices: List to list. (line 159) +* -remove-first: Sublist selection. (line 43) +* -remove-item: Sublist selection. (line 83) +* -remove-last: Sublist selection. (line 64) +* -repeat: Other list operations. + (line 19) +* -replace: List to list. (line 68) +* -replace-at: List to list. (line 121) +* -replace-first: List to list. (line 82) +* -replace-last: List to list. (line 96) +* -rotate: Other list operations. + (line 8) +* -rotate-args: Function combinators. + (line 112) +* -rpartial: Function combinators. + (line 22) +* -running-product: Reductions. (line 211) +* -running-sum: Reductions. (line 190) +* -same-items?: Predicates. (line 115) +* -second-item: Other list operations. + (line 285) +* -select-by-indices: Sublist selection. (line 208) +* -select-column: Sublist selection. (line 238) +* -select-columns: Sublist selection. (line 219) +* -separate: Partitioning. (line 69) +* -setq: Binding. (line 270) +* -slice: Sublist selection. (line 104) +* -snoc: Other list operations. + (line 43) +* -some: Predicates. (line 8) +* -some-->: Threading macros. (line 86) +* -some->: Threading macros. (line 62) +* -some->>: Threading macros. (line 74) +* -sort: Other list operations. + (line 345) +* -splice: Maps. (line 95) +* -splice-list: Maps. (line 115) +* -split-at: Partitioning. (line 8) +* -split-on: Partitioning. (line 34) +* -split-when: Partitioning. (line 52) +* -split-with: Partitioning. (line 23) +* -sum: Reductions. (line 180) +* -table: Other list operations. + (line 202) +* -table-flat: Other list operations. + (line 221) +* -tails: Reductions. (line 232) +* -take: Sublist selection. (line 120) +* -take-last: Sublist selection. (line 133) +* -take-while: Sublist selection. (line 175) +* -third-item: Other list operations. + (line 295) +* -tree-map: Tree operations. (line 28) +* -tree-map-nodes: Tree operations. (line 39) +* -tree-mapreduce: Tree operations. (line 84) +* -tree-mapreduce-from: Tree operations. (line 103) +* -tree-reduce: Tree operations. (line 52) +* -tree-reduce-from: Tree operations. (line 69) +* -tree-seq: Tree operations. (line 8) +* -unfold: Unfolding. (line 25) +* -union: Set operations. (line 8) +* -unzip: Other list operations. + (line 158) +* -update-at: List to list. (line 133) +* -when-let: Binding. (line 9) +* -when-let*: Binding. (line 21) +* -zip: Other list operations. + (line 107) +* -zip-fill: Other list operations. + (line 150) +* -zip-lists: Other list operations. + (line 131) +* -zip-with: Other list operations. + (line 91) +* dash-fontify-mode: Fontification of special variables. + (line 6) +* dash-register-info-lookup: Info symbol lookup. (line 6) +* global-dash-fontify-mode: Fontification of special variables. + (line 12) + + + +Tag Table: +Node: Top742 +Node: Installation2397 +Node: Using in a package3159 +Node: Fontification of special variables3504 +Node: Info symbol lookup4294 +Node: Functions4877 +Node: Maps6361 +Ref: -map6658 +Ref: -map-when7031 +Ref: -map-first7606 +Ref: -map-last8081 +Ref: -map-indexed8551 +Ref: -annotate9237 +Ref: -splice9724 +Ref: -splice-list10502 +Ref: -mapcat10961 +Ref: -copy11334 +Node: Sublist selection11522 +Ref: -filter11715 +Ref: -remove12262 +Ref: -remove-first12800 +Ref: -remove-last13642 +Ref: -remove-item14367 +Ref: -non-nil14767 +Ref: -slice15043 +Ref: -take15572 +Ref: -take-last15979 +Ref: -drop16410 +Ref: -drop-last16851 +Ref: -take-while17277 +Ref: -drop-while17892 +Ref: -select-by-indices18508 +Ref: -select-columns19019 +Ref: -select-column19722 +Node: List to list20185 +Ref: -keep20377 +Ref: -concat20941 +Ref: -flatten21235 +Ref: -flatten-n21991 +Ref: -replace22375 +Ref: -replace-first22836 +Ref: -replace-last23331 +Ref: -insert-at23819 +Ref: -replace-at24144 +Ref: -update-at24531 +Ref: -remove-at25019 +Ref: -remove-at-indices25504 +Node: Reductions26083 +Ref: -reduce-from26279 +Ref: -reduce-r-from27003 +Ref: -reduce28266 +Ref: -reduce-r29017 +Ref: -reductions-from30295 +Ref: -reductions-r-from31101 +Ref: -reductions31931 +Ref: -reductions-r32642 +Ref: -count33387 +Ref: -sum33611 +Ref: -running-sum33799 +Ref: -product34120 +Ref: -running-product34328 +Ref: -inits34669 +Ref: -tails34914 +Ref: -common-prefix35158 +Ref: -common-suffix35452 +Ref: -min35746 +Ref: -min-by35972 +Ref: -max36493 +Ref: -max-by36718 +Node: Unfolding37244 +Ref: -iterate37485 +Ref: -unfold37932 +Node: Predicates38737 +Ref: -some38914 +Ref: -every39331 +Ref: -any?40010 +Ref: -all?40341 +Ref: -none?41048 +Ref: -only-some?41350 +Ref: -contains?41835 +Ref: -same-items?42224 +Ref: -is-prefix?42609 +Ref: -is-suffix?42935 +Ref: -is-infix?43261 +Ref: -cons-pair?43615 +Node: Partitioning43940 +Ref: -split-at44128 +Ref: -split-with44792 +Ref: -split-on45192 +Ref: -split-when45863 +Ref: -separate46500 +Ref: -partition46939 +Ref: -partition-all47388 +Ref: -partition-in-steps47813 +Ref: -partition-all-in-steps48307 +Ref: -partition-by48789 +Ref: -partition-by-header49167 +Ref: -partition-after-pred49768 +Ref: -partition-before-pred50215 +Ref: -partition-before-item50600 +Ref: -partition-after-item50907 +Ref: -group-by51209 +Node: Indexing51642 +Ref: -elem-index51844 +Ref: -elem-indices52239 +Ref: -find-index52619 +Ref: -find-last-index53108 +Ref: -find-indices53612 +Ref: -grade-up54017 +Ref: -grade-down54424 +Node: Set operations54838 +Ref: -union55021 +Ref: -difference55459 +Ref: -intersection55871 +Ref: -powerset56303 +Ref: -permutations56513 +Ref: -distinct56809 +Node: Other list operations57183 +Ref: -rotate57408 +Ref: -repeat57761 +Ref: -cons*58040 +Ref: -snoc58456 +Ref: -interpose58866 +Ref: -interleave59160 +Ref: -iota59526 +Ref: -zip-with60009 +Ref: -zip60723 +Ref: -zip-lists61552 +Ref: -zip-fill62250 +Ref: -unzip62572 +Ref: -cycle63314 +Ref: -pad63713 +Ref: -table64032 +Ref: -table-flat64818 +Ref: -first65823 +Ref: -last66309 +Ref: -first-item66643 +Ref: -second-item67042 +Ref: -third-item67306 +Ref: -fourth-item67568 +Ref: -fifth-item67834 +Ref: -last-item68096 +Ref: -butlast68387 +Ref: -sort68632 +Ref: -list69118 +Ref: -fix69687 +Node: Tree operations70176 +Ref: -tree-seq70372 +Ref: -tree-map71227 +Ref: -tree-map-nodes71667 +Ref: -tree-reduce72514 +Ref: -tree-reduce-from73396 +Ref: -tree-mapreduce73996 +Ref: -tree-mapreduce-from74855 +Ref: -clone76140 +Node: Threading macros76467 +Ref: ->76692 +Ref: ->>77180 +Ref: -->77683 +Ref: -as->78239 +Ref: -some->78693 +Ref: -some->>79066 +Ref: -some-->79501 +Ref: -doto80050 +Node: Binding80603 +Ref: -when-let80810 +Ref: -when-let*81265 +Ref: -if-let81788 +Ref: -if-let*82148 +Ref: -let82765 +Ref: -let*88837 +Ref: -lambda89774 +Ref: -setq90580 +Node: Side effects91381 +Ref: -each91575 +Ref: -each-while92096 +Ref: -each-indexed92698 +Ref: -each-r93284 +Ref: -each-r-while93720 +Ref: -dotimes94346 +Node: Destructive operations94899 +Ref: !cons95117 +Ref: !cdr95321 +Node: Function combinators95514 +Ref: -partial95718 +Ref: -rpartial96236 +Ref: -juxt96884 +Ref: -compose97336 +Ref: -applify97943 +Ref: -on98373 +Ref: -flip99145 +Ref: -rotate-args99669 +Ref: -const100298 +Ref: -cut100640 +Ref: -not101120 +Ref: -orfn101646 +Ref: -andfn102408 +Ref: -iteratefn103164 +Ref: -fixfn103866 +Ref: -prodfn105422 +Node: Development106480 +Node: Contribute106769 +Node: Contributors107781 +Node: FDL109874 +Node: GPL135194 +Node: Index172943 + +End Tag Table + + +Local Variables: +coding: utf-8 +End: diff --git a/emacs.d/elpa/dash-20210708.2009/dir b/emacs.d/elpa/dash-20210708.2009/dir new file mode 100644 index 0000000..7d473f4 --- /dev/null +++ b/emacs.d/elpa/dash-20210708.2009/dir @@ -0,0 +1,18 @@ +This is the file .../info/dir, which contains the +topmost node of the Info hierarchy, called (dir)Top. +The first time you invoke Info you start off looking at this node. + +File: dir, Node: Top This is the top of the INFO tree + + This (the Directory node) gives a menu of major topics. + Typing "q" exits, "H" lists all Info commands, "d" returns here, + "h" gives a primer for first-timers, + "mEmacs<Return>" visits the Emacs manual, etc. + + In Emacs, you can click mouse button 2 on a menu item or cross reference + to select it. + +* Menu: + +Emacs +* Dash: (dash.info). A modern list library for GNU Emacs. diff --git a/emacs.d/elpa/ht-20210119.741/ht-autoloads.el b/emacs.d/elpa/ht-20210119.741/ht-autoloads.el new file mode 100644 index 0000000..c860d46 --- /dev/null +++ b/emacs.d/elpa/ht-20210119.741/ht-autoloads.el @@ -0,0 +1,22 @@ +;;; ht-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "ht" "ht.el" (0 0 0 0)) +;;; Generated autoloads from ht.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "ht" 'nil)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; ht-autoloads.el ends here diff --git a/emacs.d/elpa/ht-20210119.741/ht-pkg.el b/emacs.d/elpa/ht-20210119.741/ht-pkg.el new file mode 100644 index 0000000..15125c7 --- /dev/null +++ b/emacs.d/elpa/ht-20210119.741/ht-pkg.el @@ -0,0 +1,2 @@ +;;; Generated package description from ht-20210119.741/ht.el -*- no-byte-compile: t -*- +(define-package "ht" "20210119.741" "The missing hash table library for Emacs" '((dash "2.12.0")) :commit "c4c1be487d6ecb353d07881526db05d7fc90ea87" :authors '(("Wilfred Hughes" . "me@wilfred.me.uk")) :maintainer '("Wilfred Hughes" . "me@wilfred.me.uk") :keywords '("hash table" "hash map" "hash")) diff --git a/emacs.d/elpa/ht-20210119.741/ht.el b/emacs.d/elpa/ht-20210119.741/ht.el new file mode 100644 index 0000000..0809ef1 --- /dev/null +++ b/emacs.d/elpa/ht-20210119.741/ht.el @@ -0,0 +1,337 @@ +;;; ht.el --- The missing hash table library for Emacs -*- lexical-binding: t; -*- + +;; Copyright (C) 2013 Wilfred Hughes + +;; Author: Wilfred Hughes <me@wilfred.me.uk> +;; Version: 2.4 +;; Package-Version: 20210119.741 +;; Package-Commit: c4c1be487d6ecb353d07881526db05d7fc90ea87 +;; Keywords: hash table, hash map, hash +;; Package-Requires: ((dash "2.12.0")) + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; The missing hash table library for Emacs. +;; +;; See documentation at https://github.com/Wilfred/ht.el + +;;; Code: + +(require 'dash) +(require 'gv) +(eval-when-compile + (require 'inline)) + +(defmacro ht (&rest pairs) + "Create a hash table with the key-value pairs given. +Keys are compared with `equal'. + +\(fn (KEY-1 VALUE-1) (KEY-2 VALUE-2) ...)" + (let* ((table-symbol (make-symbol "ht-temp")) + (assignments + (mapcar + (lambda (pair) `(ht-set! ,table-symbol ,@pair)) + pairs))) + `(let ((,table-symbol (ht-create))) + ,@assignments + ,table-symbol))) + +(define-inline ht-set! (table key value) + "Associate KEY in TABLE with VALUE." + (inline-quote + (prog1 nil + (puthash ,key ,value ,table)))) + +(defalias 'ht-set 'ht-set!) + +(define-inline ht-create (&optional test) + "Create an empty hash table. + +TEST indicates the function used to compare the hash +keys. Default is `equal'. It can be `eq', `eql', `equal' or a +user-supplied test created via `define-hash-table-test'." + (declare (side-effect-free t)) + (inline-quote (make-hash-table :test (or ,test 'equal)))) + +(defun ht<-alist (alist &optional test) + "Create a hash table with initial values according to ALIST. + +TEST indicates the function used to compare the hash +keys. Default is `equal'. It can be `eq', `eql', `equal' or a +user-supplied test created via `define-hash-table-test'." + (declare (side-effect-free t)) + (let ((h (ht-create test))) + ;; the first key-value pair in an alist gets precedence, so we + ;; start from the end of the list: + (dolist (pair (reverse alist) h) + (let ((key (car pair)) + (value (cdr pair))) + (ht-set! h key value))))) + +(defalias 'ht-from-alist 'ht<-alist) + +(defun ht<-plist (plist &optional test) + "Create a hash table with initial values according to PLIST. + +TEST indicates the function used to compare the hash +keys. Default is `equal'. It can be `eq', `eql', `equal' or a +user-supplied test created via `define-hash-table-test'." + (declare (side-effect-free t)) + (let ((h (ht-create test))) + (dolist (pair (nreverse (-partition 2 plist)) h) + (let ((key (car pair)) + (value (cadr pair))) + (ht-set! h key value))))) + +(defalias 'ht-from-plist 'ht<-plist) + +(define-inline ht-get (table key &optional default) + "Look up KEY in TABLE, and return the matching value. +If KEY isn't present, return DEFAULT (nil if not specified)." + (declare (side-effect-free t)) + (inline-quote + (gethash ,key ,table ,default))) + +;; Don't use `ht-set!' here, gv setter was assumed to return the value +;; to be set. +(gv-define-setter ht-get (value table key) `(puthash ,key ,value ,table)) + +(define-inline ht-get* (table &rest keys) + "Look up KEYS in nested hash tables, starting with TABLE. +The lookup for each key should return another hash table, except +for the final key, which may return any value." + (declare (side-effect-free t)) + (inline-letevals (table keys) + (inline-quote + (progn + (while ,keys + (setf ,table (ht-get ,table (pop ,keys)))) + ,table)))) + +(put 'ht-get* 'compiler-macro + (lambda (_ table &rest keys) + (--reduce-from `(ht-get ,acc ,it) table keys))) + +(defun ht-update! (table from-table) + "Update TABLE according to every key-value pair in FROM-TABLE." + (maphash + (lambda (key value) (puthash key value table)) + from-table) + nil) + +(defalias 'ht-update 'ht-update!) + +(defun ht-merge (&rest tables) + "Crete a new tables that includes all the key-value pairs from TABLES. +If multiple have tables have the same key, the value in the last +table is used." + (let ((merged (ht-create))) + (mapc (lambda (table) (ht-update! merged table)) tables) + merged)) + +(define-inline ht-remove! (table key) + "Remove KEY from TABLE." + (inline-quote (remhash ,key ,table))) + +(defalias 'ht-remove 'ht-remove!) + +(define-inline ht-clear! (table) + "Remove all keys from TABLE." + (inline-quote + (prog1 nil + (clrhash ,table)))) + +(defalias 'ht-clear 'ht-clear!) + +(defun ht-map (function table) + "Apply FUNCTION to each key-value pair of TABLE, and make a list of the results. +FUNCTION is called with two arguments, KEY and VALUE." + (let (results) + (maphash + (lambda (key value) + (push (funcall function key value) results)) + table) + results)) + +(defmacro ht-amap (form table) + "Anaphoric version of `ht-map'. +For every key-value pair in TABLE, evaluate FORM with the +variables KEY and VALUE bound. If you don't use both of +these variables, then use `ht-map' to avoid warnings." + `(ht-map (lambda (key value) ,form) ,table)) + +(defun ht-keys (table) + "Return a list of all the keys in TABLE." + (declare (side-effect-free t)) + (ht-map (lambda (key _value) key) table)) + +(defun ht-values (table) + "Return a list of all the values in TABLE." + (declare (side-effect-free t)) + (ht-map (lambda (_key value) value) table)) + +(defun ht-items (table) + "Return a list of two-element lists '(key value) from TABLE." + (declare (side-effect-free t)) + (ht-amap (list key value) table)) + +(defalias 'ht-each 'maphash + "Apply FUNCTION to each key-value pair of TABLE. +Returns nil, used for side-effects only.") + +(defmacro ht-aeach (form table) + "Anaphoric version of `ht-each'. +For every key-value pair in TABLE, evaluate FORM with the +variables key and value bound." + `(ht-each (lambda (key value) ,form) ,table)) + +(defun ht-select-keys (table keys) + "Return a copy of TABLE with only the specified KEYS." + (declare (side-effect-free t)) + (let (result) + (setq result (make-hash-table :test (hash-table-test table))) + (dolist (key keys result) + (if (not (equal (gethash key table 'key-not-found) 'key-not-found)) + (puthash key (gethash key table) result))))) + +(defun ht->plist (table) + "Return a flat list '(key1 value1 key2 value2...) from TABLE. + +Note that hash tables are unordered, so this cannot be an exact +inverse of `ht<-plist'. The following is not guaranteed: + +\(let ((data '(a b c d))) + (equalp data + (ht->plist (ht<-plist data))))" + (declare (side-effect-free t)) + (apply 'append (ht-items table))) + +(defalias 'ht-to-plist 'ht->plist) + +(define-inline ht-copy (table) + "Return a shallow copy of TABLE (keys and values are shared)." + (declare (side-effect-free t)) + (inline-quote (copy-hash-table ,table))) + +(defun ht->alist (table) + "Return a list of two-element lists '(key . value) from TABLE. + +Note that hash tables are unordered, so this cannot be an exact +inverse of `ht<-alist'. The following is not guaranteed: + +\(let ((data '((a . b) (c . d)))) + (equalp data + (ht->alist (ht<-alist data))))" + (declare (side-effect-free t)) + (ht-amap (cons key value) table)) + +(defalias 'ht-to-alist 'ht->alist) + +(defalias 'ht? 'hash-table-p) + +(defalias 'ht-p 'hash-table-p) + +(define-inline ht-contains? (table key) + "Return 't if TABLE contains KEY." + (declare (side-effect-free t)) + (inline-quote + (let ((not-found-symbol (make-symbol "ht--not-found"))) + (not (eq (ht-get ,table ,key not-found-symbol) not-found-symbol))))) + +(defalias 'ht-contains-p 'ht-contains?) + +(define-inline ht-size (table) + "Return the actual number of entries in TABLE." + (declare (side-effect-free t)) + (inline-quote + (hash-table-count ,table))) + +(define-inline ht-empty? (table) + "Return true if the actual number of entries in TABLE is zero." + (declare (side-effect-free t)) + (inline-quote + (zerop (ht-size ,table)))) + +(defalias 'ht-empty-p 'ht-empty?) + +(defun ht-select (function table) + "Return a hash table containing all entries in TABLE for which +FUNCTION returns a truthy value. + +FUNCTION is called with two arguments, KEY and VALUE." + (let ((results (ht-create))) + (ht-each + (lambda (key value) + (when (funcall function key value) + (ht-set! results key value))) + table) + results)) + +(defun ht-reject (function table) + "Return a hash table containing all entries in TABLE for which +FUNCTION returns a falsy value. + +FUNCTION is called with two arguments, KEY and VALUE." + (let ((results (ht-create))) + (ht-each + (lambda (key value) + (unless (funcall function key value) + (ht-set! results key value))) + table) + results)) + +(defun ht-reject! (function table) + "Delete entries from TABLE for which FUNCTION returns a falsy value. + +FUNCTION is called with two arguments, KEY and VALUE." + (ht-each + (lambda (key value) + (when (funcall function key value) + (remhash key table))) + table) + nil) + +(defalias 'ht-delete-if 'ht-reject!) + +(defun ht-find (function table) + "Return (key, value) from TABLE for which FUNCTION returns a truthy value. +Return nil otherwise. + +FUNCTION is called with two arguments, KEY and VALUE." + (catch 'break + (ht-each + (lambda (key value) + (when (funcall function key value) + (throw 'break (list key value)))) + table))) + +(defun ht-equal? (table1 table2) + "Return t if TABLE1 and TABLE2 have the same keys and values. +Does not compare equality predicates." + (declare (side-effect-free t)) + (let ((keys1 (ht-keys table1)) + (keys2 (ht-keys table2)) + (sentinel (make-symbol "ht-sentinel"))) + (and (equal (length keys1) (length keys2)) + (--all? + (equal (ht-get table1 it) + (ht-get table2 it sentinel)) + keys1)))) + +(defalias 'ht-equal-p 'ht-equal?) + +(provide 'ht) +;;; ht.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-actionscript.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-actionscript.el new file mode 100644 index 0000000..6e368dc --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-actionscript.el @@ -0,0 +1,134 @@ +;;; lsp-actionscript.el --- ActionScript Client settings -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 Jen-Chieh Shen + +;; Author: Jen-Chieh Shen <jcs090218@gmail.com> +;; Keywords: actionscript lsp + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP client for ActionScript + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-actionscript nil + "LSP support for ActionScript." + :group 'lsp-mode + :link '(url-link "https://github.com/BowlerHatLLC/vscode-as3mxml") + :package-version `(lsp-mode . "7.1.0")) + +(defcustom lsp-actionscript-java-path "java" + "Path of the java executable." + :group 'lsp-actionscript + :type 'string) + +(defcustom lsp-actionscript-sdk-path "" + "Path to supported SDK. +See https://github.com/BowlerHatLLC/vscode-as3mxml/wiki/Choose-an-ActionScript-SDK-for-the-current-workspace-in-Visual-Studio-Code." + :type 'string + :group 'lsp-actionscript + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-actionscript-version "1.5.0" + "Version of ActionScript language server." + :type 'string + :group 'lsp-actionscript + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-actionscript-extension-name + (format "vscode-nextgenas-%s.vsix" lsp-actionscript-version) + "File name of the extension file from language server." + :type 'string + :group 'lsp-actionscript + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-actionscript-server-download-url + (format "https://github.com/BowlerHatLLC/vscode-as3mxml/releases/download/v%s/%s" + lsp-actionscript-version lsp-actionscript-extension-name) + "Automatic download url for lsp-actionscript." + :type 'string + :group 'lsp-actionscript + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-actionscript-server-store-path + (f-join lsp-server-install-dir "as3mxml") + "The path to the file in which `lsp-actionscript' will be stored." + :type 'file + :group 'lsp-actionscript + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-actionscript-option-charset "UTF8" + "The charset to use by the ActionScript Language server." + :type 'string + :group 'lsp-actionscript + :package-version '(lsp-mode . "7.1.0")) + +(defun lsp-actionscript--extension-root () + "The path that the downloaded extension will extract to." + (f-join lsp-actionscript-server-store-path + (format "vscode-nextgenas-%s" lsp-actionscript-version))) + +(defun lsp-actionscript--extension-path () + "Return full path of the downloaded extension." + (f-join lsp-actionscript-server-store-path lsp-actionscript-extension-name)) + +(defun lsp-actionscript--extension-dir () + "Return as3mxml extension path." + (f-join (lsp-actionscript--extension-root) "extension")) + +(defun lsp-actionscript--server-command () + "Startup command for ActionScript language server." + (list lsp-actionscript-java-path + (format "-Droyalelib=%s" lsp-actionscript-sdk-path) + (format "-Dfile.encoding=%s" lsp-actionscript-option-charset) + "-cp" + (format "%s/bundled-compiler/*;%s/bin/*" + (lsp-actionscript--extension-dir) (lsp-actionscript--extension-dir)) + "com.as3mxml.vscode.Main")) + +(defun lsp-actionscript--extension-path-zip () + "Change extension path from .vsix to .zip." + (concat (f-no-ext (lsp-actionscript--extension-path)) ".zip")) + +(lsp-dependency + 'as3mxml + '(:system "as3mxml") + `(:download :url lsp-actionscript-server-download-url + :store-path ,(lsp-actionscript--extension-path-zip))) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection + #'lsp-actionscript--server-command + (lambda () (f-exists? (lsp-actionscript--extension-path-zip)))) + :major-modes '(actionscript-mode) + :priority -1 + :server-id 'as3mxml-ls + :download-server-fn (lambda (_client _callback error-callback _update?) + (lsp-package-ensure + 'as3mxml + (lambda () + ;; TODO: Error handling when unzip failed + (lsp-unzip (lsp-actionscript--extension-path-zip) + (lsp-actionscript--extension-root))) + error-callback)))) + +(lsp-consistency-check lsp-actionscript) + +(provide 'lsp-actionscript) +;;; lsp-actionscript.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-ada.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-ada.el new file mode 100644 index 0000000..9b105b3 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-ada.el @@ -0,0 +1,74 @@ +;;; lsp-ada.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, ada + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the Ada Programming Language + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-ada nil + "Settings for Ada Language Server." + :group 'tools + :tag "Language Server" + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-ada-project-file "default.gpr" + "Set the project file full path to configure the language server with. + The ~ prefix (for the user home directory) is supported. + See https://github.com/AdaCore/ada_language_server for a per-project + configuration example." + :type 'string + :group 'lsp-ada + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-ada-option-charset "UTF-8" + "The charset to use by the Ada Language server. Defaults to 'UTF-8'." + :type 'string + :group 'lsp-ada + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-ada-enable-diagnostics t + "A boolean to disable diagnostics. Defaults to true." + :type 'boolean + :group 'lsp-ada + :package-version '(lsp-mode . "6.2")) + +(lsp-register-custom-settings + '(("ada.projectFile" lsp-ada-project-file) + ("ada.enableDiagnostics" lsp-ada-enable-diagnostics) + ("ada.defaultCharset" lsp-ada-option-charset))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection '("ada_language_server")) + :major-modes '(ada-mode) + :priority -1 + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration + (lsp-configuration-section "ada")))) + :server-id 'ada-ls)) + +(lsp-consistency-check lsp-ada) + +(provide 'lsp-ada) +;;; lsp-ada.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-angular.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-angular.el new file mode 100644 index 0000000..65a021a --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-angular.el @@ -0,0 +1,82 @@ +;;; lsp-angular.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the Angular Web application framework. + +;;; Code: + +(require 'lsp-mode) +(require 'f) + + +;;; Angular +(defgroup lsp-angular nil + "Angular LSP client, provided by the Angular Language Service Server." + :group 'lsp-mode + :version "7.1" + :link '(url-link "https://github.com/angular/vscode-ng-language-service")) + +(defcustom lsp-clients-angular-language-server-command + nil + "The command that starts the angular language server." + :group 'lsp-angular + :type '(choice + (string :tag "Single string value") + (repeat :tag "List of string values" + string))) + +(defun lsp-client--angular-start-loading (_workspace params) + (lsp--info "Started loading project %s" params)) + +(defun lsp-client--angular-finished-loading (_workspace params) + (lsp--info "Finished loading project %s" params)) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (lambda () (if lsp-clients-angular-language-server-command + lsp-clients-angular-language-server-command + (let ((node-modules-path + (concat (string-trim (shell-command-to-string "npm config get --global prefix")) + "/lib/node_modules"))) + (list + "node" + (concat node-modules-path "/@angular/language-server") + "--ngProbeLocations" + node-modules-path + "--tsProbeLocations" + node-modules-path + "--stdio"))))) + :activation-fn (lambda (&rest _args) + (and (string-match-p "\\(\\.html\\|\\.ts\\)\\'" (buffer-file-name)) + (lsp-workspace-root) + (file-exists-p (f-join (lsp-workspace-root) "angular.json")))) + :priority -1 + :notification-handlers (ht ("angular/projectLoadingStart" #'lsp-client--angular-start-loading) + ("angular/projectLoadingFinish" #'lsp-client--angular-finished-loading)) + :add-on? t + :server-id 'angular-ls)) + + +(lsp-consistency-check lsp-angular) + +(provide 'lsp-angular) +;;; lsp-angular.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-bash.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-bash.el new file mode 100644 index 0000000..ee8a28e --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-bash.el @@ -0,0 +1,90 @@ +;;; lsp-bash.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, bash, shell-script + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the Bash Programming Language + +;;; Code: + +(require 'lsp-mode) + +;;; Bash +(defgroup lsp-bash nil + "Settings for the Bash Language Server." + :group 'lsp-mode + :link '(url-link "https://github.com/bash-lsp/bash-language-server") + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-bash-explainshell-endpoint nil + "The endpoint to use explainshell.com to answer 'onHover' queries. +See instructions at https://marketplace.visualstudio.com/items?itemName=mads-hartmann.bash-ide-vscode" + :type 'string + :risky t + :group 'lsp-bash + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-bash-highlight-parsing-errors nil + "Consider parsing errors in scripts as 'problems'." + :type 'boolean + :group 'lsp-bash + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-bash-glob-pattern nil + "Glob pattern used to find shell script files to parse." + :type 'string + :group 'lsp-bash + :package-version '(lsp-mode . "6.3")) + +(defun lsp-bash--bash-ls-server-command () + "Startup command for Bash language server." + (list (lsp-package-path 'bash-language-server) "start")) + +(lsp-dependency 'bash-language-server + '(:system "bash-language-server") + '(:npm :package "bash-language-server" + :path "bash-language-server")) + +(defvar sh-shell) + +(defun lsp-bash-check-sh-shell (&rest _) + "Check whether `sh-shell' is sh or bash. + +This prevents the Bash server from being turned on in zsh files." + (and (eq major-mode 'sh-mode) + (memq sh-shell '(sh bash)))) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection #'lsp-bash--bash-ls-server-command) + :priority -1 + :activation-fn #'lsp-bash-check-sh-shell + :environment-fn (lambda () + '(("EXPLAINSHELL_ENDPOINT" . lsp-bash-explainshell-endpoint) + ("HIGHLIGHT_PARSING_ERRORS" . lsp-bash-highlight-parsing-errors) + ("GLOB_PATTERN" . lsp-bash-glob-pattern))) + :server-id 'bash-ls + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'bash-language-server callback error-callback)))) + +(lsp-consistency-check lsp-bash) + +(provide 'lsp-bash) +;;; lsp-bash.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-beancount.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-beancount.el new file mode 100644 index 0000000..f1f8c74 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-beancount.el @@ -0,0 +1,71 @@ +;;; lsp-beancount.el --- Beancount Client settings -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, beancount + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP client for Beancount + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-beancount nil + "Settings for the Beancount Language Server." + :group 'lsp-mode + :link '(url-link "https://github.com/polarmutex/beancount-language-server") + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-beancount-langserver-executable "beancount-langserver" + "Command to start Beancount language server." + :type 'string + :group 'lsp-beancount + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-beancount-python-interpreter nil + "Path to Python executable." + :type 'string + :group 'lsp-beancount + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-beancount-journal-file nil + "Pathg to Beancount journal file." + :type 'string + :group 'lsp-beancount + :package-version '(lsp-mode . "7.1.0")) + +(lsp-register-client + (make-lsp-client + :new-connection + (lsp-stdio-connection + (lambda () + (when (null lsp-beancount-python-interpreter) + (setq lsp-beancount-python-interpreter (or (executable-find "python3") + (executable-find "python")))) + `(,lsp-beancount-langserver-executable "--stdio"))) + :major-modes '(beancount-mode) + :initialization-options + `((journalFile . ,lsp-beancount-journal-file) + (pythonPath . ,lsp-beancount-python-interpreter)) + :server-id 'beancount-ls)) + +(lsp-consistency-check lsp-beancount) + +(provide 'lsp-beancount) +;;; lsp-beancount.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-clangd.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-clangd.el new file mode 100644 index 0000000..fc37a17 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-clangd.el @@ -0,0 +1,304 @@ +;;; lsp-clangd.el --- LSP clients for the C Languages Family -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Daniel Martín & emacs-lsp maintainers +;; URL: https://github.com/emacs-lsp/lsp-mode +;; Keywords: languages, c, cpp, clang + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP clients for the C Languages Family. + +;; ** Clang-tidy Flycheck integration (Clangd) ** +;; +;; If you invoke `flycheck-display-error-explanation' on a +;; `clang-tidy' error (if Clangd is configured to show `clang-tidy' +;; diagnostics), Emacs will open a detailed explanation about the +;; message by querying the LLVM website. As an embedded web browser is +;; used to show the documentation, this feature requires that Emacs is +;; compiled with libxml2 support. + +;;; Code: + +(require 'lsp-mode) +(require 'cl-lib) +(require 'rx) +(require 'seq) +(require 'dom) +(eval-when-compile (require 'subr-x)) + +(require 'dash) +(require 's) + +(defvar flycheck-explain-error-buffer) +(declare-function flycheck-error-id "ext:flycheck" (err) t) +(declare-function flycheck-error-group "ext:flycheck" (err) t) +(declare-function flycheck-error-message "ext:flycheck" (err) t) + +(defcustom lsp-clangd-version "12.0.0" + "Clangd version to download. +It has to be set before `lsp-clangd.el' is loaded and it has to +be available here: https://github.com/clangd/clangd/releases/" + :type 'string + :group 'lsp-clangd + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-clangd-download-url + (format (pcase system-type + ('darwin "https://github.com/clangd/clangd/releases/download/%s/clangd-mac-%s.zip") + ('windows-nt "https://github.com/clangd/clangd/releases/download/%s/clangd-windows-%s.zip") + (_ "https://github.com/clangd/clangd/releases/download/%s/clangd-linux-%s.zip")) + lsp-clangd-version + lsp-clangd-version) + "Automatic download url for clangd" + :type 'string + :group 'lsp-clangd + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-clangd-binary-path + (f-join lsp-server-install-dir (format "clangd/clangd_%s/bin" + lsp-clangd-version) + (pcase system-type + ('windows-nt "clangd.exe") + (_ "clangd"))) + "The path to `clangd' binary." + :type 'file + :group 'lsp-clangd + :package-version '(lsp-mode . "7.1")) + +(lsp-dependency + 'clangd + `(:download :url lsp-clangd-download-url + :decompress :zip + :store-path ,(f-join lsp-server-install-dir "clangd" "clangd.zip") + :binary-path lsp-clangd-binary-path + :set-executable? t)) + +(defun lsp-cpp-flycheck-clang-tidy--skip-http-headers () + "Position point just after HTTP headers." + (re-search-forward "^$")) + +(defun lsp-cpp-flycheck-clang-tidy--narrow-to-http-body () + "Narrow the current buffer to contain the body of an HTTP response." + (lsp-cpp-flycheck-clang-tidy--skip-http-headers) + (narrow-to-region (point) (point-max))) + +(defun lsp-cpp-flycheck-clang-tidy--decode-region-as-utf8 (start end) + "Decode a region from START to END in UTF-8." + (condition-case nil + (decode-coding-region start end 'utf-8) + (coding-system-error nil))) + +(defun lsp-cpp-flycheck-clang-tidy--remove-crlf () + "Remove carriage return and line feeds from the current buffer." + (save-excursion + (while (re-search-forward "\r$" nil t) + (replace-match "" t t)))) + +(defun lsp-cpp-flycheck-clang-tidy--extract-relevant-doc-section () + "Extract the parts of the LLVM clang-tidy documentation that are relevant. + +This function assumes that the current buffer contains the result +of browsing 'clang.llvm.org', as returned by `url-retrieve'. +More concretely, this function returns the main <div> element +with class 'section', and also removes 'headerlinks'." + (goto-char (point-min)) + (lsp-cpp-flycheck-clang-tidy--narrow-to-http-body) + (lsp-cpp-flycheck-clang-tidy--decode-region-as-utf8 (point-min) (point-max)) + (lsp-cpp-flycheck-clang-tidy--remove-crlf) + (let* ((dom (libxml-parse-html-region (point-min) (point-max))) + (section (dom-by-class dom "section"))) + (dolist (headerlink (dom-by-class section "headerlink")) + (dom-remove-node section headerlink)) + section)) + +(defun lsp-cpp-flycheck-clang-tidy--explain-error (explanation &rest args) + "Explain an error in the Flycheck error explanation buffer using EXPLANATION. + +EXPLANATION is a function with optional ARGS that, when +evaluated, inserts the content in the appropriate Flycheck +buffer." + (with-current-buffer flycheck-explain-error-buffer + (let ((inhibit-read-only t) + (inhibit-modification-hooks t)) + (erase-buffer) + (apply explanation args) + (goto-char (point-min))))) + +(defun lsp-cpp-flycheck-clang-tidy--show-loading-status () + "Show a loading string while clang-tidy documentation is fetched from llvm.org. +Recent versions of `flycheck' call `display-message-or-buffer' to +display error explanations. `display-message-or-buffer' displays +the documentation string either in the echo area or in a separate +window, depending on the string's height. This function forces to +always display it in a separate window by appending the required +number of newlines." + (let* ((num-lines-threshold + (round (if resize-mini-windows + (cond ((floatp max-mini-window-height) + (* (frame-height) + max-mini-window-height)) + ((integerp max-mini-window-height) + max-mini-window-height) + (t + 1)) + 1))) + (extra-new-lines (make-string (1+ num-lines-threshold) ?\n))) + (concat "Loading documentation..." extra-new-lines))) + +(defun lsp-cpp-flycheck-clang-tidy--show-documentation (error-id) + "Show clang-tidy documentation about ERROR-ID. + +Information comes from the clang.llvm.org website." + (url-retrieve (format + "https://clang.llvm.org/extra/clang-tidy/checks/%s.html" error-id) + (lambda (status) + (if-let ((error-status (plist-get status :error))) + (lsp-cpp-flycheck-clang-tidy--explain-error + #'insert + (format + "Error accessing clang-tidy documentation: %s" + (error-message-string error-status))) + (let ((doc-contents + (lsp-cpp-flycheck-clang-tidy--extract-relevant-doc-section))) + (lsp-cpp-flycheck-clang-tidy--explain-error + #'shr-insert-document doc-contents))))) + (lsp-cpp-flycheck-clang-tidy--show-loading-status)) + +;;;###autoload +(defun lsp-cpp-flycheck-clang-tidy-error-explainer (error) + "Explain a clang-tidy ERROR by scraping documentation from llvm.org." + (unless (fboundp 'libxml-parse-html-region) + (error "This function requires Emacs to be compiled with libxml2")) + (if-let ((clang-tidy-error-id (flycheck-error-id error))) + (condition-case err + (lsp-cpp-flycheck-clang-tidy--show-documentation clang-tidy-error-id) + (error + (format + "Error accessing clang-tidy documentation: %s" + (error-message-string err)))) + (error "The clang-tidy error message does not contain an [error-id]"))) + + +;;; lsp-clangd +(defgroup lsp-clangd nil + "LSP support for C-family languages (C, C++, Objective-C, Objective-C++), using clangd." + :group 'lsp-mode + :link '(url-link "https://clang.llvm.org/extra/clangd")) + +(defcustom lsp-clients-clangd-executable nil + "The clangd executable to use. +When `'non-nil' use the name of the clangd executable file +available in your path to use. Otherwise the system will try to +find a suitable one. Set this variable before loading lsp." + :group 'lsp-clangd + :risky t + :type '(choice (file :tag "Path") + (const :tag "Auto" nil))) + +(defvar lsp-clients--clangd-default-executable nil + "Clang default executable full path when found. +This must be set only once after loading the clang client.") + +(defcustom lsp-clients-clangd-args '("--header-insertion-decorators=0") + "Extra arguments for the clangd executable." + :group 'lsp-clangd + :risky t + :type '(repeat string)) + +(defun lsp-clients--clangd-command () + "Generate the language server startup command." + (unless lsp-clients--clangd-default-executable + (setq lsp-clients--clangd-default-executable + (or (lsp-package-path 'clangd) + (-first #'executable-find + (-map (lambda (version) + (concat "clangd" version)) + '("" "-12" "-11" "-10" "-9" "-8" "-7" "-6"))) + (lsp-clients-executable-find "xcodebuild" "-find-executable" "clangd") + (lsp-clients-executable-find "xcrun" "--find" "clangd")))) + + `(,(or lsp-clients-clangd-executable lsp-clients--clangd-default-executable "clangd") + ,@lsp-clients-clangd-args)) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + 'lsp-clients--clangd-command) + :activation-fn (lsp-activate-on "c" "cpp" "objective-c") + :priority -1 + :server-id 'clangd + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'clangd callback error-callback)))) + +(defun lsp-clangd-join-region (beg end) + "Apply join-line from BEG to END. +This function is useful when an indented function prototype needs +to be shown in a single line." + (save-excursion + (let ((end (copy-marker end))) + (goto-char beg) + (while (< (point) end) + (join-line 1))) + (s-trim (buffer-string)))) + +(cl-defmethod lsp-clients-extract-signature-on-hover (contents (_server-id (eql clangd))) + "Extract a representative line from clangd's CONTENTS, to show in the echo area. +This function tries to extract the type signature from CONTENTS, +or the first line if it cannot do so. A single line is always +returned to avoid that the echo area grows uncomfortably." + (with-temp-buffer + (-let [value (lsp:markup-content-value contents)] + (insert value) + (goto-char (point-min)) + (if (re-search-forward (rx (seq "```cpp\n" + (opt (group "//" + (zero-or-more nonl) + "\n")) + (group + (one-or-more + (not (any "`"))) + "\n") + "```")) nil t nil) + (progn (narrow-to-region (match-beginning 2) (match-end 2)) + (lsp--render-element (lsp-make-marked-string + :language "cpp" + :value (lsp-clangd-join-region (point-min) (point-max))))) + (car (s-lines (lsp--render-element contents))))))) + +(cl-defmethod lsp-diagnostics-flycheck-error-explainer (e (_server-id (eql clangd))) + "Explain a `flycheck-error' E that was generated by the Clangd language server." + (cond ((string-equal "clang-tidy" (flycheck-error-group e)) + (lsp-cpp-flycheck-clang-tidy-error-explainer e)) + (t (flycheck-error-message e)))) + +(defun lsp-clangd-find-other-file (&optional new-window) + "Switch between the corresponding C/C++ source and header file. +If NEW-WINDOW (interactively the prefix argument) is non-nil, +open in a new window. + +Only works with clangd." + (interactive "P") + (let ((other (lsp-send-request (lsp-make-request + "textDocument/switchSourceHeader" + (lsp--text-document-identifier))))) + (unless (s-present? other) + (user-error "Could not find other file")) + (funcall (if new-window #'find-file-other-window #'find-file) + (lsp--uri-to-path other)))) + +(lsp-consistency-check lsp-clangd) + +(provide 'lsp-clangd) +;;; lsp-clangd.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-clojure.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-clojure.el new file mode 100644 index 0000000..9855983 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-clojure.el @@ -0,0 +1,308 @@ +;;; lsp-clojure.el --- Clojure Client settings -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Benedek Fazekas + +;; Author: Benedek Fazekas <benedek.fazekas@gmail.com> +;; Keywords: languages,tools + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; lsp-clojure client + +;;; Code: + +(require 'lsp-mode) +(require 'lsp-protocol) +(require 'cl-lib) + +(defgroup lsp-clojure nil + "LSP support for Clojure." + :link '(url-link "https://github.com/snoe/clojure-lsp") + :group 'lsp-mode + :tag "Lsp Clojure") + +(define-obsolete-variable-alias 'lsp-clojure-server-command + 'lsp-clojure-custom-server-command "lsp-mode 7.1") + +(defcustom lsp-clojure-custom-server-command nil + "The clojure-lisp server command." + :group 'lsp-clojure + :risky t + :type '(repeat string)) + +(defcustom lsp-clojure-server-download-url + (format "https://github.com/clojure-lsp/clojure-lsp/releases/latest/download/clojure-lsp-native-%s-amd64.zip" + (pcase system-type + ('gnu/linux "linux") + ('darwin "macos") + ('windows-nt "windows"))) + "Automatic download url for lsp-clojure." + :type 'string + :group 'lsp-clojure + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-clojure-server-store-path + (f-join lsp-server-install-dir + "clojure" + (if (eq system-type 'windows-nt) + "clojure-lsp.exe" + "clojure-lsp")) + "The path to the file in which `clojure-lsp' will be stored." + :type 'file + :group 'lsp-clojure + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-clojure-workspace-dir (expand-file-name (locate-user-emacs-file "workspace/")) + "LSP clojure workspace directory." + :group 'lsp-clojure + :risky t + :type 'directory) + +(defcustom lsp-clojure-workspace-cache-dir (expand-file-name ".cache/" lsp-clojure-workspace-dir) + "LSP clojure workspace cache directory." + :group 'lsp-clojure + :risky t + :type 'directory) + +;; Internal + +(lsp-interface + (Clojure:CursorInfoParams (:textDocument :position) nil)) + +(lsp-dependency + 'clojure-lsp + `(:download :url lsp-clojure-server-download-url + :decompress :zip + :store-path lsp-clojure-server-store-path + :set-executable? t) + '(:system "clojure-lsp")) + +;; Refactorings + +(defun lsp-clojure--execute-command (command &optional args) + "Send an executeCommand request for COMMAND with ARGS." + (lsp--cur-workspace-check) + (lsp-send-execute-command command (apply #'vector args))) + +(defun lsp-clojure--refactoring-call (refactor-name &rest additional-args) + "Send an executeCommand request for REFACTOR-NAME with ADDITIONAL-ARGS. +If there are more arguments expected after the line and column numbers." + (lsp--cur-workspace-check) + (lsp-clojure--execute-command refactor-name (cl-list* (lsp--buffer-uri) + (- (line-number-at-pos) 1) ;; clojure-lsp expects line numbers to start at 0 + (current-column) + additional-args))) + +(defun lsp-clojure-add-import-to-namespace (import-name) + "Add to IMPORT-NAME to :import form." + (interactive "MImport name: ") + (lsp-clojure--refactoring-call "add-import-to-namespace" import-name)) + +(defun lsp-clojure-add-missing-libspec () + "Apply add-missing-libspec refactoring at point." + (interactive) + (lsp-clojure--refactoring-call "add-missing-libspec")) + +(defun lsp-clojure-clean-ns () + "Apply clean-ns refactoring at point." + (interactive) + (lsp-clojure--refactoring-call "clean-ns")) + +(defun lsp-clojure-cycle-coll () + "Apply cycle-coll refactoring at point." + (interactive) + (lsp-clojure--refactoring-call "cycle-coll")) + +(defun lsp-clojure-cycle-privacy () + "Apply cycle-privacy refactoring at point." + (interactive) + (lsp-clojure--refactoring-call "cycle-privacy")) + +(defun lsp-clojure-expand-let () + "Apply expand-let refactoring at point." + (interactive) + (lsp-clojure--refactoring-call "expand-let")) + +(defun lsp-clojure-extract-function (function-name) + "Move form at point into a new function named FUNCTION-NAME." + (interactive "MFunction name: ") ;; Name of the function + (lsp-clojure--refactoring-call "extract-function" function-name)) + +(defun lsp-clojure-inline-symbol () + "Apply inline-symbol refactoring at point." + (interactive) + (lsp-clojure--refactoring-call "inline-symbol")) + +(defun lsp-clojure-introduce-let (binding-name) + "Move form at point into a new let binding as BINDING-NAME." + (interactive "MBinding name: ") ;; Name of the let binding + (lsp-clojure--refactoring-call "introduce-let" binding-name)) + +(defun lsp-clojure-move-to-let (binding-name) + "Move form at point into nearest existing let binding as BINDING-NAME." + (interactive "MBinding name: ") ;; Name of the let binding + (lsp-clojure--refactoring-call "move-to-let" binding-name)) + +(defun lsp-clojure-thread-first () + "Apply thread-first refactoring at point." + (interactive) + (lsp-clojure--refactoring-call "thread-first")) + +(defun lsp-clojure-thread-first-all () + "Apply thread-first-all refactoring at point." + (interactive) + (lsp-clojure--refactoring-call "thread-first-all")) + +(defun lsp-clojure-thread-last () + "Apply thread-last refactoring at point." + (interactive) + (lsp-clojure--refactoring-call "thread-last")) + +(defun lsp-clojure-thread-last-all () + "Apply thread-last-all refactoring at point." + (interactive) + (lsp-clojure--refactoring-call "thread-last-all")) + +(defun lsp-clojure-unwind-all () + "Apply unwind-all refactoring at point." + (interactive) + (lsp-clojure--refactoring-call "unwind-all")) + +(defun lsp-clojure-unwind-thread () + "Apply unwind-thread refactoring at point." + (interactive) + (lsp-clojure--refactoring-call "unwind-thread")) + +(defun lsp-clojure-server-info () + "Request server info." + (interactive) + (lsp--cur-workspace-check) + (lsp-notify "clojure/serverInfo/log" nil)) + +(defun lsp-clojure-server-info-raw () + "Request server info raw data." + (interactive) + (lsp--cur-workspace-check) + (message "%s" (lsp--json-serialize (lsp-request "clojure/serverInfo/raw" nil)))) + +(defun lsp-clojure-cursor-info () + "Request cursor info at point." + (interactive) + (lsp--cur-workspace-check) + (lsp-notify "clojure/cursorInfo/log" + (lsp-make-clojure-cursor-info-params + :textDocument (lsp-make-text-document-identifier :uri (lsp--buffer-uri)) + :position (lsp-make-position :line (- (line-number-at-pos) 1) + :character (current-column))))) + +(defun lsp-clojure--ask-macro-to-resolve () + "Ask to user the macro to resolve." + (lsp--completing-read + "Select how LSP should resolve this macro:" + '("clojure.core/def" + "clojure.core/defn" + "clojure.core/let" + "clojure.core/for" + "clojure.core/->" + "clojure.core/->>" + "clj-kondo.lint-as/def-catch-all") + #'identity + nil + t)) + +(defun lsp-clojure--ask-clj-kondo-config-dir () + "Ask to user the clj-kondo config dir path." + (lsp--completing-read + "Select where LSP should save this setting:" + (list (f-join (expand-file-name "~/") ".config/clj-kondo/config.edn") + (f-join (or (lsp-workspace-root) "project") ".clj-kondo/config.edn")) + #'identity + nil + t)) + +(defun lsp-clojure-resolve-macro-as () + "Ask to user how the unresolved macro should be resolved." + (interactive) + (lsp--cur-workspace-check) + (lsp-clojure--execute-command "resolve-macro-as" + (list (lsp--buffer-uri) + (- (line-number-at-pos) 1) ;; clojure-lsp expects line numbers to start at 0 + (current-column) + (lsp-clojure--ask-macro-to-resolve) + (lsp-clojure--ask-clj-kondo-config-dir)))) + +(lsp-defun lsp-clojure--resolve-macro-as ((&Command :command :arguments?)) + "Intercept resolve-macro-as command and send all necessary data." + (let ((chosen-macro (lsp-clojure--ask-macro-to-resolve)) + (clj-kondo-config-path (lsp-clojure--ask-clj-kondo-config-dir))) + (lsp-clojure--execute-command command (append arguments? (list chosen-macro clj-kondo-config-path))))) + +(defun lsp-clojure--ensure-dir (path) + "Ensure that directory PATH exists." + (unless (file-directory-p path) + (make-directory path t))) + +(defun lsp-clojure--get-metadata-location (file-location) + "Given a FILE-LOCATION return the file containing the metadata for the file." + (format "%s.%s.metadata" + (file-name-directory file-location) + (file-name-base file-location))) + +(defun lsp-clojure--file-in-jar (uri) + "Check URI for a valid jar and include it in workspace." + (string-match "^\\(jar\\|zip\\):\\(file:.+\\)!/\\(.+\\)" uri) + (let* ((ns-path (match-string 3 uri)) + (ns (s-replace "/" "." ns-path)) + (file-location (concat lsp-clojure-workspace-cache-dir ns))) + (unless (file-readable-p file-location) + (lsp-clojure--ensure-dir (file-name-directory file-location)) + (with-lsp-workspace (lsp-find-workspace 'clojure-lsp nil) + (let ((content (lsp-send-request (lsp-make-request "clojure/dependencyContents" (list :uri uri))))) + (with-temp-file file-location + (insert content)) + (with-temp-file (lsp-clojure--get-metadata-location file-location) + (insert uri))))) + file-location)) + +(defun lsp-clojure--server-executable-path () + "Return the clojure-lsp server command." + (or (executable-find "clojure-lsp") + (lsp-package-path 'clojure-lsp))) + +(lsp-register-client + (make-lsp-client + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'clojure-lsp callback error-callback)) + :semantic-tokens-faces-overrides '(:types (("macro" . font-lock-keyword-face) + ("keyword" . clojure-keyword-face))) + :new-connection (lsp-stdio-connection + (lambda () + (or lsp-clojure-custom-server-command + `(,(lsp-clojure--server-executable-path)))) + (lambda () + (or lsp-clojure-custom-server-command + (lsp-clojure--server-executable-path)))) + :major-modes '(clojure-mode clojurec-mode clojurescript-mode) + :library-folders-fn (lambda (_workspace) (list lsp-clojure-workspace-cache-dir)) + :uri-handlers (lsp-ht ("jar" #'lsp-clojure--file-in-jar)) + :action-handlers (lsp-ht ("resolve-macro-as" #'lsp-clojure--resolve-macro-as)) + :initialization-options '(:dependency-scheme "jar") + :server-id 'clojure-lsp)) + +(lsp-consistency-check lsp-clojure) + +(provide 'lsp-clojure) +;;; lsp-clojure.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-cmake.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-cmake.el new file mode 100644 index 0000000..beffa5d --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-cmake.el @@ -0,0 +1,43 @@ +;;; lsp-cmake.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, cmake + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the CMake build tool. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-cmake nil + "LSP support for CMake, using cmake-language-server." + :group 'lsp-mode + :link '(url-link "https://github.com/regen100/cmake-language-server")) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection "cmake-language-server") + :major-modes '(cmake-mode) + :priority -1 + :server-id 'cmakels)) + +(lsp-consistency-check lsp-cmake) + +(provide 'lsp-cmake) +;;; lsp-cmake.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-completion.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-completion.el new file mode 100644 index 0000000..d8d131e --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-completion.el @@ -0,0 +1,779 @@ +;;; lsp-completion.el --- LSP completion -*- lexical-binding: t; -*- +;; +;; Copyright (C) 2020 emacs-lsp maintainers +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. +;; +;;; Commentary: +;; +;; LSP completion +;; +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-completion nil + "LSP support for completion" + :prefix "lsp-completion-" + :group 'lsp-mode + :tag "LSP Completion") + +;;;###autoload +(define-obsolete-variable-alias 'lsp-prefer-capf + 'lsp-completion-provider "lsp-mode 7.0.1") + +(defcustom lsp-completion-provider :capf + "The completion backend provider." + :type '(choice + (const :tag "Use company-capf" :capf) + (const :tag "None" :none)) + :group 'lsp-completion + :package-version '(lsp-mode . "7.0.1")) + +;;;###autoload +(define-obsolete-variable-alias 'lsp-enable-completion-at-point + 'lsp-completion-enable "lsp-mode 7.0.1") + +(defcustom lsp-completion-enable t + "Enable `completion-at-point' integration." + :type 'boolean + :group 'lsp-completion) + +(defcustom lsp-completion-enable-additional-text-edit t + "Whether or not to apply additional text edit when performing completion. + +If set to non-nil, `lsp-mode' will apply additional text edits +from the server. Otherwise, the additional text edits are +ignored." + :type 'boolean + :group 'lsp-completion + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-completion-show-kind t + "Whether or not to show kind of completion candidates." + :type 'boolean + :group 'lsp-completion + :package-version '(lsp-mode . "7.0.1")) + +(defcustom lsp-completion-show-detail t + "Whether or not to show detail of completion candidates." + :type 'boolean + :group 'lsp-completion) + +(defcustom lsp-completion-no-cache nil + "Whether or not caching the returned completions from server." + :type 'boolean + :group 'lsp-completion + :package-version '(lsp-mode . "7.0.1")) + +(defcustom lsp-completion-filter-on-incomplete t + "Whether or not filter incomplete results." + :type 'boolean + :group 'lsp-completion + :package-version '(lsp-mode . "7.0.1")) + +(defcustom lsp-completion-sort-initial-results t + "Whether or not filter initial results from server." + :type 'boolean + :group 'lsp-completion + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-completion-use-last-result t + "Temporarily use last server result when interrupted by keyboard. +This will help minimize popup flickering issue in `company-mode'." + :type 'boolean + :group 'lsp-completion + :package-version '(lsp-mode . "7.1")) + +(defconst lsp-completion--item-kind + [nil + "Text" + "Method" + "Function" + "Constructor" + "Field" + "Variable" + "Class" + "Interface" + "Module" + "Property" + "Unit" + "Value" + "Enum" + "Keyword" + "Snippet" + "Color" + "File" + "Reference" + "Folder" + "EnumMember" + "Constant" + "Struct" + "Event" + "Operator" + "TypeParameter"]) + +(defvar yas-indent-line) +(defvar company-backends) +(defvar company-abort-on-unique-match) + +(defvar lsp-completion--no-reordering nil + "Dont do client-side reordering completion items when set.") + +(declare-function company-mode "ext:company") +(declare-function company-doc-buffer "ext:company") +(declare-function yas-expand-snippet "ext:yasnippet") + +(defun lsp-falsy? (val) + "Non-nil if VAL is falsy." + ;; https://developer.mozilla.org/en-US/docs/Glossary/Falsy + (or (not val) (equal val "") (equal val 0))) + +(cl-defun lsp-completion--make-item (item &key markers prefix) + "Make completion item from lsp ITEM and with MARKERS and PREFIX." + (-let (((&CompletionItem :label + :sort-text? + :_emacsStartPoint start-point) + item)) + (propertize label + 'lsp-completion-item item + 'lsp-sort-text sort-text? + 'lsp-completion-start-point start-point + 'lsp-completion-markers markers + 'lsp-completion-prefix prefix))) + +(defun lsp-completion--annotate (item) + "Annotate ITEM detail." + (-let (((&CompletionItem :detail? :kind?) (plist-get (text-properties-at 0 item) + 'lsp-completion-item))) + (concat (when (and lsp-completion-show-detail detail?) + (concat " " (s-replace "\r" "" detail?))) + (when lsp-completion-show-kind + (when-let ((kind-name (and kind? (aref lsp-completion--item-kind kind?)))) + (format " (%s)" kind-name)))))) + +(defun lsp-completion--looking-back-trigger-characterp (trigger-characters) + "Return trigger character if text before point match any of the TRIGGER-CHARACTERS." + (unless (= (point) (point-at-bol)) + (seq-some + (lambda (trigger-char) + (and (equal (buffer-substring-no-properties (- (point) (length trigger-char)) (point)) + trigger-char) + trigger-char)) + trigger-characters))) + +(defvar lsp-completion--cache nil + "Cached candidates for completion at point function. +In the form of plist (prefix-pos items :lsp-items :prefix ...). +When the completion is incomplete, `items' contains value of :incomplete.") + +(defvar lsp-completion--last-result nil + "Last completion result.") + +(defun lsp-completion--clear-cache (&optional keep-last-result) + "Clear completion caches. +KEEP-LAST-RESULT if specified." + (-some-> lsp-completion--cache + (cddr) + (plist-get :markers) + (cl-second) + (set-marker nil)) + (setq lsp-completion--cache nil) + (unless keep-last-result (setq lsp-completion--last-result nil))) + +(defcustom lsp-completion-default-behaviour :replace + "Default behaviour of `InsertReplaceEdit'." + :type '(choice + (const :insert :tag "Default completion inserts") + (const :replace :tag "Default completion replaces")) + :group 'lsp-mode + :package-version '(lsp-mode . "7.1")) + +(lsp-defun lsp-completion--guess-prefix ((item &as &CompletionItem :text-edit?)) + "Guess ITEM's prefix start point according to following heuristics: +- If `textEdit' exists, use insertion range start as prefix start point. +- Else, find the point before current point is longest prefix match of +`insertText' or `label'. And: + - The character before prefix is not word constitute +Return `nil' when fails to guess prefix." + (cond + ((lsp-insert-replace-edit? text-edit?) + (lsp--position-to-point (lsp:range-start (lsp:insert-replace-edit-insert text-edit?)))) + (text-edit? + (lsp--position-to-point (lsp:range-start (lsp:text-edit-range text-edit?)))) + (t + (-let* (((&CompletionItem :label :insert-text?) item) + (text (or (unless (lsp-falsy? insert-text?) insert-text?) label)) + (point (point)) + (start (max 1 (- point (length text)))) + (char-before (char-before start)) + start-point) + (while (and (< start point) (not start-point)) + (unless (or (and char-before (equal (char-syntax char-before) ?w)) + (not (string-prefix-p (buffer-substring-no-properties start point) + text))) + (setq start-point start)) + (cl-incf start) + (setq char-before (char-before start))) + start-point)))) + +(defun lsp-completion--to-internal (items) + "Convert ITEMS into internal form." + (--> items + (-map (-lambda ((item &as &CompletionItem + :label + :filter-text? + :_emacsStartPoint start-point + :score?)) + `( :label ,(or (unless (lsp-falsy? filter-text?) filter-text?) label) + :item ,item + :start-point ,start-point + :score ,score?)) + it))) + +(cl-defun lsp-completion--filter-candidates (items &key + lsp-items + markers + prefix + &allow-other-keys) + "List all possible completions in cached ITEMS with their prefixes. +We can pass LSP-ITEMS, which will be used when there's no cache. +The MARKERS and PREFIX value will be attached to each candidate." + (lsp--while-no-input + (->> + (if items + (--> + (let (queries fuz-queries) + (-keep (-lambda ((cand &as &plist :label :start-point :score)) + (let* ((query (or (plist-get queries start-point) + (let ((s (buffer-substring-no-properties + start-point (point)))) + (setq queries (plist-put queries start-point s)) + s))) + (fuz-query (or (plist-get fuz-queries start-point) + (let ((s (lsp-completion--regex-fuz query))) + (setq fuz-queries + (plist-put fuz-queries start-point s)) + s))) + (label-len (length label))) + (when (string-match fuz-query label) + (put-text-property 0 label-len 'match-data (match-data) label) + (plist-put cand + :sort-score + (* (or (lsp-completion--fuz-score query label) 1e-05) + (or score 0.001))) + cand))) + items)) + (if lsp-completion--no-reordering + it + (sort it (lambda (o1 o2) + (> (plist-get o1 :sort-score) + (plist-get o2 :sort-score))))) + ;; TODO: pass additional function to sort the candidates + (-map (-rpartial #'plist-get :item) it)) + lsp-items) + (-map (lambda (item) (lsp-completion--make-item item + :markers markers + :prefix prefix)))))) + +(defconst lsp-completion--kind->symbol + '((1 . text) + (2 . method) + (3 . function) + (4 . constructor) + (5 . field) + (6 . variable) + (7 . class) + (8 . interface) + (9 . module) + (10 . property) + (11 . unit) + (12 . value) + (13 . enum) + (14 . keyword) + (15 . snippet) + (16 . color) + (17 . file) + (18 . reference) + (19 . folder) + (20 . enum-member) + (21 . constant) + (22 . struct) + (23 . event) + (24 . operator) + (25 . type-parameter))) + +(defun lsp-completion--candidate-kind (item) + "Return ITEM's kind." + (alist-get (lsp:completion-item-kind? (get-text-property 0 'lsp-completion-item item)) + lsp-completion--kind->symbol)) + +(defun lsp-completion--company-match (candidate) + "Return highlight of typed prefix inside CANDIDATE." + (let* ((prefix (downcase + (buffer-substring-no-properties + (plist-get (text-properties-at 0 candidate) 'lsp-completion-start-point) + (point)))) + (prefix-len (length prefix)) + (prefix-pos 0) + (label (downcase candidate)) + (label-len (length label)) + (label-pos 0) + matches start) + (while (and (not matches) + (< prefix-pos prefix-len)) + (while (and (< prefix-pos prefix-len) + (< label-pos label-len)) + (if (equal (aref prefix prefix-pos) (aref label label-pos)) + (progn + (unless start (setq start label-pos)) + (cl-incf prefix-pos)) + (when start + (setq matches (nconc matches `((,start . ,label-pos)))) + (setq start nil))) + (cl-incf label-pos)) + (when start (setq matches (nconc matches `((,start . ,label-pos))))) + ;; Search again when the whole prefix is not matched + (when (< prefix-pos prefix-len) + (setq matches nil)) + ;; Start search from next offset of prefix to find a match with label + (unless matches + (cl-incf prefix-pos) + (setq label-pos 0))) + matches)) + +(defun lsp-completion--get-documentation (item) + "Get doc comment for completion ITEM." + (unless (get-text-property 0 'lsp-completion-resolved item) + (let ((resolved-item + (-some->> item + (get-text-property 0 'lsp-completion-item) + (lsp-completion--resolve))) + (len (length item))) + (put-text-property 0 len 'lsp-completion-item resolved-item item) + (put-text-property 0 len 'lsp-completion-resolved t item))) + (-some->> item + (get-text-property 0 'lsp-completion-item) + (lsp:completion-item-documentation?) + (lsp--render-element))) + +(defun lsp-completion--get-context (trigger-characters) + "Get completion context with provided TRIGGER-CHARACTERS." + (let* ((triggered-by-char non-essential) + (trigger-char (when triggered-by-char + (lsp-completion--looking-back-trigger-characterp + trigger-characters))) + (trigger-kind (cond + (trigger-char + lsp/completion-trigger-kind-trigger-character) + ((equal (cl-second lsp-completion--cache) :incomplete) + lsp/completion-trigger-kind-trigger-for-incomplete-completions) + (t lsp/completion-trigger-kind-invoked)))) + (apply #'lsp-make-completion-context + (nconc + `(:trigger-kind ,trigger-kind) + (when trigger-char + `(:trigger-character? ,trigger-char)))))) + +(defun lsp-completion--sort-completions (completions) + "Sort COMPLETIONS." + (sort + completions + (-lambda ((&CompletionItem :sort-text? sort-text-left :label label-left) + (&CompletionItem :sort-text? sort-text-right :label label-right)) + (if (equal sort-text-left sort-text-right) + (string-lessp label-left label-right) + (string-lessp sort-text-left sort-text-right))))) + +;;;###autoload +(defun lsp-completion-at-point () + "Get lsp completions." + (when (or (--some (lsp--client-completion-in-comments? (lsp--workspace-client it)) + (lsp-workspaces)) + (not (nth 4 (syntax-ppss)))) + (let* ((trigger-chars (->> (lsp--server-capabilities) + (lsp:server-capabilities-completion-provider?) + (lsp:completion-options-trigger-characters?))) + (bounds-start (or (-some--> (cl-first (bounds-of-thing-at-point 'symbol)) + (save-excursion + (ignore-errors + (goto-char (+ it 1)) + (while (lsp-completion--looking-back-trigger-characterp + trigger-chars) + (cl-incf it) + (forward-char)) + it))) + (point))) + result done? + (candidates + (lambda () + (lsp--catch 'input + (let ((lsp--throw-on-input lsp-completion-use-last-result) + (same-session? (and lsp-completion--cache + ;; Special case for empty prefix and empty result + (or (cl-second lsp-completion--cache) + (not (string-empty-p + (plist-get (cddr lsp-completion--cache) :prefix)))) + (equal (cl-first lsp-completion--cache) bounds-start) + (s-prefix? + (plist-get (cddr lsp-completion--cache) :prefix) + (buffer-substring-no-properties bounds-start (point)))))) + (cond + ((or done? result) result) + ((and (not lsp-completion-no-cache) + same-session? + (listp (cl-second lsp-completion--cache))) + (setf result (apply #'lsp-completion--filter-candidates + (cdr lsp-completion--cache)))) + (t + (-let* ((resp (lsp-request-while-no-input + "textDocument/completion" + (plist-put (lsp--text-document-position-params) + :context (lsp-completion--get-context trigger-chars)))) + (completed (and resp + (not (and (lsp-completion-list? resp) + (lsp:completion-list-is-incomplete resp))))) + (items (lsp--while-no-input + (--> (cond + ((lsp-completion-list? resp) + (lsp:completion-list-items resp)) + (t resp)) + (if (or completed + (seq-some #'lsp:completion-item-sort-text? it)) + (lsp-completion--sort-completions it) + it) + (-map (lambda (item) + (lsp-put item + :_emacsStartPoint + (or (lsp-completion--guess-prefix item) + bounds-start))) + it)))) + (markers (list bounds-start (copy-marker (point) t))) + (prefix (buffer-substring-no-properties bounds-start (point))) + (lsp-completion--no-reordering (not lsp-completion-sort-initial-results))) + (lsp-completion--clear-cache same-session?) + (setf done? completed + lsp-completion--cache (list bounds-start + (cond + ((and done? (not (seq-empty-p items))) + (lsp-completion--to-internal items)) + ((not done?) :incomplete)) + :lsp-items nil + :markers markers + :prefix prefix) + result (lsp-completion--filter-candidates + (cond (done? + (cl-second lsp-completion--cache)) + (lsp-completion-filter-on-incomplete + (lsp-completion--to-internal items))) + :lsp-items items + :markers markers + :prefix prefix)))))) + (:interrupted lsp-completion--last-result) + (`,res (setq lsp-completion--last-result res)))))) + (list + bounds-start + (point) + (lambda (probe _pred action) + (cond + ;; metadata + ((equal action 'metadata) + `(metadata (category . lsp-capf) + (display-sort-function . identity))) + ;; boundaries + ((equal (car-safe action) 'boundaries) nil) + ;; try-completion + ((null action) + (when-let ((cands (funcall candidates))) + (if (cl-rest cands) probe (cl-first cands)))) + ;; test-completion: not return exact match so that the selection will + ;; always be shown + ((equal action 'lambda) nil) + ;; retrieve candidates + ((equal action t) (funcall candidates)))) + :annotation-function #'lsp-completion--annotate + :company-kind #'lsp-completion--candidate-kind + :company-require-match 'never + :company-prefix-length + (save-excursion + (goto-char bounds-start) + (and (lsp-completion--looking-back-trigger-characterp trigger-chars) t)) + :company-match #'lsp-completion--company-match + :company-doc-buffer (-compose #'company-doc-buffer + #'lsp-completion--get-documentation) + :exit-function + (-rpartial #'lsp-completion--exit-fn candidates))))) + +(defun lsp-completion--exit-fn (candidate _status &optional candidates) + "Exit function of `completion-at-point'. +CANDIDATE is the selected completion item. +Others: CANDIDATES" + (unwind-protect + (-let* ((candidate (if (plist-member (text-properties-at 0 candidate) + 'lsp-completion-item) + candidate + (cl-find candidate (funcall candidates) :test #'equal))) + ((&plist 'lsp-completion-item item + 'lsp-completion-start-point start-point + 'lsp-completion-markers markers + 'lsp-completion-prefix prefix) + (text-properties-at 0 candidate)) + ((&CompletionItem? :label :insert-text? :text-edit? :insert-text-format? + :additional-text-edits? :insert-text-mode? :command?) + item)) + (cond + (text-edit? + (apply #'delete-region markers) + (insert prefix) + (pcase text-edit? + ((TextEdit) (lsp--apply-text-edit text-edit?)) + ((InsertReplaceEdit :insert :replace :new-text) + (lsp--apply-text-edit + (lsp-make-text-edit + :new-text new-text + :range (if (or (and current-prefix-arg (eq lsp-completion-default-behaviour :replace)) + (and (not current-prefix-arg) (eq lsp-completion-default-behaviour :insert))) + insert + replace)))))) + ((or (unless (lsp-falsy? insert-text?) insert-text?) label) + (apply #'delete-region markers) + (insert prefix) + (delete-region start-point (point)) + (insert (or (unless (lsp-falsy? insert-text?) insert-text?) label)))) + + (lsp--indent-lines start-point (point) insert-text-mode?) + (when (equal insert-text-format? lsp/insert-text-format-snippet) + (lsp--expand-snippet (buffer-substring start-point (point)) + start-point + (point))) + + (when lsp-completion-enable-additional-text-edit + (if (or (get-text-property 0 'lsp-completion-resolved candidate) + (not (seq-empty-p additional-text-edits?))) + (lsp--apply-text-edits additional-text-edits? 'completion) + (-let [(callback cleanup-fn) (lsp--create-apply-text-edits-handlers)] + (lsp-completion--resolve-async + item + (-compose callback #'lsp:completion-item-additional-text-edits?) + cleanup-fn)))) + + (if (or (get-text-property 0 'lsp-completion-resolved candidate) + command?) + (when command? (lsp--execute-command command?)) + (lsp-completion--resolve-async + item + (-lambda ((&CompletionItem? :command?)) + (when command? (lsp--execute-command command?))))) + + (when (and (or + (equal lsp-signature-auto-activate t) + (memq :after-completion lsp-signature-auto-activate) + (and (memq :on-trigger-char lsp-signature-auto-activate) + (-when-let ((&SignatureHelpOptions? :trigger-characters?) + (lsp--capability :signatureHelpProvider)) + (lsp-completion--looking-back-trigger-characterp + trigger-characters?)))) + (lsp-feature? "textDocument/signatureHelp")) + (lsp-signature-activate)) + + (setq-local lsp-inhibit-lsp-hooks nil)) + (lsp-completion--clear-cache))) + +(defun lsp-completion--regex-fuz (str) + "Build a regex sequence from STR. Insert .* between each char." + (apply #'concat + (cl-mapcar + #'concat + (cons "" (cdr (seq-map (lambda (c) (format "[^%c]*" c)) str))) + (seq-map (lambda (c) + (format "\\(%s\\)" (regexp-quote (char-to-string c)))) + str)))) + +(defun lsp-completion--fuz-score (query str) + "Calculate fuzzy score for STR with query QUERY. +The return is nil or in range of (0, inf)." + (-when-let* ((md (cddr (or (get-text-property 0 'match-data str) + (let ((re (lsp-completion--regex-fuz query))) + (when (string-match re str) + (match-data)))))) + (start (pop md)) + (len (length str)) + ;; To understand how this works, consider these bad ascii(tm) + ;; diagrams showing how the pattern "foo" flex-matches + ;; "fabrobazo", "fbarbazoo" and "barfoobaz": + + ;; f abr o baz o + ;; + --- + --- + + + ;; f barbaz oo + ;; + ------ ++ + + ;; bar foo baz + ;; --- +++ --- + + ;; "+" indicates parts where the pattern matched. A "hole" in + ;; the middle of the string is indicated by "-". Note that there + ;; are no "holes" near the edges of the string. The completion + ;; score is a number bound by ]0..1]: the higher the better and + ;; only a perfect match (pattern equals string) will have score + ;; 1. The formula takes the form of a quotient. For the + ;; numerator, we use the number of +, i.e. the length of the + ;; pattern. For the denominator, it first computes + ;; + ;; hole_i_contrib = 1 + (Li-1)^1.05 for first hole + ;; hole_i_contrib = 1 + (Li-1)^0.25 for hole i of length Li + ;; + ;; The final value for the denominator is then given by: + ;; + ;; (SUM_across_i(hole_i_contrib) + 1) + ;; + (score-numerator 0) + (score-denominator 0) + (last-b -1) + (q-ind 0) + (update-score + (lambda (a b) + "Update score variables given match range (A B)." + (setq score-numerator (+ score-numerator (- b a))) + (unless (= a len) + ;; case mis-match will be pushed to near next rank + (unless (equal (aref query q-ind) (aref str a)) + (cl-incf a 0.9)) + (setq score-denominator + (+ score-denominator + (if (= a last-b) 0 + (+ 1 (* (if (< 0 (- a last-b 1)) 1 -1) + (expt (abs (- a last-b 1)) + ;; Give a higher score for match near start + (if (eq last-b -1) 0.75 0.25)))))))) + (setq last-b b)))) + (while md + (funcall update-score start (cl-first md)) + ;; Due to the way completion regex is constructed, `(eq end (+ start 1))` + (cl-incf q-ind) + (pop md) + (setq start (pop md))) + (unless (zerop len) + (/ score-numerator (1+ score-denominator) 1.0)))) + +(defun lsp-completion--fix-resolve-data (item) + ;; patch `CompletionItem' for rust-analyzer otherwise resolve will fail + ;; see #2675 + (let ((data (lsp:completion-item-data? item))) + (when (lsp-member? data :import_for_trait_assoc_item) + (unless (lsp-get data :import_for_trait_assoc_item) + (lsp-put data :import_for_trait_assoc_item :json-false))))) + +(defun lsp-completion--resolve (item) + "Resolve completion ITEM." + (cl-assert item nil "Completion item must not be nil") + (lsp-completion--fix-resolve-data item) + (or (ignore-errors + (when (lsp-feature? "completionItem/resolve") + (lsp-request "completionItem/resolve" item))) + item)) + +(defun lsp-completion--resolve-async (item callback &optional cleanup-fn) + "Resolve completion ITEM asynchronously with CALLBACK. +The CLEANUP-FN will be called to cleanup." + (cl-assert item nil "Completion item must not be nil") + (lsp-completion--fix-resolve-data item) + (ignore-errors + (if (lsp-feature? "completionItem/resolve") + (lsp-request-async "completionItem/resolve" item + (lambda (result) + (funcall callback result) + (when cleanup-fn (funcall cleanup-fn))) + :error-handler (lambda (err) + (when cleanup-fn (funcall cleanup-fn)) + (error (lsp:json-error-message err))) + :cancel-handler cleanup-fn + :mode 'alive) + (funcall callback item) + (when cleanup-fn (funcall cleanup-fn))))) + + +;;;###autoload +(defun lsp-completion--enable () + "Enable LSP completion support." + (when (and lsp-completion-enable + (lsp-feature? "textDocument/completion")) + (lsp-completion-mode 1))) + +(defun lsp-completion--disable () + "Disable LSP completion support." + (lsp-completion-mode -1)) + +;;;###autoload +(define-minor-mode lsp-completion-mode + "Toggle LSP completion support." + :group 'lsp-completion + :global nil + :lighter "" + (let ((completion-started-fn (lambda (&rest _) + (setq-local lsp-inhibit-lsp-hooks t))) + (after-completion-fn (lambda (result) + (when (stringp result) + (lsp-completion--clear-cache)) + (setq-local lsp-inhibit-lsp-hooks nil)))) + (cond + (lsp-completion-mode + (setq-local completion-at-point-functions nil) + (add-hook 'completion-at-point-functions #'lsp-completion-at-point nil t) + (setq-local completion-category-defaults + (add-to-list 'completion-category-defaults '(lsp-capf (styles basic)))) + + (cond + ((equal lsp-completion-provider :none)) + ((and (not (equal lsp-completion-provider :none)) + (fboundp 'company-mode)) + (setq-local company-abort-on-unique-match nil) + (company-mode 1) + (setq-local company-backends (cl-adjoin 'company-capf company-backends :test #'equal))) + (t + (lsp--warn "Unable to autoconfigure company-mode."))) + + (when (bound-and-true-p company-mode) + (add-hook 'company-completion-started-hook + completion-started-fn + nil + t) + (add-hook 'company-after-completion-hook + after-completion-fn + nil + t)) + (add-hook 'lsp-unconfigure-hook #'lsp-completion--disable nil t)) + (t + (remove-hook 'completion-at-point-functions #'lsp-completion-at-point t) + (setq-local completion-category-defaults + (cl-remove 'lsp-capf completion-category-defaults :key #'cl-first)) + (remove-hook 'lsp-unconfigure-hook #'lsp-completion--disable t) + (when (featurep 'company) + (remove-hook 'company-completion-started-hook + completion-started-fn + t) + (remove-hook 'company-after-completion-hook + after-completion-fn + t)))))) + +;;;###autoload +(add-hook 'lsp-configure-hook (lambda () + (when (and lsp-auto-configure + lsp-completion-enable) + (lsp-completion--enable)))) + +(lsp-consistency-check lsp-completion) + +(provide 'lsp-completion) +;;; lsp-completion.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-crystal.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-crystal.el new file mode 100644 index 0000000..f0aca59 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-crystal.el @@ -0,0 +1,48 @@ +;;; lsp-crystal.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, crystal + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the Crystal Programming Language. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-scry nil + "LSP support for Crystal via scry." + :group 'lsp-mode + :link '(url-link "https://github.com/crystal-lang-tools/scry")) + +(defcustom lsp-clients-crystal-executable '("scry" "--stdio") + "Command to start the scry language server." + :group 'lsp-scry + :risky t + :type 'file) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection lsp-clients-crystal-executable) + :major-modes '(crystal-mode) + :server-id 'scry)) + +(lsp-consistency-check lsp-crystal) + +(provide 'lsp-crystal) +;;; lsp-crystal.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-csharp.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-csharp.el new file mode 100644 index 0000000..ea36425 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-csharp.el @@ -0,0 +1,365 @@ +;;; lsp-csharp.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Jostein Kjønigsen, Saulius Menkevicius + +;; Author: Saulius Menkevicius <saulius.menkevicius@fastmail.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; lsp-csharp client + +;;; Code: + +(require 'lsp-mode) +(require 'gnutls) +(require 'f) + +(defgroup lsp-csharp nil + "LSP support for C#, using the Omnisharp Language Server. +Version 1.34.3 minimum is required." + :group 'lsp-mode + :link '(url-link "https://github.com/OmniSharp/omnisharp-roslyn")) + +(defcustom lsp-csharp-server-install-dir + (f-join lsp-server-install-dir "omnisharp-roslyn/") + "Installation directory for OmniSharp Roslyn server." + :group 'lsp-csharp + :type 'directory) + +(defcustom lsp-csharp-server-path + nil + "The path to the OmniSharp Roslyn language-server binary. +Set this if you have the binary installed or have it built yourself." + :group 'lsp-csharp + :type '(string :tag "Single string value or nil")) + +(defcustom lsp-csharp-test-run-buffer-name + "*lsp-csharp test run*" + "The name of buffer used for outputing lsp-csharp test run results." + :group 'lsp-csharp + :type 'string) + +(defcustom lsp-csharp-solution-file + nil + "Solution to load when starting the server. +Usually this is to be set in your .dir-locals.el on the project root directory." + :group 'lsp-csharp + :type 'string) + +(defcustom lsp-csharp-omnisharp-roslyn-download-url + (concat "https://github.com/omnisharp/omnisharp-roslyn/releases/latest/download/" + (cond ((eq system-type 'windows-nt) + ; On Windows we're trying to avoid a crash starting 64bit .NET PE binaries in + ; Emacs by using x86 version of omnisharp-roslyn on older (<= 26.4) versions + ; of Emacs. See https://lists.nongnu.org/archive/html/bug-gnu-emacs/2017-06/msg00893.html" + (if (and (string-match "^x86_64-.*" system-configuration) + (version<= "26.4" emacs-version)) + "omnisharp-win-x64.zip" + "omnisharp-win-x86.zip")) + + ((eq system-type 'darwin) + "omnisharp-osx.zip") + + ((and (eq system-type 'gnu/linux) + (or (eq (string-match "^x86_64" system-configuration) 0) + (eq (string-match "^i[3-6]86" system-configuration) 0))) + "omnisharp-linux-x64.zip") + + (t "omnisharp-mono.zip"))) + "Automatic download url for omnisharp-roslyn." + :group 'lsp-csharp + :type 'string) + +(defcustom lsp-csharp-omnisharp-roslyn-store-path + (f-join lsp-csharp-server-install-dir "latest" "omnisharp-roslyn.zip") + "The path where omnisharp-roslyn .zip archive will be stored." + :group 'lsp-csharp + :type 'file) + +(defcustom lsp-csharp-omnisharp-roslyn-server-dir + (f-join lsp-csharp-server-install-dir "latest" "omnisharp-roslyn") + "The path where omnisharp-roslyn .zip archive will be extracted." + :group 'lsp-csharp + :type 'file) + +(lsp-dependency + 'omnisharp-roslyn + `(:download :url lsp-csharp-omnisharp-roslyn-download-url + :store-path lsp-csharp-omnisharp-roslyn-store-path)) + +(defun lsp-csharp--download-server (_client callback error-callback _update?) + "Download zip package for omnisharp-roslyn and install it. +Will invoke CALLBACK on success, ERROR-CALLBACK on error." + (lsp-package-ensure + 'omnisharp-roslyn + (lambda () + (lsp-unzip lsp-csharp-omnisharp-roslyn-store-path + lsp-csharp-omnisharp-roslyn-server-dir) + (unless (eq system-type 'windows-nt) + (let ((run-script (f-join lsp-csharp-omnisharp-roslyn-server-dir "run"))) + (when (not (f-exists-p run-script)) + ; create the `run' script when missing (e.g. when server binaries are extracted from omnisharp-mono.zip) + ; NOTE: we do not check for presence or version of mono in the system + (with-temp-file run-script + (insert "#!/bin/bash\n") + (insert "BASEDIR=$(dirname \"$0\")\n") + (insert "exec mono $BASEDIR/OmniSharp.exe $@\n"))) + (set-file-modes run-script #o755))) + (funcall callback)) + error-callback)) + +(defun lsp-csharp--language-server-path () + "Resolve path to use to start the server." + (if lsp-csharp-server-path + lsp-csharp-server-path + (let ((server-dir lsp-csharp-omnisharp-roslyn-server-dir)) + (when (f-exists? server-dir) + (f-join server-dir (cond ((eq system-type 'windows-nt) "OmniSharp.exe") + (t "run"))))))) + +(defun lsp-csharp--language-server-command () + "Resolves path and arguments to use to start the server." + (append + (list (lsp-csharp--language-server-path) "-lsp") + (when lsp-csharp-solution-file (list "-s" (expand-file-name lsp-csharp-solution-file))))) + +(lsp-defun lsp-csharp-open-project-file () + "Open corresponding project file (.csproj) for the current file." + (interactive) + (-let* ((project-info-req (lsp-make-omnisharp-project-information-request :file-name (buffer-file-name))) + (project-info (lsp-request "o#/project" project-info-req)) + ((&omnisharp:ProjectInformation :ms-build-project) project-info) + ((&omnisharp:MsBuildProject :path) ms-build-project)) + (find-file path))) + +(defun lsp-csharp--get-buffer-code-elements () + "Retrieve code structure by calling into the /v2/codestructure endpoint. +Returns :elements from omnisharp:CodeStructureResponse." + (-let* ((code-structure (lsp-request "o#/v2/codestructure" + (lsp-make-omnisharp-code-structure-request :file-name (buffer-file-name)))) + ((&omnisharp:CodeStructureResponse :elements) code-structure)) + elements)) + +(defun lsp-csharp--inspect-code-elements-recursively (fn elements) + "Invoke FN for every omnisharp:CodeElement found recursively in ELEMENTS." + (seq-each + (lambda (el) + (funcall fn el) + (-let (((&omnisharp:CodeElement :children) el)) + (lsp-csharp--inspect-code-elements-recursively fn children))) + elements)) + +(defun lsp-csharp--collect-code-elements-recursively (predicate elements) + "Flatten the omnisharp:CodeElement tree in ELEMENTS matching PREDICATE." + (let ((results nil)) + (lsp-csharp--inspect-code-elements-recursively (lambda (el) + (when (funcall predicate el) + (setq results (cons el results)))) + elements) + results)) + +(lsp-defun lsp-csharp--l-c-within-range (l c (&omnisharp:Range :start :end)) + "Determine if L (line) and C (column) are within RANGE." + (-let* (((&omnisharp:Point :line start-l :column start-c) start) + ((&omnisharp:Point :line end-l :column end-c) end)) + (or (and (= l start-l) (>= c start-c) (or (> end-l start-l) (<= c end-c))) + (and (> l start-l) (< l end-l)) + (and (= l end-l) (<= c end-c))))) + +(defun lsp-csharp--code-element-stack-on-l-c (l c elements) + "Return omnisharp:CodeElement stack at L (line) and C (column) in ELEMENTS tree." + (when-let ((matching-element (seq-find (lambda (el) + (-when-let* (((&omnisharp:CodeElement :ranges) el) + ((&omnisharp:RangeList :full?) ranges)) + (lsp-csharp--l-c-within-range l c full?))) + elements))) + (-let (((&omnisharp:CodeElement :children) matching-element)) + (cons matching-element (lsp-csharp--code-element-stack-on-l-c l c children))))) + +(defun lsp-csharp--code-element-stack-at-point () + "Return omnisharp:CodeElement stack at point as a list." + (let ((pos-line (plist-get (lsp--cur-position) :line)) + (pos-col (plist-get (lsp--cur-position) :character))) + (lsp-csharp--code-element-stack-on-l-c pos-line + pos-col + (lsp-csharp--get-buffer-code-elements)))) + +(lsp-defun lsp-csharp--code-element-test-method-p (element) + "Return test method name and test framework for a given ELEMENT." + (when element + (-when-let* (((&omnisharp:CodeElement :properties) element) + ((&omnisharp:CodeElementProperties :test-method-name? :test-framework?) properties)) + (list test-method-name? test-framework?)))) + +(defun lsp-csharp--reset-test-buffer (present-buffer) + "Create new or reuse an existing test result output buffer. +PRESENT-BUFFER will make the buffer be presented to the user." + (with-current-buffer (get-buffer-create lsp-csharp-test-run-buffer-name) + (compilation-mode) + (read-only-mode) + (let ((inhibit-read-only t)) + (erase-buffer))) + + (when present-buffer + (display-buffer lsp-csharp-test-run-buffer-name))) + +(defun lsp-csharp--start-tests (test-method-framework test-method-names) + "Run test(s) identified by TEST-METHOD-NAMES using TEST-METHOD-FRAMEWORK." + (if (and test-method-framework test-method-names) + (let ((request-message (lsp-make-omnisharp-run-tests-in-class-request + :file-name (buffer-file-name) + :test-frameworkname test-method-framework + :method-names (vconcat test-method-names)))) + (lsp-csharp--reset-test-buffer t) + (lsp-session-set-metadata "last-test-method-framework" test-method-framework) + (lsp-session-set-metadata "last-test-method-names" test-method-names) + (lsp-request-async "o#/v2/runtestsinclass" + request-message + (-lambda ((&omnisharp:RunTestResponse)) + (message "lsp-csharp: Test run has started")))) + (message "lsp-csharp: No test methods to run"))) + +(defun lsp-csharp--test-message (message) + "Emit a MESSAGE to lsp-csharp test run buffer." + (when-let ((existing-buffer (get-buffer lsp-csharp-test-run-buffer-name)) + (inhibit-read-only t)) + (with-current-buffer existing-buffer + (save-excursion + (goto-char (point-max)) + (insert message "\n"))))) + +(defun lsp-csharp-run-test-at-point () + "Start test run at current point (if any)." + (interactive) + (let* ((stack (lsp-csharp--code-element-stack-at-point)) + (element-on-point (car (last stack))) + (test-method (lsp-csharp--code-element-test-method-p element-on-point)) + (test-method-name (car test-method)) + (test-method-framework (car (cdr test-method)))) + (lsp-csharp--start-tests test-method-framework (list test-method-name)))) + +(defun lsp-csharp-run-all-tests-in-buffer () + "Run all test methods in the current buffer." + (interactive) + (let* ((elements (lsp-csharp--get-buffer-code-elements)) + (test-methods (lsp-csharp--collect-code-elements-recursively 'lsp-csharp--code-element-test-method-p elements)) + (test-method-framework (car (cdr (lsp-csharp--code-element-test-method-p (car test-methods))))) + (test-method-names (mapcar (lambda (method) + (car (lsp-csharp--code-element-test-method-p method))) + test-methods))) + (lsp-csharp--start-tests test-method-framework test-method-names))) + +(defun lsp-csharp-run-test-in-buffer () + "Run selected test in current buffer." + (interactive) + (when-let* ((elements (lsp-csharp--get-buffer-code-elements)) + (test-methods (lsp-csharp--collect-code-elements-recursively 'lsp-csharp--code-element-test-method-p elements)) + (test-method-framework (car (cdr (lsp-csharp--code-element-test-method-p (car test-methods))))) + (test-method-names (mapcar (lambda (method) + (car (lsp-csharp--code-element-test-method-p method))) + test-methods)) + (selected-test-method-name (lsp--completing-read "Select test:" test-method-names 'identity))) + (lsp-csharp--start-tests test-method-framework (list selected-test-method-name)))) + +(defun lsp-csharp-run-last-tests () + "Re-run test(s) that were run last time." + (interactive) + (if-let ((last-test-method-framework (lsp-session-get-metadata "last-test-method-framework")) + (last-test-method-names (lsp-session-get-metadata "last-test-method-names"))) + (lsp-csharp--start-tests last-test-method-framework last-test-method-names) + (message "lsp-csharp: No test method(s) found to be ran previously on this workspace"))) + +(lsp-defun lsp-csharp--handle-os-error (_workspace (&omnisharp:ErrorMessage :file-name :text)) + "Handle the 'o#/error' (interop) notification by displaying a message with lsp-warn." + (lsp-warn "%s: %s" file-name text)) + +(lsp-defun lsp-csharp--handle-os-testmessage (_workspace (&omnisharp:TestMessageEvent :message)) + "Handle the 'o#/testmessage and display test message on lsp-csharp +test output buffer." + (lsp-csharp--test-message message)) + +(lsp-defun lsp-csharp--handle-os-testcompleted (_workspace (&omnisharp:DotNetTestResult + :method-name + :outcome + :error-message + :error-stack-trace + :standard-output + :standard-error)) + "Handle the 'o#/testcompleted' message from the server. + +Will display the results of the test on the lsp-csharp test output buffer." + (let ((passed (string-equal "passed" outcome))) + (lsp-csharp--test-message + (format "[%s] %s " + (propertize (upcase outcome) 'font-lock-face (if passed 'success 'error)) + method-name)) + + (unless passed + (lsp-csharp--test-message error-message) + + (when error-stack-trace + (lsp-csharp--test-message error-stack-trace)) + + (unless (seq-empty-p standard-output) + (lsp-csharp--test-message "STANDARD OUTPUT:") + (seq-doseq (stdout-line standard-output) + (lsp-csharp--test-message stdout-line))) + + (unless (seq-empty-p standard-error) + (lsp-csharp--test-message "STANDARD ERROR:") + (seq-doseq (stderr-line standard-error) + (lsp-csharp--test-message stderr-line)))))) + +(lsp-defun lsp-csharp--action-client-find-references ((&Command :arguments?)) + "Read first argument from ACTION as Location and display xrefs for that location +using the `textDocument/references' request." + (-if-let* (((&Location :uri :range) (lsp-seq-first arguments?)) + ((&Range :start range-start) range) + (find-refs-params (append (lsp--text-document-position-params (list :uri uri) range-start) + (list :context (list :includeDeclaration json-false)))) + (locations-found (lsp-request "textDocument/references" find-refs-params))) + (lsp-show-xrefs (lsp--locations-to-xref-items locations-found) nil t) + (message "No references found"))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + #'lsp-csharp--language-server-command + (lambda () + (when-let ((binary (lsp-csharp--language-server-path))) + (f-exists? binary)))) + + :major-modes '(csharp-mode csharp-tree-sitter-mode) + :server-id 'csharp + :action-handlers (ht ("omnisharp/client/findReferences" 'lsp-csharp--action-client-find-references)) + :notification-handlers (ht ("o#/projectadded" 'ignore) + ("o#/projectchanged" 'ignore) + ("o#/projectremoved" 'ignore) + ("o#/packagerestorestarted" 'ignore) + ("o#/msbuildprojectdiagnostics" 'ignore) + ("o#/packagerestorefinished" 'ignore) + ("o#/unresolveddependencies" 'ignore) + ("o#/error" 'lsp-csharp--handle-os-error) + ("o#/testmessage" 'lsp-csharp--handle-os-testmessage) + ("o#/testcompleted" 'lsp-csharp--handle-os-testcompleted) + ("o#/projectconfiguration" 'ignore) + ("o#/projectdiagnosticstatus" 'ignore)) + :download-server-fn #'lsp-csharp--download-server)) + +(lsp-consistency-check lsp-csharp) + +(provide 'lsp-csharp) +;;; lsp-csharp.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-css.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-css.el new file mode 100644 index 0000000..2363699 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-css.el @@ -0,0 +1,254 @@ +;;; lsp-css.el --- CSS language server configuration -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Ivan Yonchovski + +;; Author: Ivan Yonchovski <yyoncho@gmail.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; + +;;; Code: + +(require 'lsp-protocol) +(require 'lsp-mode) + +(defgroup lsp-css nil + "LSP support for CSS." + :group 'lsp-mode + :link '(url-link + "https://github.com/vscode-langservers/vscode-css-languageserver-bin")) + +(defcustom lsp-css-experimental-custom-data nil + "A list of JSON file paths that define custom CSS data that +loads custom properties, at directives, pseudo classes / +elements." + :type '(repeat string)) + +(defcustom lsp-css-completion-trigger-property-value-completion t + "By default, VS Code triggers property value completion after +selecting a CSS property. Use this setting to disable this +behavior." + :type 'boolean) + +(defcustom lsp-css-validate t + "Enables or disables all validations." + :type 'boolean) + +(defcustom lsp-css-lint-compatible-vendor-prefixes "ignore" + "When using a vendor-specific prefix make sure to also include +all other vendor-specific properties." + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-vendor-prefix "warning" + "When using a vendor-specific prefix, also include the standard +property." + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-duplicate-properties "ignore" + "Do not use duplicate style definitions." + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-empty-rules "warning" + "Do not use empty rulesets." + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-import-statement "ignore" + "Import statements do not load in parallel." + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-box-model "ignore" + nil + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-universal-selector "ignore" + nil + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-zero-units "ignore" + "No unit for zero needed." + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-font-face-properties "warning" + nil + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-hex-color-length "error" + "Hex colors must consist of three or six hex numbers." + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-arguments-in-color-function "error" + "Invalid number of parameters." + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-unknown-properties "warning" + "Unknown property." + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-valid-properties nil + "A list of properties that are not validated against the +`unknownProperties` rule." + :type '(repeat string)) + +(defcustom lsp-css-lint-ie-hack "ignore" + "IE hacks are only necessary when supporting IE7 and older." + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-unknown-vendor-specific-properties "ignore" + "Unknown vendor specific property." + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-property-ignored-due-to-display "warning" + nil + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-important "ignore" + nil + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-float "ignore" + nil + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-id-selector "ignore" + "Selectors should not contain IDs because these rules are too +tightly coupled with the HTML." + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-lint-unknown-at-rules "warning" + "Unknown at-rule." + :type '(choice + (const "ignore") + (const "warning") + (const "error"))) + +(defcustom lsp-css-trace-server "off" + "Traces the communication between VS Code and the CSS language +server." + :type '(choice + (const "off") + (const "messages") + (const "verbose"))) + +(lsp-register-custom-settings + '(("css.trace.server" lsp-css-trace-server) + ("css.lint.unknownAtRules" lsp-css-lint-unknown-at-rules) + ("css.lint.idSelector" lsp-css-lint-id-selector) + ("css.lint.float" lsp-css-lint-float) + ("css.lint.important" lsp-css-lint-important) + ("css.lint.propertyIgnoredDueToDisplay" lsp-css-lint-property-ignored-due-to-display) + ("css.lint.unknownVendorSpecificProperties" lsp-css-lint-unknown-vendor-specific-properties) + ("css.lint.ieHack" lsp-css-lint-ie-hack) + ("css.lint.validProperties" lsp-css-lint-valid-properties) + ("css.lint.unknownProperties" lsp-css-lint-unknown-properties) + ("css.lint.argumentsInColorFunction" lsp-css-lint-arguments-in-color-function) + ("css.lint.hexColorLength" lsp-css-lint-hex-color-length) + ("css.lint.fontFaceProperties" lsp-css-lint-font-face-properties) + ("css.lint.zeroUnits" lsp-css-lint-zero-units) + ("css.lint.universalSelector" lsp-css-lint-universal-selector) + ("css.lint.boxModel" lsp-css-lint-box-model) + ("css.lint.importStatement" lsp-css-lint-import-statement) + ("css.lint.emptyRules" lsp-css-lint-empty-rules) + ("css.lint.duplicateProperties" lsp-css-lint-duplicate-properties) + ("css.lint.vendorPrefix" lsp-css-lint-vendor-prefix) + ("css.lint.compatibleVendorPrefixes" lsp-css-lint-compatible-vendor-prefixes) + ("css.validate" lsp-css-validate t) + ("css.completion.triggerPropertyValueCompletion" lsp-css-completion-trigger-property-value-completion t) + ("css.experimental.customData" lsp-css-experimental-custom-data))) + +(defun lsp-css--server-command () + "Generate startup command for CSS language server." + (list (lsp-package-path 'css-languageserver) "--stdio")) + +;;; CSS +(lsp-defun lsp-css--apply-code-action ((&Command :arguments?)) + "Apply ACTION as workspace edit command." + (lsp--apply-text-edits (cl-caddr arguments?) 'code-action)) + +(lsp-dependency 'css-languageserver + '(:system "css-languageserver") + '(:npm :package "vscode-css-languageserver-bin" + :path "css-languageserver")) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection #'lsp-css--server-command) + :activation-fn (lsp-activate-on "css" "scss" "sass") + :priority -1 + :action-handlers (lsp-ht ("_css.applyCodeAction" #'lsp-css--apply-code-action)) + :server-id 'css-ls + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'css-languageserver callback error-callback)))) + +(lsp-consistency-check lsp-css) + +(provide 'lsp-css) +;;; lsp-css.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-d.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-d.el new file mode 100644 index 0000000..f9c7b13 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-d.el @@ -0,0 +1,37 @@ +;;; lsp-d.el --- lsp-mode dlang integration -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 lsp-mode maintainers + +;; Author: lsp-mode maintainers +;; Keywords: languages + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; client for serve-d + +;;; Code: + +(require 'lsp-mode) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection "serve-d") + :major-modes '(d-mode) + :server-id 'serve-d)) + +(lsp-consistency-check lsp-d) + +(provide 'lsp-d) +;;; lsp-d.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-dhall.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-dhall.el new file mode 100644 index 0000000..7b10597 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-dhall.el @@ -0,0 +1,43 @@ +;;; lsp-dhall.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, dhall + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the Dhall Programming Language. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-dhall nil + "LSP support for Dhall, using dhall-lsp-server." + :group 'lsp-mode + :link '(url-link "https://github.com/dhall-lang/dhall-haskell")) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection "dhall-lsp-server") + :major-modes '(dhall-mode) + :priority -1 + :server-id 'dhallls)) + +(lsp-consistency-check lsp-dhall) + +(provide 'lsp-dhall) +;;; lsp-dhall.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-diagnostics.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-diagnostics.el new file mode 100644 index 0000000..ac1512d --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-diagnostics.el @@ -0,0 +1,369 @@ +;;; lsp-diagnostics.el --- LSP diagnostics integration -*- lexical-binding: t; -*- +;; +;; Copyright (C) 2020 emacs-lsp maintainers +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. +;; +;;; Commentary: +;; +;; LSP diagnostics integration +;; +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-diagnostics nil + "LSP support for diagnostics" + :prefix "lsp-disagnostics-" + :group 'lsp-mode + :tag "LSP Diagnostics") + +;;;###autoload +(define-obsolete-variable-alias 'lsp-diagnostic-package + 'lsp-diagnostics-provider "lsp-mode 7.0.1") + +(defcustom lsp-diagnostics-provider :auto + "The checker backend provider." + :type + '(choice + (const :tag "Pick flycheck if present and fallback to flymake" :auto) + (const :tag "Pick flycheck" :flycheck) + (const :tag "Pick flymake" :flymake) + (const :tag "Use neither flymake nor lsp" :none) + (const :tag "Prefer flymake" t) + (const :tag "Prefer flycheck" nil)) + :group 'lsp-diagnostics + :package-version '(lsp-mode . "6.3")) + +;;;###autoload +(define-obsolete-variable-alias 'lsp-flycheck-default-level + 'lsp-diagnostics-flycheck-default-level "lsp-mode 7.0.1") + +(defcustom lsp-diagnostics-flycheck-default-level 'error + "Error level to use when the server does not report back a diagnostic level." + :type '(choice + (const error) + (const warning) + (const info)) + :group 'lsp-diagnostics) + +(defcustom lsp-diagnostics-attributes + `((unnecessary :foreground "gray") + (deprecated :strike-through t)) + "The Attributes used on the diagnostics. +List containing (tag attributes) where tag is the LSP diagnostic tag and +attributes is a `plist' containing face attributes which will be applied +on top the flycheck face for that error level." + :type '(repeat list) + :group 'lsp-diagnostics) + +(defcustom lsp-diagnostics-disabled-modes nil + "A list of major models for which `lsp-diagnostics-mode' should be disabled." + :type '(repeat symbol) + :group 'lsp-diagnostics + :package-version '(lsp-mode . "7.1")) + +;; Flycheck integration + +(declare-function flycheck-mode "ext:flycheck") +(declare-function flycheck-define-generic-checker + "ext:flycheck" (symbol docstring &rest properties)) +(declare-function flycheck-error-new "ext:flycheck" t t) +(declare-function flycheck-error-message "ext:flycheck" (err) t) +(declare-function flycheck-define-error-level "ext:flycheck" (level &rest properties)) +(declare-function flycheck-buffer "ext:flycheck") +(declare-function flycheck-valid-checker-p "ext:flycheck") +(declare-function flycheck-stop "ext:flycheck") + +(defvar flycheck-mode) +(defvar flycheck-check-syntax-automatically) +(defvar flycheck-checker) +(defvar flycheck-checkers) + + +(defvar-local lsp-diagnostics--flycheck-enabled nil + "True when lsp diagnostics flycheck integration has been enabled in this buffer.") + +(defvar-local lsp-diagnostics--flycheck-checker nil + "The value of flycheck-checker before lsp diagnostics was activated.") + +(defun lsp-diagnostics--flycheck-level (flycheck-level tags) + "Generate flycheck level from the original FLYCHECK-LEVEL (e. +g. `error', `warning') and list of LSP TAGS." + (let ((name (format "lsp-flycheck-%s-%s" + flycheck-level + (mapconcat #'symbol-name tags "-")))) + (or (intern-soft name) + (let* ((face (--doto (intern (format "lsp-%s-face" name)) + (copy-face (-> flycheck-level + (get 'flycheck-overlay-category) + (get 'face)) + it) + (mapc (lambda (tag) + (apply #'set-face-attribute it nil + (cl-rest (assoc tag lsp-diagnostics-attributes)))) + tags))) + (category (--doto (intern (format "lsp-%s-category" name)) + (setf (get it 'face) face + (get it 'priority) 100))) + (new-level (intern name)) + (bitmap (or (get flycheck-level 'flycheck-fringe-bitmaps) + (get flycheck-level 'flycheck-fringe-bitmap-double-arrow)))) + (flycheck-define-error-level new-level + :severity (get flycheck-level 'flycheck-error-severity) + :compilation-level (get flycheck-level 'flycheck-compilation-level) + :overlay-category category + :fringe-bitmap bitmap + :fringe-face (get flycheck-level 'flycheck-fringe-face) + :error-list-face face) + new-level)))) + +(defun lsp-diagnostics--flycheck-calculate-level (severity tags) + "Calculate flycheck level by SEVERITY and TAGS." + (let ((level (pcase severity + (1 'error) + (2 'warning) + (3 'info) + (4 'info) + (_ lsp-flycheck-default-level))) + ;; materialize only first tag. + (tags (seq-map (lambda (tag) + (cond + ((= tag lsp/diagnostic-tag-unnecessary) 'unnecessary) + ((= tag lsp/diagnostic-tag-deprecated) 'deprecated))) + tags))) + (if tags + (lsp-diagnostics--flycheck-level level tags) + level))) + +(defun lsp-diagnostics--flycheck-start (checker callback) + "Start an LSP syntax check with CHECKER. + +CALLBACK is the status callback passed by Flycheck." + + (remove-hook 'lsp-on-idle-hook #'lsp-diagnostics--flycheck-buffer t) + + (->> (lsp--get-buffer-diagnostics) + (-map (-lambda ((&Diagnostic :message :severity? :tags? :code? :source? + :range (&Range :start (&Position :line start-line + :character start-character) + :end (&Position :line end-line + :character end-character)))) + (flycheck-error-new + :buffer (current-buffer) + :checker checker + :filename buffer-file-name + :message message + :level (lsp-diagnostics--flycheck-calculate-level severity? tags?) + :id code? + :group source? + :line (lsp-translate-line (1+ start-line)) + :column (1+ (lsp-translate-column start-character)) + :end-line (lsp-translate-line (1+ end-line)) + :end-column (1+ (lsp-translate-column end-character))))) + (funcall callback 'finished))) + +(defun lsp-diagnostics--flycheck-buffer () + "Trigger flyckeck on buffer." + (remove-hook 'lsp-on-idle-hook #'lsp-diagnostics--flycheck-buffer t) + (flycheck-buffer)) + +(defun lsp-diagnostics--flycheck-report () + "Report flycheck. +This callback is invoked when new diagnostics are received +from the language server." + (when (and (or (memq 'idle-change flycheck-check-syntax-automatically) + (and (memq 'save flycheck-check-syntax-automatically) + (not (buffer-modified-p)))) + lsp--cur-workspace) + ;; make sure diagnostics are published even if the diagnostics + ;; have been received after idle-change has been triggered + (->> lsp--cur-workspace + (lsp--workspace-buffers) + (mapc (lambda (buffer) + (when (and (lsp-buffer-live-p buffer) + (or + (not (bufferp buffer)) + (and (get-buffer-window buffer) + (not (-contains? (buffer-local-value 'lsp-on-idle-hook buffer) + 'lsp-diagnostics--flycheck-buffer))))) + (lsp-with-current-buffer buffer + (add-hook 'lsp-on-idle-hook #'lsp-diagnostics--flycheck-buffer nil t) + (lsp--idle-reschedule (current-buffer))))))))) + +(cl-defgeneric lsp-diagnostics-flycheck-error-explainer (e _server-id) + "Explain a `flycheck-error' E in a generic way depending on the SERVER-ID." + (flycheck-error-message e)) + +(defvar lsp-diagnostics-mode) ;; properly defined by define-minor-mode below + +;;;###autoload +(defun lsp-diagnostics-lsp-checker-if-needed () + (unless (flycheck-valid-checker-p 'lsp) + (flycheck-define-generic-checker 'lsp + "A syntax checker using the Language Server Protocol (LSP) +provided by lsp-mode. +See https://github.com/emacs-lsp/lsp-mode." + :start #'lsp-diagnostics--flycheck-start + :modes '(lsp-placeholder-mode) ;; placeholder + :predicate (lambda () lsp-diagnostics-mode) + :error-explainer (lambda (e) + (lsp-diagnostics-flycheck-error-explainer + e (lsp--workspace-server-id (car-safe (lsp-workspaces)))))))) + +(defun lsp-diagnostics-flycheck-enable (&rest _) + "Enable flycheck integration for the current buffer." + (require 'flycheck) + (lsp-diagnostics-lsp-checker-if-needed) + (and (not lsp-diagnostics--flycheck-enabled) + (not (eq flycheck-checker 'lsp)) + (setq lsp-diagnostics--flycheck-checker flycheck-checker)) + (setq-local lsp-diagnostics--flycheck-enabled t) + (flycheck-mode 1) + (flycheck-stop) + (setq-local flycheck-checker 'lsp) + (lsp-flycheck-add-mode major-mode) + (add-to-list 'flycheck-checkers 'lsp) + (add-hook 'lsp-diagnostics-updated-hook #'lsp-diagnostics--flycheck-report nil t) + (add-hook 'lsp-managed-mode-hook #'lsp-diagnostics--flycheck-report nil t)) + +(defun lsp-diagnostics-flycheck-disable () + "Disable flycheck integration for the current buffer is it was enabled." + (when lsp-diagnostics--flycheck-enabled + (flycheck-stop) + (when (eq flycheck-checker 'lsp) + (setq-local flycheck-checker lsp-diagnostics--flycheck-checker)) + (setq lsp-diagnostics--flycheck-checker nil) + (setq-local lsp-diagnostics--flycheck-enabled nil) + (when flycheck-mode + (flycheck-mode 1)))) + +;; Flymake integration + +(declare-function flymake-mode "ext:flymake") +(declare-function flymake-make-diagnostic "ext:flymake") +(declare-function flymake-diag-region "ext:flymake") + +(defvar flymake-diagnostic-functions) +(defvar flymake-mode) +(defvar-local lsp-diagnostics--flymake-report-fn nil) + +(defun lsp-diagnostics--flymake-setup () + "Setup flymake." + (setq lsp-diagnostics--flymake-report-fn nil) + (add-hook 'flymake-diagnostic-functions 'lsp-diagnostics--flymake-backend nil t) + (add-hook 'lsp-diagnostics-updated-hook 'lsp-diagnostics--flymake-after-diagnostics nil t) + (flymake-mode 1)) + +(defun lsp-diagnostics--flymake-after-diagnostics () + "Handler for `lsp-diagnostics-updated-hook'." + (cond + ((and lsp-diagnostics--flymake-report-fn flymake-mode) + (lsp-diagnostics--flymake-update-diagnostics)) + ((not flymake-mode) + (setq lsp-diagnostics--flymake-report-fn nil)))) + +(defun lsp-diagnostics--flymake-backend (report-fn &rest _args) + "Flymake backend using REPORT-FN." + (let ((first-run (null lsp-diagnostics--flymake-report-fn))) + (setq lsp-diagnostics--flymake-report-fn report-fn) + (when first-run + (lsp-diagnostics--flymake-update-diagnostics)))) + +(defun lsp-diagnostics--flymake-update-diagnostics () + "Report new diagnostics to flymake." + (funcall lsp-diagnostics--flymake-report-fn + (-some->> (lsp-diagnostics t) + (gethash (lsp--fix-path-casing buffer-file-name)) + (--map (-let* (((&Diagnostic :message :severity? + :range (range &as &Range + :start (&Position :line start-line :character) + :end (&Position :line end-line))) it) + ((start . end) (lsp--range-to-region range))) + (when (= start end) + (if-let ((region (flymake-diag-region (current-buffer) + (1+ start-line) + character))) + (setq start (car region) + end (cdr region)) + (lsp-save-restriction-and-excursion + (goto-char (point-min)) + (setq start (point-at-bol (1+ start-line)) + end (point-at-eol (1+ end-line)))))) + (flymake-make-diagnostic (current-buffer) + start + end + (cl-case severity? + (1 :error) + (2 :warning) + (t :note)) + message)))) + ;; This :region keyword forces flymake to delete old diagnostics in + ;; case the buffer hasn't changed since the last call to the report + ;; function. See https://github.com/joaotavora/eglot/issues/159 + :region (cons (point-min) (point-max)))) + + + +;;;###autoload +(defun lsp-diagnostics--enable () + "Enable LSP checker support." + (when (and (member lsp-diagnostics-provider '(:auto :none :flycheck :flymake t nil)) + (not (member major-mode lsp-diagnostics-disabled-modes))) + (lsp-diagnostics-mode 1))) + +(defun lsp-diagnostics--disable () + "Disable LSP checker support." + (lsp-diagnostics-mode -1)) + +;;;###autoload +(define-minor-mode lsp-diagnostics-mode + "Toggle LSP diagnostics integration." + :group 'lsp-diagnostics + :global nil + :lighter "" + (cond + (lsp-diagnostics-mode + (cond + ((and (or + (and (eq lsp-diagnostics-provider :auto) + (functionp 'flycheck-mode)) + (and (eq lsp-diagnostics-provider :flycheck) + (or (functionp 'flycheck-mode) + (user-error "The lsp-diagnostics-provider is set to :flycheck but flycheck is not installed?"))) + ;; legacy + (null lsp-diagnostics-provider)) + (require 'flycheck nil t)) + (lsp-diagnostics-flycheck-enable)) + ((or (eq lsp-diagnostics-provider :auto) + (eq lsp-diagnostics-provider :flymake) + (eq lsp-diagnostics-provider t)) + (require 'flymake) + (lsp-diagnostics--flymake-setup)) + ((not (eq lsp-diagnostics-provider :none)) + (lsp--warn "Unable to autoconfigure flycheck/flymake. The diagnostics won't be rendered."))) + + (add-hook 'lsp-unconfigure-hook #'lsp-diagnostics--disable nil t)) + (t (lsp-diagnostics-flycheck-disable) + (remove-hook 'lsp-unconfigure-hook #'lsp-diagnostics--disable t)))) + +;;;###autoload +(add-hook 'lsp-configure-hook (lambda () + (when lsp-auto-configure + (lsp-diagnostics--enable)))) + +(lsp-consistency-check lsp-diagnostics) + +(provide 'lsp-diagnostics) +;;; lsp-diagnostics.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-dired.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-dired.el new file mode 100644 index 0000000..8b84af7 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-dired.el @@ -0,0 +1,178 @@ +;;; lsp-dired.el --- `lsp-mode' diagnostics integrated into `dired' -*- lexical-binding: t -*- + +;; Copyright (C) 2021 + +;; Author: Alexander Miller <alexanderm@web.de> +;; Author: Ivan Yonchovski <yyoncho@gmail.com> + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: +;;; `lsp-mode' diagnostics integrated into `dired' + +;;; Code: + +(require 'dired) +(require 'pcase) +(require 'lsp-mode) + +(defgroup lsp-dired nil + "LSP support for dired" + :prefix "lsp-dired-" + :group 'lsp-mode + :tag "LSP Dired") + +(defvar lsp-dired--ranger-adjust nil) +(with-eval-after-load 'ranger (setf lsp-dired--ranger-adjust t)) + +(defvar-local lsp-dired-displayed nil + "Flags whether icons have been added.") + +(defvar-local lsp-dired--covered-subdirs nil + "List of subdirs icons were already added for.") + +(defun lsp-dired--display () + "Display the icons of files in a dired buffer." + (when (and (display-graphic-p) + (not lsp-dired-displayed) + dired-subdir-alist) + (setq-local lsp-dired-displayed t) + (pcase-dolist (`(,path . ,pos) dired-subdir-alist) + (lsp-dired--insert-for-subdir path pos)))) + +(defun lsp-dired--insert-for-subdir (path pos) + "Display icons for subdir PATH at given POS." + (let ((buf (current-buffer))) + ;; run the function after current to make sure that we are creating the + ;; overlays after `treemacs-icons-dired' has run. + (run-with-idle-timer + 0.0 nil + (lambda () + (unless (and (member path lsp-dired--covered-subdirs) + (not (buffer-live-p buf))) + (with-current-buffer buf + (add-to-list 'lsp-dired--covered-subdirs path) + (let (buffer-read-only) + (save-excursion + (goto-char pos) + (forward-line (if lsp-dired--ranger-adjust 1 2)) + (cl-block :file + (while (not (eobp)) + (if (dired-move-to-filename nil) + (let* ((file (dired-get-filename nil t)) + (bol (progn + (point-at-bol) + (search-forward-regexp "^[[:space:]]*" (line-end-position) t) + (point))) + (face (lsp-dired--face-for-path file))) + (when face + (-doto (make-overlay bol (point-at-eol)) + (overlay-put 'evaporate t) + (overlay-put 'face face)))) + (cl-return-from :file nil)) + (forward-line 1))))))))))) + +(defface lsp-dired-path-face '((t :inherit font-lock-string-face)) + "Face used for breadcrumb paths on headerline." + :group 'lsp-dired) + +(defface lsp-dired-path-error-face + '((t :underline (:style wave :color "Red1"))) + "Face used for breadcrumb paths on headerline when there is an error under that path" + :group 'lsp-dired) + +(defface lsp-dired-path-warning-face + '((t :underline (:style wave :color "Yellow"))) + "Face used for breadcrumb paths on headerline when there is an warning under that path" + :group 'lsp-dired) + +(defface lsp-dired-path-info-face + '((t :underline (:style wave :color "Green"))) + "Face used for breadcrumb paths on headerline when there is an info under that path" + :group 'lsp-dired) + +(defface lsp-dired-path-hint-face + '((t :underline (:style wave :color "Green"))) + "Face used for breadcrumb paths on headerline when there is an hint under that path" + :group 'lsp-dired) + +(defun lsp-dired--face-for-path (dir) + "Calculate the face for DIR." + (when-let ((diags (lsp-diagnostics-stats-for (directory-file-name dir)))) + (cl-labels ((check-severity + (severity) + (not (zerop (aref diags severity))))) + (cond + ((check-severity lsp/diagnostic-severity-error) + 'lsp-dired-path-error-face) + ((check-severity lsp/diagnostic-severity-warning) + 'lsp-dired-path-warning-face) + ((check-severity lsp/diagnostic-severity-information) + 'lsp-dired-path-info-face) + ((check-severity lsp/diagnostic-severity-hint) + 'lsp-dired-path-hint-face))))) + +(defun lsp-dired--insert-subdir-advice (&rest args) + "Advice to dired & dired+ insert-subdir commands. +Will add icons for the subdir in the `car' of ARGS." + (let* ((path (car args)) + (pos (cdr (assoc path dired-subdir-alist)))) + (when pos + (lsp-dired--insert-for-subdir path pos)))) + +(defun lsp-dired--kill-subdir-advice (&rest _args) + "Advice to dired kill-subdir commands. +Will remove the killed subdir from `lsp-dired--covered-subdirs'." + (setf lsp-dired--covered-subdirs (delete (dired-current-directory) + lsp-dired--covered-subdirs))) + +(defun lsp-dired--reset (&rest _args) + "Reset metadata on revert." + (setq-local lsp-dired--covered-subdirs nil) + (setq-local lsp-dired-displayed nil)) + +;;;###autoload +(define-minor-mode lsp-dired-mode + "Display `lsp-mode' icons for each file in a dired buffer." + :require 'lsp-dired + :init-value nil + :global t + :group 'lsp-dired + (cond + (lsp-dired-mode + (add-hook 'dired-after-readin-hook #'lsp-dired--display) + (advice-add 'dired-kill-subdir :before #'lsp-dired--kill-subdir-advice) + (advice-add 'dired-insert-subdir :after #'lsp-dired--insert-subdir-advice) + (advice-add 'diredp-insert-subdirs :after #'lsp-dired--insert-subdir-advice) + (advice-add 'dired-revert :before #'lsp-dired--reset) + (dolist (buffer (buffer-list)) + (with-current-buffer buffer + (when (derived-mode-p 'dired-mode) + (lsp-dired--display))))) + (t + (advice-remove 'dired-kill-subdir #'lsp-dired--kill-subdir-advice) + (advice-remove 'dired-insert-subdir #'lsp-dired--insert-subdir-advice) + (advice-remove 'diredp-insert-subdirs #'lsp-dired--insert-subdir-advice) + (advice-remove 'dired-revert #'lsp-dired--reset) + (remove-hook 'dired-after-readin-hook #'lsp-dired--display) + (dolist (buffer (buffer-list)) + (with-current-buffer buffer + (when (derived-mode-p 'dired-mode) + (dired-revert))))))) + + +(lsp-consistency-check lsp-dired)(provide 'lsp-dired) + + +;;; lsp-dired.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-dockerfile.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-dockerfile.el new file mode 100644 index 0000000..a095137 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-dockerfile.el @@ -0,0 +1,66 @@ +;;; lsp-dockerfile.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, dockerfile + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for Dockerfile documents. + +;;; Code: + +(require 'lsp-mode) + + +;;; Dockerfile + +(defgroup lsp-dockerfile nil + "Dockerfile LSP client, provided by the Dockerfile Language Server." + :group 'lsp-mode + :version "7.1" + :link '(url-link "https://github.com/rcjsuen/dockerfile-language-server-nodejs")) + +(defcustom lsp-dockerfile-language-server-command + '("docker-langserver" "--stdio") + "The command that starts the docker language server." + :group 'lsp-dockerfile + :type '(repeat :tag "List of string values" string)) + +(lsp-dependency 'docker-langserver + '(:system "docker-langserver") + '(:npm :package "dockerfile-language-server-nodejs" + :path "docker-langserver")) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (lambda () + `(,(or (executable-find + (cl-first lsp-dockerfile-language-server-command)) + (lsp-package-path 'docker-langserver)) + ,@(cl-rest lsp-dockerfile-language-server-command)))) + :major-modes '(dockerfile-mode) + :priority -1 + :server-id 'dockerfile-ls + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'docker-langserver + callback error-callback)))) + +(lsp-consistency-check lsp-dockerfile) + +(provide 'lsp-dockerfile) +;;; lsp-dockerfile.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-elixir.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-elixir.el new file mode 100644 index 0000000..c36579d --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-elixir.el @@ -0,0 +1,190 @@ +;;; lsp-elixir.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, elixir + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the Elixir Programming Language. + +;;; Code: + +(require 'lsp-mode) +(require 'ht) + +(defcustom lsp-elixir-dialyzer-enabled t + "Run ElixirLS's rapid Dialyzer when code is saved." + :type 'boolean + :group 'lsp-elixir + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-elixir-dialyzer-warn-opts '() + "Dialyzer options to enable or disable warnings. + +See Dialyzer's documentation for options. Note that the \"race_conditions\" +option is unsupported" + :type '(repeat string) + :group 'lsp-elixir + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-elixir-dialyzer-format "dialyxir_long" + "Formatter to use for Dialyzer warnings." + :type 'string + :group 'lsp-elixir + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-elixir-mix-env "test" + "Mix environment to use for compilation." + :type 'string + :group 'lsp-elixir + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-elixir-mix-target nil + "Mix target to use for compilation (requires Elixir >= 1.8)." + :type 'string + :group 'lsp-elixir + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-elixir-project-dir nil + "Subdirectory containing Mix project if not in the project root. + +If value is `\"\"` then defaults to the workspace rootUri." + :type 'string + :group 'lsp-elixir + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-elixir-fetch-deps t + "Automatically fetch project dependencies when compiling." + :type 'boolean + :group 'lsp-elixir + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-elixir-suggest-specs t + "Suggest @spec annotations inline using Dialyzer's inferred success typings. +This requires Dialyzer." + :type 'boolean + :group 'lsp-elixir + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-elixir-signature-after-complete t + "Show signature help after confirming autocomplete." + :type 'boolean + :group 'lsp-elixir + :package-version '(lsp-mode . "7.1")) + +(defgroup lsp-elixir nil + "LSP support for Elixir, using elixir-ls." + :group 'lsp-mode + :link '(url-link "https://github.com/elixir-lsp/elixir-ls")) + +(define-obsolete-variable-alias 'lsp-clients-elixir-server-executable 'lsp-elixir-server-command "2021-04-05") + +(defcustom lsp-elixir-server-command + (if (equal system-type 'windows-nt) + '("language_server.bat") + '("language_server.sh")) + "Command to start elixir-ls. + +Leave as default to let `executable-find' search for it." + :group 'lsp-elixir + :type '(repeat string) + :package-version '(lsp-mode . "7.1")) + + +(defconst lsp-elixir-ls-server-dir + (f-join lsp-server-install-dir "elixir-ls") + "Elixir-ls local server Directory") + +(defcustom lsp-elixir-local-server-command + (f-join lsp-elixir-ls-server-dir + (cl-first lsp-elixir-server-command)) + "Command to start local elixir-ls binary." + :group 'lsp-elixir + :type '(repeat string) + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-elixir-enable-test-lenses t + "Suggest Tests." + :type 'boolean + :group 'lsp-elixir + :package-version '(lsp-mode . "7.1")) + +(defun lsp-elixir--build-test-command (argument) + "Builds the test command from the ARGUMENT." + (let ((test-name (lsp-get argument :testName)) + (module (lsp-get argument :module)) + (describe (lsp-get argument :describe))) + (cond (module (concat "\"" "module:" module "\"")) + ((not test-name) (concat "\"" "describe:" describe "\"")) + (describe (concat "\"" "test:test " describe " " test-name "\"" )) + (t (concat "\"" "test:test " test-name "\"" ))))) + +(lsp-defun lsp-elixir--run-test ((&Command :arguments?)) + "Runs tests." + (let* ((argument (lsp-seq-first arguments?)) + (file-path (lsp-get argument :filePath)) + (test-command (lsp-elixir--build-test-command argument))) + (compile + (concat "cd " (lsp-workspace-root file-path) " && " + "mix test --exclude test --include " test-command " " file-path + " --no-color")) + file-path)) + +(lsp-dependency 'elixir-ls + '(:system "elixir-ls")) + +(lsp-register-custom-settings + '(("elixirLS.dialyzerEnabled" lsp-elixir-dialyzer-enabled t) + ("elixirLS.dialyzerWarnOpts" lsp-elixir-dialyzer-warn-opts) + ("elixirLS.dialyzerFormat" lsp-elixir-dialyzer-format) + ("elixirLS.mixEnv" lsp-elixir-mix-env) + ("elixirLS.mixTarget" lsp-elixir-mix-target) + ("elixirLS.projectDir" lsp-elixir-project-dir) + ("elixirLS.fetchDeps" lsp-elixir-fetch-deps t) + ("elixirLS.suggestSpecs" lsp-elixir-suggest-specs t) + ("elixirLS.signatureAfterComplete" lsp-elixir-signature-after-complete t) + ("elixirLS.enableTestLenses" lsp-elixir-enable-test-lenses t))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (lambda () + `(,(or (when (f-exists? lsp-elixir-local-server-command) + lsp-elixir-local-server-command) + (or (executable-find + (cl-first lsp-elixir-server-command)) + (lsp-package-path 'elixir-ls)) + "language_server.bat") + ,@(cl-rest lsp-elixir-server-command)))) + :major-modes '(elixir-mode) + :priority -1 + :server-id 'elixir-ls + :action-handlers (ht ("elixir.lens.test.run" 'lsp-elixir--run-test)) + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration + (lsp-configuration-section "elixirLS"))) + (puthash + "textDocumentSync" + (ht ("save" t) + ("change" 2)) + (lsp--workspace-server-capabilities workspace))))) + +(lsp-consistency-check lsp-elixir) + +(provide 'lsp-elixir) +;;; lsp-elixir.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-elm.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-elm.el new file mode 100644 index 0000000..55f9f27 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-elm.el @@ -0,0 +1,137 @@ +;;; lsp-elm.el --- Elm Client settings -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Daniel V + +;; Author: Daniel V +;; Keywords: elm lsp + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; lsp-elm client + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-elm nil + "LSP support for the Elm programming language, using the server from https://github.com/elm-tooling/elm-language-server" + :group 'lsp-mode + :link '(url-link "https://github.com/elm-tooling/elm-language-server")) + +(defcustom lsp-elm-elm-language-server-path nil + "Path for elm-language-server. +Can be installed globally with: npm i -g @elm-tooling/elm-language-server, +or manually by cloning the repo and following the installing instructions." + :group 'lsp-elm + :risky t + :type 'file) + +(defcustom lsp-elm-trace-server + nil + "Enable/disable trace logging of client and server communication." + :type 'boolean + :group 'lsp-elm) + +(defcustom lsp-elm-elm-path + "" + "The path to your elm executable. + +Should be empty by default, in that case it will assume the name and try +to first get it from a local npm installation or a global one. If you +set it manually it will not try to load from the npm folder." + :type 'file + :group 'lsp-elm) + +(defcustom lsp-elm-elm-format-path + "" + "The path to your elm-format executable. + +Should be empty by default, in that case it will assume the name and try +to first get it from a local npm installation or a global one. If you +set it manually it will not try to load from the npm folder." + :type 'file + :group 'lsp-elm) + +(defcustom lsp-elm-elm-test-path + "" + "The path to your elm-test executable. + +Should be empty by default, in that case it will assume the name and try +to first get it from a local npm installation or a global one. If you +set it manually it will not try to load from the npm folder." + :type 'file + :group 'lsp-elm) + +(defcustom lsp-elm-disable-elmls-diagnostics + nil + "Enable/Disable linting diagnostics from the language server." + :type 'boolean + :group 'lsp-elm) + +(defcustom lsp-elm-only-update-diagnostics-on-save + nil + "Only update compiler diagnostics on save, not on document change." + :type 'boolean + :group 'lsp-elm) + +(defcustom lsp-elm-skip-install-package-confirmation + nil + "Skip confirmation for the Install Package code action." + :type 'boolean + :group 'lsp-elm) + +(defcustom lsp-elm-server-args + '("--stdio") + "Arguments to pass to the server." + :type '(repeat string) + :group 'lsp-elm) + +(defun lsp-elm--elm-language-server-command () + "Generate LSP startup command for the Elm Language Server." + (cons + (or lsp-elm-elm-language-server-path + (lsp-package-path 'elm-language-server)) + lsp-elm-server-args)) + +(defun lsp-clients-elm--make-init-options () + "Init options for elm-language-server." + `(:elmPath ,lsp-elm-elm-path + :elmFormatPath ,lsp-elm-elm-format-path + :elmTestPath ,lsp-elm-elm-test-path + :disableElmLSDiagnostics ,(lsp-json-bool lsp-elm-disable-elmls-diagnostics) + :onlyUpdateDiagnosticsOnSave ,(lsp-json-bool lsp-elm-only-update-diagnostics-on-save) + :skipInstallPackageConfirmation ,(lsp-json-bool lsp-elm-skip-install-package-confirmation) + :trace.server ,(lsp-json-bool lsp-elm-trace-server))) + +(lsp-dependency 'elm-language-server + '(:system "elm-language-server") + '(:npm :package "@elm-tooling/elm-language-server" + :path "elm-language-server")) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection #'lsp-elm--elm-language-server-command) + :major-modes '(elm-mode) + :priority -1 + :initialization-options #'lsp-clients-elm--make-init-options + :server-id 'elm-ls + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'elm-language-server callback error-callback)))) + +(lsp-consistency-check lsp-elm) + +(provide 'lsp-elm) +;;; lsp-elm.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-erlang.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-erlang.el new file mode 100644 index 0000000..2deae83 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-erlang.el @@ -0,0 +1,67 @@ +;;; lsp-erlang.el --- Erlang Client settings -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Roberto Aloi + +;; Author: Roberto Aloi +;; Keywords: erlang lsp + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; lsp-erlang client + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-erlang nil + "LSP support for the Erlang programming language, using erlang-ls" + :group 'lsp-mode + :link '(url-link "https://github.com/erlang-ls/erlang_ls")) + +(defcustom lsp-erlang-server-path + "erlang_ls" + "Path to the Erlang Language Server binary." + :group 'lsp-erlang + :risky t + :type 'file) + +(defcustom lsp-erlang-server-connection-type + 'stdio + "Type of connection to use with the Erlang Language Server: tcp or stdio" + :group 'lsp-erlang + :risky t + :type 'symbol) + +(defun lsp-erlang-server-start-fun (port) + `(,lsp-erlang-server-path + "--transport" "tcp" + "--port" ,(number-to-string port))) + +(defun lsp-erlang-server-connection () + (if (eq lsp-erlang-server-connection-type 'tcp) + (lsp-tcp-connection 'lsp-erlang-server-start-fun) + (lsp-stdio-connection `(,lsp-erlang-server-path "--transport" "stdio")))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-erlang-server-connection) + :major-modes '(erlang-mode) + :priority -1 + :server-id 'erlang-ls)) + +(lsp-consistency-check lsp-erlang) + +(provide 'lsp-erlang) +;;; lsp-erlang.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-eslint.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-eslint.el new file mode 100644 index 0000000..1420b45 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-eslint.el @@ -0,0 +1,355 @@ +;;; lsp-eslint.el --- lsp-mode eslint integration -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Ivan Yonchovski + +;; Author: Ivan Yonchovski <yyoncho@gmail.com> +;; Keywords: languages + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; + +;;; Code: + +(require 'lsp-protocol) +(require 'lsp-mode) + +(defconst lsp-eslint/status-ok 1) +(defconst lsp-eslint/status-warn 2) +(defconst lsp-eslint/status-error 3) + +(defgroup lsp-eslint nil + "ESlint language server group." + :group 'lsp-mode + :link '(url-link "https://github.com/Microsoft/vscode-eslint")) + +(defcustom lsp-eslint-unzipped-path (f-join lsp-server-install-dir "eslint/unzipped") + "The path to the file in which `eslint' will be stored." + :type 'file + :group 'lsp-eslint + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-eslint-server-command `("node" + "~/server/out/eslintServer.js" + "--stdio") + "Command to start eslint server." + :risky t + :type '(repeat string) + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-enable t + "Controls whether eslint is enabled for JavaScript files or not." + :type 'boolean + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-package-manager "npm" + "The package manager you use to install node modules." + :type '(choice (const :tag "npm" "npm") + (const :tag "yarn" "yarn") + (const :tag "pnpm" "pnpm") + (string :tag "other")) + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-format t + "Whether to perform format." + :type 'boolean + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-node-path nil + "A path added to NODE_PATH when resolving the eslint module." + :type '(repeat string) + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-node "node" + "Path to nodejs." + :type 'file + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-eslint-options nil + "The eslint options object to provide args normally passed to + eslint when executed from a command line (see + http://eslint.org/docs/developer-guide/nodejs-api#cliengine)." + :type 'alist) + +(defcustom lsp-eslint-trace-server "off" + "Traces the communication between VSCode and the eslint linter service." + :type 'string) + +(defcustom lsp-eslint-run "onType" + "Run the linter on save (onSave) or on type (onType)" + :type '(choice (const :tag "onSave" "onSave") + (const :tag "onType" "onType")) + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-auto-fix-on-save nil + "Turns auto fix on save on or off." + :type 'boolean + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-fix-all-problem-type + "all" + "Determines which problems are fixed when running the +source.fixAll code action." + :type '(choice + (const "all") + (const "problems") + string) + :package-version '(lsp-mode . "7.0.1")) + +(defcustom lsp-eslint-quiet nil + "Turns on quiet mode, which ignores warnings." + :type 'boolean + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-working-directories [] + "" + :type 'lsp-string-vector + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-validate ["javascript" "javascriptreact"] + "An array of language ids which should be validated by ESLint" + :type 'lsp-string-vector + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-provide-lint-task nil + "Controls whether a task for linting the whole workspace will be available." + :type 'boolean + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-lint-task-enable nil + "Controls whether a task for linting the whole workspace will be available." + :type 'boolean + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-lint-task-options "." + "Command line options applied when running the task for linting the whole +workspace (see https://eslint.org/docs/user-guide/command-line-interface)." + :type 'string + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-runtime nil + "The location of the node binary to run ESLint under." + :type '(repeat string) + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-code-action-disable-rule-comment '((enable . t) (location . "separateLine")) + "" + :type 'alist + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-code-action-show-documentation '((enable . t)) + "" + :type 'alist) + +(defcustom lsp-eslint-experimental-incremental-sync t + "Controls whether the new incremental text document synchronization should +be used." + :type 'boolean + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-eslint-save-library-choices t + "Controls whether to remember choices made to permit or deny ESLint libraries +from running." + :type 'boolean + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-eslint-library-choices-file (expand-file-name (locate-user-emacs-file ".lsp-eslint-choices")) + "The file where choices to permit or deny ESLint libraries from running is +stored." + :type 'string + :package-version '(lsp-mode . "7.1")) + +(defun lsp--find-eslint () + (or + (when-let ((workspace-folder (lsp-find-session-folder (lsp-session) default-directory))) + (let ((eslint-local-path (f-join workspace-folder "node_modules" ".bin" + (if (eq system-type 'windows-nt) "eslint.cmd" "eslint")))) + (when (f-exists? eslint-local-path) + eslint-local-path))) + "eslint")) + +(defun lsp-eslint-create-default-configuration () + "Create default eslint configuration." + (interactive) + (unless (lsp-session-folders (lsp-session)) + (user-error "There are no workspace folders")) + (pcase (->> (lsp-session) + lsp-session-folders + (-filter (lambda (dir) + (-none? + (lambda (file) (f-exists? (f-join dir file))) + '(".eslintrc.js" ".eslintrc.yaml" ".eslintrc.yml" ".eslintrc" ".eslintrc.json"))))) + (`nil (user-error "All workspace folders contain eslint configuration")) + (folders (let ((default-directory (completing-read "Select project folder: " folders nil t))) + (async-shell-command (format "%s --init" (lsp--find-eslint))))))) + +(lsp-defun lsp-eslint-status-handler (workspace (&eslint:StatusParams :state)) + (setf (lsp--workspace-status-string workspace) + (propertize "ESLint" + 'face (cond + ((eq state lsp-eslint/status-error) 'error) + ((eq state lsp-eslint/status-warn) 'warn) + (t 'success))))) + +(lsp-defun lsp-eslint--configuration (_workspace (&ConfigurationParams :items)) + (->> items + (seq-map (-lambda ((&ConfigurationItem :scope-uri?)) + (-when-let* ((file (lsp--uri-to-path scope-uri?)) + (buffer (find-buffer-visiting file)) + (workspace-folder (lsp-find-session-folder (lsp-session) file))) + (with-current-buffer buffer + (list :validate "probe" + :packageManager lsp-eslint-package-manager + :codeActionOnSave (list :enable t + :mode lsp-eslint-fix-all-problem-type) + :format (lsp-json-bool lsp-eslint-format) + :options (or lsp-eslint-options (ht)) + :run (or lsp-eslint-run "onType") + :nodePath lsp-eslint-node-path + :onIgnoredFiles "off" + :quiet (lsp-json-bool lsp-eslint-quiet) + :workspaceFolder (list :uri (lsp--path-to-uri workspace-folder) + :name (f-filename workspace-folder)) + :codeAction (list + :disableRuleComment (or lsp-eslint-code-action-disable-rule-comment + (list :enable t + :location "separateLine")) + :showDocumentation (or lsp-eslint-code-action-show-documentation + (list :enable t)))))))) + (apply #'vector))) + +(lsp-defun lsp-eslint--open-doc (_workspace (&eslint:OpenESLintDocParams :url)) + "Open documentation." + (browse-url url)) + +(defun lsp-eslint-apply-all-fixes () + "Apply all autofixes in the current buffer." + (interactive) + (lsp-send-execute-command "eslint.applyAllFixes" (vector (lsp--versioned-text-document-identifier)))) + +;; XXX: replace with `lsp-make-interactive-code-action' macro +;; (lsp-make-interactive-code-action eslint-fix-all "source.fixAll.eslint") + +(defun lsp-eslint-fix-all () + "Perform the source.fixAll.eslint code action, if available." + (interactive) + (condition-case nil + (lsp-execute-code-action-by-kind "source.fixAll.eslint") + (lsp-no-code-actions + (when (called-interactively-p 'any) + (lsp--info "source.fixAll.eslint action not available"))))) + +(defun lsp-eslint-server-command () + (if (lsp-eslint-server-exists? lsp-eslint-server-command) + lsp-eslint-server-command + `(,lsp-eslint-node ,(f-join lsp-eslint-unzipped-path + "extension/server/out/eslintServer.js") + "--stdio"))) + +(defun lsp-eslint-server-exists? (eslint-server-command) + (let* ((command-name (f-base (f-filename (cl-first eslint-server-command)))) + (first-argument (cl-second eslint-server-command)) + (first-argument-exist (and first-argument (file-exists-p first-argument)))) + (if (equal command-name lsp-eslint-node) + first-argument-exist + (executable-find (cl-first eslint-server-command))))) + +(defvar lsp-eslint--stored-libraries (ht) + "Hash table defining if a given path to an ESLint library is allowed to run. +If the value for a key is 4, it will be allowed. If it is 1, it will not. If a +value does not exist for the key, or the value is nil, the user will be prompted +to allow or deny it.") + +(when (and (file-exists-p lsp-eslint-library-choices-file) + lsp-eslint-save-library-choices) + (setq lsp-eslint--stored-libraries (lsp--read-from-file lsp-eslint-library-choices-file))) + +(lsp-defun lsp-eslint--confirm-local (_workspace (&eslint:ConfirmExecutionParams :library-path) callback) + (if-let ((option-alist '(("Always" 4 . t) + ("Yes" 4 . nil) + ("No" 1 . nil) + ("Never" 1 . t))) + (remembered-answer (gethash library-path lsp-eslint--stored-libraries))) + (funcall callback remembered-answer) + (lsp-ask-question + (format "Allow lsp-mode to execute %s?" library-path) + (mapcar 'car option-alist) + (lambda (response) + (let ((option (cdr (assoc response option-alist)))) + (when (cdr option) + (puthash library-path (car option) lsp-eslint--stored-libraries) + (when lsp-eslint-save-library-choices + (lsp--persist lsp-eslint-library-choices-file lsp-eslint--stored-libraries))) + (funcall callback (car option))))))) + +(defun lsp-eslint--probe-failed (_workspace _message) + "Called when the server detects a misconfiguration in ESLint." + (lsp--error "ESLint is not configured correctly. Please ensure your eslintrc is set up for the languages you are using.")) + +(lsp-register-client + (make-lsp-client + :new-connection + (lsp-stdio-connection + (lambda () (lsp-eslint-server-command)) + (lambda () (lsp-eslint-server-exists? (lsp-eslint-server-command)))) + :activation-fn (lambda (filename &optional _) + (when lsp-eslint-enable + (or (string-match-p (rx (one-or-more anything) "." + (or "ts" "js" "jsx" "tsx" "html" "vue")eos) + filename) + (derived-mode-p 'js-mode 'js2-mode 'typescript-mode 'html-mode)))) + :priority -1 + :completion-in-comments? t + :add-on? t + :multi-root t + :notification-handlers (ht ("eslint/status" #'lsp-eslint-status-handler)) + :request-handlers (ht ("workspace/configuration" #'lsp-eslint--configuration) + ("eslint/openDoc" #'lsp-eslint--open-doc) + ("eslint/probeFailed" #'lsp-eslint--probe-failed)) + :async-request-handlers (ht ("eslint/confirmESLintExecution" #'lsp-eslint--confirm-local)) + :server-id 'eslint + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--server-register-capability + (lsp-make-registration + :id "random-id" + :method "workspace/didChangeWatchedFiles" + :register-options? (lsp-make-did-change-watched-files-registration-options + :watchers + `[,(lsp-make-file-system-watcher + :glob-pattern "**/.eslintr{c.js,c.yaml,c.yml,c,c.json}") + ,(lsp-make-file-system-watcher + :glob-pattern "**/.eslintignore") + ,(lsp-make-file-system-watcher + :glob-pattern "**/package.json")]))))) + :download-server-fn (lambda (_client callback error-callback _update?) + (let ((tmp-zip (make-temp-file "ext" nil ".zip"))) + (delete-file tmp-zip) + (lsp-download-install + (lambda (&rest _) + (condition-case err + (progn + (lsp-unzip tmp-zip lsp-eslint-unzipped-path) + (funcall callback)) + (error (funcall error-callback err)))) + error-callback + :url (lsp-vscode-extension-url "dbaeumer" "vscode-eslint" "2.1.14") + :store-path tmp-zip))))) + +(lsp-consistency-check lsp-eslint) + +(provide 'lsp-eslint) +;;; lsp-eslint.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-fortran.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-fortran.el new file mode 100644 index 0000000..c9ffb7a --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-fortran.el @@ -0,0 +1,61 @@ +;;; lsp-fortran.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, fortran + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the Fortran Programming Language. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-fortran nil + "LSP support for Fortran, using the Fortran Language Server." + :group 'lsp-mode + :link '(url-link "https://github.com/hansec/fortran-language-server")) + +(defcustom lsp-clients-fortls-executable "fortls" + "The fortls executable to use. +Leave as just the executable name to use the default behavior of +finding the executable with `exec-path'." + :group 'lsp-fortran + :risky t + :type 'file) + +(defcustom lsp-clients-fortls-args '() + "Extra arguments for the fortls executable" + :group 'lsp-fortran + :risky t + :type '(repeat string)) + +(defun lsp-clients--fortls-command () + "Generate the language server startup command." + `(,lsp-clients-fortls-executable,@lsp-clients-fortls-args)) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection 'lsp-clients--fortls-command) + :major-modes '(f90-mode fortran-mode) + :priority -1 + :server-id 'fortls)) + +(lsp-consistency-check lsp-fortran) + +(provide 'lsp-fortran) +;;; lsp-fortran.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-fsharp.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-fsharp.el new file mode 100644 index 0000000..6552d83 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-fsharp.el @@ -0,0 +1,305 @@ +;;; lsp-fsharp.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Reed Mullanix + +;; Author: Reed Mullanix <reedmullanix@gmail.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; lsp-fsharp client + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-fsharp nil + "LSP support for the F# Programming Language, using the FsharpAutoComplete server." + :link '(url-link "https://github.com/fsharp/FsAutoComplete") + :group 'lsp-mode + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-fsharp-server-runtime 'net-core + "The .NET runtime to use." + :group 'lsp-fsharp + :type '(choice (const :tag "Use .Net Core" net-core) + (const :tag "Use Mono" mono) + (const :tag "Use .Net Framework" net-framework)) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-fsharp-server-install-dir (f-join lsp-server-install-dir "fsautocomplete/") + "Install directory for fsautocomplete server. +The slash is expected at the end." + :group 'lsp-fsharp + :risky t + :type 'directory + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-fsharp-server-args nil + "Extra arguments for the F# language server." + :type '(repeat string) + :group 'lsp-fsharp + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-fsharp-keywords-autocomplete t + "Provides keywords in autocomplete list." + :group 'lsp-fsharp + :type 'bool + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-fsharp-external-autocomplete nil + "Provides autocompletion for symbols from not opened namespaces/modules; +inserts open on accept." + :group 'lsp-fsharp + :type 'bool + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-fsharp-linter t + "Enables FSharpLint integration, provides additional warnings and code +action fixes." + :group 'lsp-fsharp + :type 'bool + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-fsharp-union-case-stub-generation t + "Enables a code action to generate pattern matching cases." + :group 'lsp-fsharp + :type 'bool + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-fsharp-union-case-stub-generation-body "failwith \"Not Implemented\"" + "Defines dummy body used by pattern matching generator." + :group 'lsp-fsharp + :type 'string + :risky t + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-fsharp-record-stub-generation t + "Enables code action to generate record stub." + :group 'lsp-fsharp + :type 'bool + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-fsharp-record-stub-generation-body "failwith \"Not Implemented\"" + "Defines dummy body used by record stub generator." + :group 'lsp-fsharp + :type 'string + :risky t + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-fsharp-interface-stub-generation t + "Enables code action to generate an interface stub." + :group 'lsp-fsharp + :type 'bool + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-fsharp-interface-stub-generation-object-identifier "this" + "Defines object identifier used by interface stub generator, +e.g. `this' or `self'." + :group 'lsp-fsharp + :type 'string + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-fsharp-interface-stub-generation-method-body "failwith \"Not Implemented\"" + "Defines dummy body used by interface stub generator." + :group 'lsp-fsharp + :type 'string + :risky t + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-fsharp-unused-opens-analyzer t + "Enables unused open detection." + :group 'lsp-fsharp + :type 'bool + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-fsharp-unused-declarations-analyzer t + "Enables unused symbol detection." + :group 'lsp-fsharp + :type 'bool + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-fsharp-simplify-name-analyzer nil + "Enables simplify name analyzer and remove redundant qualifier quick fix." + :group 'lsp-fsharp + :type 'bool + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-fsharp-resolve-namespaces t + "Enables resolve namespace quick fix; adds `open' if symbol is from not yet +opened module/namespace." + :group 'lsp-fsharp + :type 'bool + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-fsharp-enable-reference-code-lens t + "Enables reference count code lenses. +It is recommended to disable if `--backgorund-service-enabled' is not used." + :group 'lsp-fsharp + :type 'bool + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-fsharp-auto-workspace-init nil + "Enable automatic workspace initialization. +Do note that this can cause unexpected or challenging behaviors, as solutions +with test projects are not autoloaded by FSharpAutoComplete." + :group 'lsp-fsharp + :type 'bool + :risky t) + +(defun lsp-fsharp--fsac-runtime-cmd () + "Get the command required to run fsautocomplete based off of the +current runtime." + (pcase lsp-fsharp-server-runtime + ('net-core "dotnet") + ('mono "mono") + ('net-framework nil))) + +(defun lsp-fsharp--fsac-cmd () + "The location of fsautocomplete executable." + (let ((file-ext (if (eq lsp-fsharp-server-runtime 'net-core) + ".dll" + ".exe"))) + (expand-file-name (concat "fsautocomplete" file-ext) lsp-fsharp-server-install-dir))) + +(defun lsp-fsharp--version-list-latest (lst) + "Return latest version from LST (if any)." + (->> lst + (-map (lambda (x) (car (s-split " " x)))) + (-filter (lambda (x) (> (length x) 0))) + (-sort (lambda (a b) (not (version<= (substring a 1) + (substring b 1))))) + cl-first)) + +(defun lsp-fsharp--fetch-json (url) + "Retrieve and parse JSON from URL." + (with-temp-buffer + (url-insert-file-contents url) + (let ((json-false :false)) + (json-read)))) + +(defun lsp-fsharp--latest-version-from-github () + "Return latest version of the server available from github." + (lsp-fsharp--version-list-latest + (seq-map (lambda (elt) (s-trim (cdr (assq 'name elt)))) + (lsp-fsharp--fetch-json "https://api.github.com/repos/fsharp/FsAutoComplete/releases")))) + +(defun lsp-fsharp--server-download-url (version) + "Return url for .zip file to download for given VERSION, depending on `lsp-fsharp-server-runtime'." + (concat "https://github.com/fsharp/FsAutoComplete/releases/download" + "/" version + "/" (if (eq lsp-fsharp-server-runtime 'net-core) + "fsautocomplete.netcore.zip" + "fsautocomplete.zip"))) + +(defun lsp-fsharp--fsac-install (_client callback _error-callback _update?) + "Download the latest version of fsautocomplete and extract it to `lsp-fsharp-server-install-dir'." + (let* ((temp-file (make-temp-file "fsautocomplete" nil ".zip")) + (install-dir-full (expand-file-name lsp-fsharp-server-install-dir)) + (unzip-script (cond ((executable-find "unzip") (format "mkdir -p %s && unzip -qq %s -d %s" install-dir-full temp-file install-dir-full)) + ((executable-find "powershell") (format "powershell -noprofile -noninteractive -nologo -ex bypass Expand-Archive -path '%s' -dest '%s'" temp-file install-dir-full)) + (t (user-error (format "Unable to unzip server - file %s cannot be extracted, please extract it manually" temp-file))))) + (latest-version (lsp-fsharp--latest-version-from-github)) + (server-download-url (lsp-fsharp--server-download-url latest-version))) + (url-copy-file server-download-url temp-file t) + (shell-command unzip-script) + (shell-command (format "%s %s --version" (lsp-fsharp--fsac-runtime-cmd) (lsp-fsharp--fsac-cmd))) + (funcall callback))) + +(defun lsp-fsharp-update-fsac () + "Update fsautocomplete to the latest version." + (interactive) + (-let [install-dir (f-expand lsp-fsharp-server-install-dir)] + (f-delete install-dir t) + (lsp-fsharp--fsac-install nil #'ignore #'lsp--error t))) + +(defun lsp-fsharp--make-launch-cmd () + "Build the command required to launch fsautocomplete." + (append (list (lsp-fsharp--fsac-runtime-cmd) (lsp-fsharp--fsac-cmd) "--background-service-enabled") + lsp-fsharp-server-args)) + +(defun lsp-fsharp--project-list () + "Get the list of files we need to send to fsharp/workspaceLoad." + (let* ((response (lsp-request "fsharp/workspacePeek" + `(:directory ,(lsp-workspace-root) + :deep 10 + :excludedDirs ["paket-files" ".git" "packages" "node_modules"]))) + (data (lsp--read-json (lsp-get response :content))) + (found (-> data (lsp-get :Data) (lsp-get :Found))) + (directory (seq-find (lambda (d) (equal "directory" (lsp-get d :Type))) found))) + (-> directory (lsp-get :Data) (lsp-get :Fsprojs)))) + +;;;###autoload +(defun lsp-fsharp--workspace-load (projects) + "Load all of the provided PROJECTS." + (lsp-request-async "fsharp/workspaceLoad" + `(:textDocuments ,(vconcat [] (mapcar (lambda (p) `(:uri ,p)) projects))) + (lambda (_) + (lsp--info "Workspace Loaded!")))) + +(defvar lsp-fsharp--default-init-options (list) + "Default init options to be passed to FSharpAutoComplete, + updated conditionally by `lsp-fsharp--make-init-options'.") + +(defun lsp-fsharp--make-init-options () + "Init options for F#." + (-let [opts lsp-fsharp--default-init-options] + (if lsp-fsharp-auto-workspace-init + (push '(:AutomaticWorkspaceInit . t) opts) + opts))) + +(lsp-register-custom-settings + `(("FSharp.KeywordsAutocomplete" lsp-fsharp-keywords-autocomplete t) + ("FSharp.ExternalAutocomplete" lsp-fsharp-external-autocomplete t) + ("FSharp.Linter" lsp-fsharp-linter t) + ("FSharp.UnionCaseStubGeneration" lsp-fsharp-union-case-stub-generation t) + ("FSharp.UnionCaseStubGenerationBody" lsp-fsharp-union-case-stub-generation-body) + ("FSharp.RecordStubGeneration" lsp-fsharp-record-stub-generation t) + ("FSharp.RecordStubGenerationBody" lsp-fsharp-record-stub-generation-body) + ("FSharp.InterfaceStubGeneration" lsp-fsharp-interface-stub-generation t) + ("FSharp.InterfaceStubGenerationObjectIdentifier" lsp-fsharp-interface-stub-generation-object-identifier) + ("FSharp.InterfaceStubGenerationMethodBody" lsp-fsharp-interface-stub-generation-method-body) + ("FSharp.UnusedOpensAnalyzer" lsp-fsharp-unused-opens-analyzer t) + ("FSharp.UnusedDeclarationsAnalyzer" lsp-fsharp-unused-declarations-analyzer t) + ("FSharp.SimplifyNameAnalyzer" lsp-fsharp-simplify-name-analyzer t) + ("FSharp.ResolveNamespaces" lsp-fsharp-resolve-namespaces t) + ("FSharp.EnableReferenceCodeLens" lsp-fsharp-enable-reference-code-lens t))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + #'lsp-fsharp--make-launch-cmd + (lambda () (f-exists? (lsp-fsharp--fsac-cmd)))) + :major-modes '(fsharp-mode) + :notification-handlers (ht ("fsharp/notifyCancel" #'ignore) + ("fsharp/notifyWorkspace" #'ignore) + ("fsharp/fileParsed" #'ignore) + ("fsharp/notifyWorkspacePeek" #'ignore)) + :initialization-options 'lsp-fsharp--make-init-options + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + ;; Something needs to be calling lsp--set-configuration + (progn + (lsp--set-configuration + (lsp-configuration-section "fsharp")) + (lsp-fsharp--workspace-load + (lsp-fsharp--project-list))))) + :server-id 'fsac + :download-server-fn #'lsp-fsharp--fsac-install)) + +(lsp-consistency-check lsp-fsharp) + +(provide 'lsp-fsharp) +;;; lsp-fsharp.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-gdscript.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-gdscript.el new file mode 100644 index 0000000..4a52ec8 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-gdscript.el @@ -0,0 +1,61 @@ +;;; lsp-gdscript.el --- LSP mode -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Oliver Frank + +;; Author: Oliver Frank <oliverfrank321@gmail.com> +;; Keywords: languages + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; lsp-gdscript client + +;;; Code: +(require 'lsp-mode) + +(defgroup lsp-gdscript nil + "LSP support for GDScript, using godot's language server." + :group 'lsp-mode + :link '(url-link "https://github.com/godotengine/godot") + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-gdscript-port 6008 + "Port to connect server to" + :type 'integer + :group 'lsp-gdscript) + +(defun lsp-gdscript-tcp-connect-to-port () + (list + :connect (lambda (filter sentinel name _environment-fn) + (let* ((host "localhost") + (port lsp-gdscript-port) + (tcp-proc (lsp--open-network-stream host port (concat name "::tcp")))) + + (set-process-query-on-exit-flag tcp-proc nil) + (set-process-filter tcp-proc filter) + (set-process-sentinel tcp-proc sentinel) + (cons tcp-proc tcp-proc))) + :test? (lambda () t))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-gdscript-tcp-connect-to-port) + :major-modes '(gdscript-mode) + :server-id 'gdscript)) + + +(lsp-consistency-check lsp-gdscript)(provide 'lsp-gdscript) + + +;;; lsp-gdscript.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-go.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-go.el new file mode 100644 index 0000000..880a705 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-go.el @@ -0,0 +1,338 @@ +;;; lsp-go.el --- Go Client settings -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Muir Manders + +;; Author: Muir Manders <muir@mnd.rs> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; lsp-go client + +;;; Code: + +(require 'lsp-mode) +(require 'lsp-completion) + +(defgroup lsp-go nil + "LSP support for the Go Programming Language, using the gopls language server." + :link '(url-link "https://github.com/golang/tools/blob/master/gopls/README.md") + :group 'lsp-mode + :package-version '(lsp-mode . "6.3.2")) + +(define-obsolete-variable-alias + 'lsp-gopls-server-path + 'lsp-go-gopls-server-path + "lsp-mode 7.0.1") + +(defcustom lsp-go-gopls-server-path "gopls" + "Path to gopls server binary." + :type 'string + :group 'lsp-go) + +(define-obsolete-variable-alias + 'lsp-gopls-server-args + 'lsp-go-gopls-server-args + "lsp-mode 7.0.1") + +(defcustom lsp-go-gopls-server-args nil + "Extra CLI arguments for gopls." + :type '(repeat string) + :group 'lsp-go) + +(define-obsolete-variable-alias + 'lsp-gopls-use-placeholders + 'lsp-go-use-placeholders + "lsp-mode 7.0.1") + +(defcustom lsp-go-use-placeholders t + "Cause gopls to provide placeholder parameter snippets when +completing function calls." + :type 'boolean + :group 'lsp-go) + +(define-obsolete-variable-alias + 'lsp-gopls-build-flags + 'lsp-go-build-flags + "lsp-mode 7.0.1") + +(defcustom lsp-go-build-flags [] + "A vector of flags passed on to the build system when invoked, + applied to queries like `go list'." + :type 'lsp-string-vector + :group 'lsp-go + :risky t + :package-version '(lsp-mode "6.2")) + +(define-obsolete-variable-alias + 'lsp-gopls-env + 'lsp-go-env + "lsp-mode 7.0.1") + +(defcustom lsp-go-env nil + "`gopls' has the unusual ability to set environment variables, + intended to affect the behavior of commands invoked by `gopls' + on the user's behalf. This variable takes a hash table of env + var names to desired values." + :type '(alist :key-type (string :tag "env var name") :value-type (string :tag "value")) + :group 'lsp-go + :risky t + :package-version '(lsp-mode "6.2")) + +(defcustom lsp-go-directory-filters [] + "A vector of directory filters." + :link '(url-link "https://github.com/golang/tools/blob/67e49ef2d0f326051e22a4a55bdf9344ae1a8ed8/gopls/doc/settings.md#directoryfilters-string") + :group 'lsp-go + :type 'lsp-string-vector + :package-version '(lsp-mode "7.1")) + +(define-obsolete-variable-alias + 'lsp-gopls-hover-kind + 'lsp-go-hover-kind + "lsp-mode 7.0.1") + +(defcustom lsp-go-hover-kind "SynopsisDocumentation" + "`gopls' allows the end user to select the desired amount of + documentation returned during e.g. hover and thing-at-point + operations." + :type '(choice (const "SynopsisDocumentation") + (const "NoDocumentation") + (const "FullDocumentation") + (const "SingleLine") + (const "Structured")) + :group 'lsp-go + :risky t + :package-version '(lsp-mode "6.2")) + +(define-obsolete-variable-alias + 'lsp-gopls-available-codelens + 'lsp-go-available-codelenses + "lsp-mode 7.0.1") + +(define-obsolete-variable-alias + 'lsp-go-available-codelens + 'lsp-go-available-codelenses + "lsp-mode 7.0.1") + +(defvar lsp-go-available-codelenses + '( + (gc_details . "Toggle the calculation of gc annotations") + (generate . "Run `go generate` for a directory") + (regenerate_cgo . "Regenerate cgo definitions") + (test . "Run `go test` for a specific set of test or benchmark functions (lgeacy)") + (tidy . "Run `go mod tidy` for a module") + (upgrade_dependency . "Upgrade a dependency") + (vendor . "Runs `go mod vendor' for a module")) + "Available codelenses that can be further enabled or disabled + through `lsp-go-codelenses'.") + +(defun lsp-go--defcustom-available-as-alist-type (alist) + "Returns a list suitable for the `:type' field in a `defcustom' used to populate an alist. + +The input ALIST has the form `((\"name\" . \"documentation sentence\") [...])' + +The returned type provides a tri-state that either: + - does not include the element in the alist + - sets element to false (actually, :json-false) + - sets element to true (actually, t) +" + (let ((list '())) + (dolist (v alist) + (push `(cons + :tag ,(cdr v) + (const :format "" ,(car v)) + (choice (const :tag "Enable" t) (const :tag "Disable" :json-false))) + list)) + (push 'set list) + list)) + +(define-obsolete-variable-alias + 'lsp-gopls-codelens + 'lsp-go-codelenses + "lsp-mode 7.0.1") + +(define-obsolete-variable-alias + 'lsp-go-codelens + 'lsp-go-codelenses + "lsp-mode 7.0.1") + +(defcustom lsp-go-codelenses '((gc_details . :json-false) + (generate . t) + (regenerate_cgo . t) + (tidy . t) + (upgrade_dependency . t) + (test . t) + (vendor . t)) + "Select what codelenses should be enabled or not. + +The codelenses can be found at https://github.com/golang/tools/blob/3fa0e8f87c1aae0a9adc2a63af1a1945d16d9359/internal/lsp/source/options.go#L106-L112." + :type (lsp-go--defcustom-available-as-alist-type lsp-go-available-codelenses) + :group 'lsp-go + :risky t + :package-version '(lsp-mode "7.0")) + +(define-obsolete-variable-alias + 'lsp-clients-go-library-directories + 'lsp-go-library-directories + "lsp-mode 7.0.1") + +(defcustom lsp-go-library-directories '("/usr") + "List of directories which will be considered to be libraries." + :group 'lsp-go + :risky t + :type '(repeat string)) + +(define-obsolete-variable-alias + 'lsp-clients-go-library-directories-include-go-modules + 'lsp-go-library-directories-include-go-modules + "lsp-mode 7.0.1") + +(defcustom lsp-go-library-directories-include-go-modules t + "Whether or not $GOPATH/pkg/mod should be included as a library directory." + :type 'boolean + :group 'lsp-go) + +(defun lsp-go--library-default-directories (_workspace) + "Calculate go library directories. + +If `lsp-go-library-directories-include-go-modules' is non-nil +and the environment variable GOPATH is set this function will return +$GOPATH/pkg/mod along with the value of +`lsp-go-library-directories'." + (let ((library-dirs lsp-go-library-directories)) + (when (and lsp-go-library-directories-include-go-modules + (or (and (not (file-remote-p default-directory)) (executable-find "go")) + (and (version<= "27.0" emacs-version) (with-no-warnings (executable-find "go" (file-remote-p default-directory)))))) + (with-temp-buffer + (when (zerop (process-file "go" nil t nil "env" "GOPATH")) + (setq library-dirs + (append + library-dirs + (list + (concat + (string-trim-right (buffer-substring (point-min) (point-max))) + "/pkg/mod"))))))) + (if (file-remote-p default-directory) + (mapcar (lambda (path) (concat (file-remote-p default-directory) path)) library-dirs) + library-dirs))) + +(defcustom lsp-go-link-target "godoc.org" + "Which website to use for displaying Go documentation." + :type '(choice (const "godoc.org") + (const "pkg.go.dev") + (string :tag "A custom website")) + :group 'lsp-go + :package-version '(lsp-mode "7.0.1")) + +(defcustom lsp-go-links-in-hover t + "If non-nil, hover documentation includes links." + :type 'boolean + :group 'lsp-go + :package-version '(lsp-mode "7.1")) + +(defcustom lsp-go-use-gofumpt nil + "If non-nil, use gofumpt formatting." + :type 'boolean + :group 'lsp-go + :package-version '(lsp-mode "7.1")) + +(defcustom lsp-go-goimports-local "" + "Equivalent of the goimports -local flag, which puts imports beginning with + this string after third-party packages. It should be the prefix of the import + path whose imports should be grouped separately." + :type 'string + :group 'lsp-go + :package-version '(lsp-mode "7.1")) + +(defcustom lsp-go-analyses nil + "Specify analyses that the user would like to enable or disable. A map of the + names of analysis passes that should be enabled/disabled. A full list of + analyzers that gopls uses can be found at + https://github.com/golang/tools/blob/master/gopls/doc/analyzers.md" + :type '(alist :key-type (string :tag "analyzer name") :value-type (boolean :tag "value")) + :group 'lsp-go + :risky t + :package-version '(lsp-mode "7.1")) + +(defcustom lsp-go-import-shortcut "Both" + "Specifies whether import statements should link to documentation or go to + definitions." + :type '(choice (const "Both") + (const "Link") + (const "Definition")) + :group 'lsp-go + :risky t + :package-version '(lsp-mode "7.1")) + +(defcustom lsp-go-symbol-matcher "Fuzzy" + "Sets the algorithm that is used when finding workspace symbols." + :type '(choice (const "Fuzzy") + (const "CaseInsensitive") + (const "CaseSensitive")) + :group 'lsp-go + :risky t + :package-version '(lsp-mode "7.1")) + +(defcustom lsp-go-symbol-style "Dynamic" + "Controls how symbols are qualified in symbol responses. + + 'Dynamic' uses whichever qualifier results in the highest scoring match for + the given symbol query. Here a 'qualifier' is any '/' or '.' delimited suffix + of the fully qualified symbol. i.e. 'to/pkg.Foo.Field' or just 'Foo.Field'. + + 'Full' is fully qualified symbols, i.e. 'path/to/pkg.Foo.Field'. + + 'Package' is package qualified symbols i.e. 'pkg.Foo.Field'." + :type '(choice (const "Dynamic") + (const "Full") + (const "Package")) + :group 'lsp-go + :risky t + :package-version '(lsp-mode "7.1")) + +(lsp-register-custom-settings + '(("gopls.usePlaceholders" lsp-go-use-placeholders t) + ("gopls.hoverKind" lsp-go-hover-kind) + ("gopls.buildFlags" lsp-go-build-flags) + ("gopls.env" lsp-go-env) + ("gopls.linkTarget" lsp-go-link-target) + ("gopls.codelenses" lsp-go-codelenses) + ("gopls.linksInHover" lsp-go-links-in-hover t) + ("gopls.gofumpt" lsp-go-use-gofumpt t) + ("gopls.local" lsp-go-goimports-local) + ("gopls.directoryFilters" lsp-go-directory-filters) + ("gopls.analyses" lsp-go-analyses) + ("gopls.importShortcut" lsp-go-import-shortcut) + ("gopls.symbolMatcher" lsp-go-symbol-matcher) + ("gopls.symbolStyle" lsp-go-symbol-style))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (lambda () (cons lsp-go-gopls-server-path lsp-go-gopls-server-args))) + :major-modes '(go-mode go-dot-mod-mode) + :language-id "go" + :priority 0 + :server-id 'gopls + :completion-in-comments? t + :library-folders-fn #'lsp-go--library-default-directories + :after-open-fn (lambda () + ;; https://github.com/golang/tools/commit/b2d8b0336 + (setq-local lsp-completion-filter-on-incomplete nil)))) + +(lsp-consistency-check lsp-go) + +(provide 'lsp-go) +;;; lsp-go.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-groovy.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-groovy.el new file mode 100644 index 0000000..c1fcaaf --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-groovy.el @@ -0,0 +1,66 @@ +;;; lsp-groovy.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, groovy + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the Groovy Programming Language. + +;;; Code: + +(require 'lsp-mode) +(require 'f) + +(defgroup lsp-groovy nil + "LSP support for Groovy, using groovy-language-server." + :group 'lsp-mode + :link '(url-link "https://github.com/prominic/groovy-language-server")) + +(defcustom lsp-groovy-server-file (f-join lsp-server-install-dir "groovy-language-server-all.jar") + "JAR file path for groovy-language-server-all.jar." + :group 'lsp-groovy + :risky t + :type 'file) + +(defun lsp-groovy--lsp-command () + "Generate LSP startup command." + `("java" "-jar" ,(expand-file-name lsp-groovy-server-file))) + +(defcustom lsp-groovy-classpath ["/usr/local/opt/groovy/libexec/lib"] + "List of paths to Groovy JARs." + :group 'lsp-groovy + :risky t + :type 'lsp-string-vector) + +(lsp-register-custom-settings + '(("groovy.classpath" lsp-groovy-classpath))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection 'lsp-groovy--lsp-command) + :major-modes '(groovy-mode) + :priority -1 + :server-id 'groovy-ls + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration (lsp-configuration-section "groovy")))))) + +(lsp-consistency-check lsp-groovy) + +(provide 'lsp-groovy) +;;; lsp-groovy.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-hack.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-hack.el new file mode 100644 index 0000000..161659a --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-hack.el @@ -0,0 +1,54 @@ +;;; lsp-xxx.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, hack + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the Hack Programming Language. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-hack nil + "LSP support for Hack, using HHVM." + :group 'lsp-mode + :link '(url-link "https://docs.hhvm.com/hhvm")) + +(defcustom lsp-clients-hack-command '("hh_client" "lsp" "--from" "emacs") + "Command to start hh_client." + :group 'lsp-hack + :risky t + :type '(repeat string)) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection (lambda () lsp-clients-hack-command)) + :major-modes '(hack-mode) + :priority -1 + :server-id 'hack + ;; ignore some unsupported messages from Nuclide + :notification-handlers (lsp-ht ("telemetry/event" 'ignore) + ("$/cancelRequest" 'ignore)) + :request-handlers (lsp-ht ("window/showStatus" 'ignore)))) + + +(lsp-consistency-check lsp-hack) + +(provide 'lsp-hack) +;;; lsp-hack.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-haxe.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-haxe.el new file mode 100644 index 0000000..62707be --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-haxe.el @@ -0,0 +1,226 @@ +;;; lsp-haxe.el --- Haxe Client settings -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Yannik Böttcher + +;; Author: Yannik Böttcher <yannikboettcher@outlook.de> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; lsp-haxe client + +;;; Code: + + +;; adapted from lsp-clangd configuration +(require 'lsp-protocol) +(require 'lsp-mode) + +(defgroup lsp-haxe nil + "LSP support for Haxe using the language server provided by vshaxe" + :group 'lsp-mode + :link '(url-link "https://github.com/vshaxe/vshaxe")) + + +;; Haxe ls is executed via node +(defcustom lsp-clients--haxe-executable "node" + "Haxe ls is executed via node." + :group 'lsp-haxe + :risky t + :type 'file) + +;; The server.js is being passed to node as an argument +(defcustom lsp-clients--haxe-server-path (expand-file-name "~/.haxe-language-server/bin/server.js") + "The path to the server.js file." + :group 'lsp-haxe + :risky t + :type 'file) + +;; Build the actual Haxe ls command. +(defun lsp-clients--haxe-command () + "Haxe ls startup command." + `(,lsp-clients--haxe-executable ,lsp-clients--haxe-server-path)) + +;; https://github.com/yyoncho/lsp-mode/commit/72186e1adc089d772c87ed8f287eb3333b66bfa7 +;; This is to force the client to send a didChangeConfiguration Message. Without this, the server won't start, https://github.com/vshaxe/vshaxe/issues/328#issuecomment-471809093 +(defcustom lsp-clients--haxe-settings (list :haxe.executable "haxe") + "Lsp clients configuration settings." + :group 'lsp-haxe + :risky t + :type '(repeat string)) + +;; The build spec for the project. +(defcustom lsp-haxe-hxml "build.hxml" + "The compile file for the haxe project." + :type 'file + :group 'lsp-haxe + :package-version '(lsp-mode . "7.0")) + +;; https://github.com/emacs-lsp/lsp-mode/blob/150a933694349df960dc8fd7a15e04f5727e6433/lsp-rust.el#L251 +(lsp-defun lsp-clients--haxe-processStart (_workspace (&haxe:ProcessStartNotification :title)) + "Handle processStart notification. Just logs PARAMS." + (lsp-log title)) + +(defcustom lsp-haxe-executable "haxe" + nil + :type 'file + :group 'lsp-haxe) + +(defcustom lsp-haxe-configurations nil + nil + :type '(repeat string) + :group 'lsp-haxe) + +(defcustom lsp-haxe-display-configurations nil + nil + :type '(repeat string) + :group 'lsp-haxe) + +(defcustom lsp-haxe-display-server nil + nil + :type 'string + :group 'lsp-haxe) + +(defcustom lsp-haxe-display-port "auto" + nil + :type 'number + :group 'lsp-haxe) + +(defcustom lsp-haxe-enable-compilation-server t + nil + :type 'boolean + :group 'lsp-haxe) + +(defcustom lsp-haxe-task-presentation + '((echo . t) + (reveal . "always") + (focus . :json-false) + (panel . "shared") + (showReuseMessage . t) + (clear . :json-false)) + nil + :type 'plist + :group 'lsp-haxe) + +(defcustom lsp-haxe-enable-code-lens t + nil + :type 'boolean + :group 'lsp-haxe) + +(defcustom lsp-haxe-enable-diagnostics t + nil + :type 'boolean + :group 'lsp-haxe) + +(defcustom lsp-haxe-enable-server-view nil + nil + :type 'boolean + :group 'lsp-haxe) + +(defcustom lsp-haxe-enable-methods-view nil + nil + :type 'boolean + :group 'lsp-haxe) + +(defcustom lsp-haxe-enable-signature-help-documentation t + nil + :type 'boolean + :group 'lsp-haxe) + +(defcustom lsp-haxe-diagnostics-path-filter "${workspaceRoot}" + nil + :type 'string + :group 'lsp-haxe) + +(defcustom lsp-haxe-build-completion-cache t + nil + :type 'boolean + :group 'lsp-haxe) + +(defcustom lsp-haxe-enable-completion-cache-warning t + nil + :type 'boolean + :group 'lsp-haxe) + +(defcustom lsp-haxe-code-generation nil + nil + :type 'string + :group 'lsp-haxe) + +(defcustom lsp-haxe-exclude ["zpp_nape"] + nil + :type '(repeat string) + :group 'lsp-haxe) + +(defcustom lsp-haxe-postfix-completion nil + nil + :type 'string + :group 'lsp-haxe) + +(lsp-register-custom-settings + '(("haxe.hxml" lsp-haxe-hxml) + ("haxe.postfixCompletion" lsp-haxe-postfix-completion) + ("haxe.exclude" lsp-haxe-exclude) + ("haxe.codeGeneration" lsp-haxe-code-generation) + ("haxe.enableCompletionCacheWarning" lsp-haxe-enable-completion-cache-warning t) + ("haxe.buildCompletionCache" lsp-haxe-build-completion-cache t) + ("haxe.diagnosticsPathFilter" lsp-haxe-diagnostics-path-filter) + ("haxe.enableSignatureHelpDocumentation" lsp-haxe-enable-signature-help-documentation t) + ("haxe.enableMethodsView" lsp-haxe-enable-methods-view t) + ("haxe.enableServerView" lsp-haxe-enable-server-view t) + ("haxe.enableDiagnostics" lsp-haxe-enable-diagnostics t) + ("haxe.enableCodeLens" lsp-haxe-enable-code-lens t) + ("haxe.taskPresentation" lsp-haxe-task-presentation) + ("haxe.enableCompilationServer" lsp-haxe-enable-compilation-server t) + ("haxe.displayPort" lsp-haxe-display-port) + ("haxe.displayServer" lsp-haxe-display-server) + ("haxe.displayConfigurations" lsp-haxe-display-configurations) + ("haxe.configurations" lsp-haxe-configurations) + ("haxe.executable" lsp-haxe-executable))) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection #'lsp-clients--haxe-command) + :major-modes '(haxe-mode) ; force didChangeConfiguration message + :initialized-fn + (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration (lsp-configuration-section "haxe")))) + :priority -1 + :server-id 'haxe + :initialization-options + (lambda () + `(:sendMethodResults t + :haxelibConfig (:executable "haxelib") + :displayServerConfig + ( :print (:reusing :json-false :completion :json-false) + :arguments [] + :env nil + :path "haxe") + :displayArguments [,lsp-haxe-hxml])) + :notification-handlers + (lsp-ht ("haxe/progressStart" 'lsp-clients--haxe-processStart) + ("haxe/progressStop" 'ignore) + ("haxe/didDetectOldPreview" 'ignore) + ("haxe/didChangeDisplayPort" 'ignore) + ("haxe/didRunHaxeMethod" 'ignore) + ("haxe/didChangeRequestQueue" 'ignore) + ("haxe/cacheBuildFailed" 'ignore)))) + +(lsp-consistency-check lsp-haxe) + +(provide 'lsp-haxe) +;;; lsp-haxe.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-headerline.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-headerline.el new file mode 100644 index 0000000..3ed62e5 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-headerline.el @@ -0,0 +1,473 @@ +;;; lsp-headerline.el --- LSP headerline features -*- lexical-binding: t; -*- +;; +;; Copyright (C) 2020 emacs-lsp maintainers +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. +;; +;;; Commentary: +;; +;; LSP headerline features +;; +;;; Code: + +(require 'lsp-icons) +(require 'lsp-mode) + +(defgroup lsp-headerline nil + "LSP support for headerline" + :prefix "lsp-headerline-" + :group 'lsp-mode + :tag "LSP Headerline") + +(defcustom lsp-headerline-breadcrumb-segments '(path-up-to-project file symbols) + "Segments used in breadcrumb text on headerline." + :type '(repeat + (choice (const :tag "Include the project name." project) + (const :tag "Include the open file name." file) + (const :tag "Include the directories up to project." path-up-to-project) + (const :tag "Include document symbols if server supports it." symbols))) + :group 'lsp-headerline) + +(defcustom lsp-headerline-breadcrumb-enable-symbol-numbers nil + "Whether to label symbols with numbers on the breadcrumb." + :type 'boolean + :group 'lsp-headerline) + +(defcustom lsp-headerline-breadcrumb-enable-diagnostics t + "If non-nil, apply different face on the breadcrumb based on the errors." + :type 'boolean + :group 'lsp-headerline + :package-version '(lsp-mode . "7.1")) + +(defface lsp-headerline-breadcrumb-separator-face '((t :inherit shadow :height 0.8)) + "Face used for breadcrumb separator on headerline." + :group 'lsp-headerline) + +(defface lsp-headerline-breadcrumb-path-face '((t :inherit font-lock-string-face)) + "Face used for breadcrumb paths on headerline." + :group 'lsp-headerline) + +(defface lsp-headerline-breadcrumb-path-error-face + '((t :underline (:style wave :color "Red1") + :inherit lsp-headerline-breadcrumb-path-face)) + "Face used for breadcrumb paths on headerline when there is an error under that path" + :group 'lsp-headerline) + +(defface lsp-headerline-breadcrumb-path-warning-face + '((t :underline (:style wave :color "Yellow") + :inherit lsp-headerline-breadcrumb-path-face)) + "Face used for breadcrumb paths on headerline when there is an warning under that path" + :group 'lsp-headerline) + +(defface lsp-headerline-breadcrumb-path-info-face + '((t :underline (:style wave :color "Green") + :inherit lsp-headerline-breadcrumb-path-face)) + "Face used for breadcrumb paths on headerline when there is an info under that path" + :group 'lsp-headerline) + +(defface lsp-headerline-breadcrumb-path-hint-face + '((t :underline (:style wave :color "Green") + :inherit lsp-headerline-breadcrumb-path-face)) + "Face used for breadcrumb paths on headerline when there is an hint under that path" + :group 'lsp-headerline) + +(defface lsp-headerline-breadcrumb-project-prefix-face + '((t :inherit font-lock-string-face :weight bold)) + "Face used for breadcrumb prefix on headerline. +Only if `lsp-headerline-breadcrumb-prefix` is `project-name-only`." + :group 'lsp-headerline) + +(defface lsp-headerline-breadcrumb-unknown-project-prefix-face + '((t :inherit shadow :weight bold)) + "Face used for breadcrumb prefix on headerline. +Only if `lsp-headerline-breadcrumb-prefix` is `project-name-only`." + :group 'lsp-headerline) + +(defface lsp-headerline-breadcrumb-symbols-face + '((t :inherit font-lock-doc-face :weight bold)) + "Face used for breadcrumb symbols text on headerline." + :group 'lsp-headerline) + +(defface lsp-headerline-breadcrumb-symbols-error-face + '((t :inherit lsp-headerline-breadcrumb-symbols-face + :underline (:style wave :color "Red1"))) + "Face used for breadcrumb symbols text on headerline when there +is an error in symbols range." + :group 'lsp-headerline) + +(defface lsp-headerline-breadcrumb-symbols-warning-face + '((t :inherit lsp-headerline-breadcrumb-symbols-face + :underline (:style wave :color "Yellow"))) + "Face used for breadcrumb symbols text on headerline when there +is an warning in symbols range." + :group 'lsp-headerline) + +(defface lsp-headerline-breadcrumb-symbols-info-face + '((t :inherit lsp-headerline-breadcrumb-symbols-face + :underline (:style wave :color "Green"))) + "Face used for breadcrumb symbols text on headerline when there +is an info in symbols range." + :group 'lsp-headerline) + +(defface lsp-headerline-breadcrumb-symbols-hint-face + '((t :inherit lsp-headerline-breadcrumb-symbols-face + :underline (:style wave :color "Green"))) + "Face used for breadcrumb symbols text on headerline when there +is an hints in symbols range." + :group 'lsp-headerline) + +(defface lsp-headerline-breadcrumb-deprecated-face + '((t :inherit lsp-headerline-breadcrumb-symbols-face + :strike-through t)) + "Face used on breadcrumb deprecated text on modeline." + :group 'lsp-headerline) + +(defvar-local lsp-headerline--string nil + "Holds the current breadcrumb string on headerline.") + +(defvar lsp-headerline-arrow nil + "Holds the current breadcrumb string on headerline.") + +(defvar-local lsp-headerline--path-up-to-project-segments nil + "Holds the current breadcrumb path-up-to-project segments for +caching purposes.") + +(defun lsp-headerline--arrow-icon () + "Build the arrow icon for headerline breadcrumb." + (or + lsp-headerline-arrow + (setq lsp-headerline-arrow (lsp-icons-all-the-icons-material-icon + "chevron_right" + 'lsp-headerline-breadcrumb-separator-face + ">" + 'headerline-breadcrumb)))) + +(lsp-defun lsp-headerline--symbol-icon ((&DocumentSymbol :kind)) + "Build the SYMBOL icon for headerline breadcrumb." + (concat (lsp-icons-get-by-symbol-kind kind 'headerline-breadcrumb) + " ")) + +(lsp-defun lsp-headerline--go-to-symbol ((&DocumentSymbol + :selection-range (&RangeToPoint :start selection-start) + :range (&RangeToPoint :start narrowing-start + :end narrowing-end))) + "Go to breadcrumb symbol. +If the buffer is narrowed and the target symbol lies before the +minimum reachable point in the narrowed buffer, then widen and +narrow to the outer symbol." + (when (buffer-narrowed-p) + (narrow-to-region + (min (point-min) narrowing-start) + (max (point-max) narrowing-end))) + (goto-char selection-start)) + +(lsp-defun lsp-headerline--narrow-to-symbol ((&DocumentSymbol :range (&RangeToPoint :start :end))) + "Narrow to breadcrumb symbol range." + (narrow-to-region start end)) + +(defun lsp-headerline--with-action (local-map help-echo-string display-string) + "Assign LOCAL-MAP and HELP-ECHO-STRING to the region around the DISPLAY-STRING." + (propertize display-string + 'mouse-face 'header-line-highlight + 'help-echo help-echo-string + 'local-map local-map)) + +(defmacro lsp-headerline--make-mouse-handler (&rest body) + "Making mouse event handler. +Switch to current mouse interacting window before doing BODY." + (declare (debug t) (indent 0)) + `(lambda (event) + (interactive "e") + (select-window (posn-window (elt event 1))) + ,@body)) + +(defun lsp-headerline--directory-with-action (full-path directory-display-string) + "Build action for FULL-PATH and DIRECTORY-DISPLAY-STRING." + (lsp-headerline--with-action (let ((map (make-sparse-keymap))) + (define-key map [header-line mouse-1] + (lsp-headerline--make-mouse-handler + (dired full-path))) + (define-key map [header-line mouse-2] + (lsp-headerline--make-mouse-handler + (dired-other-window full-path))) + map) + (format "mouse-1: browse '%s' with Dired\nmouse-2: browse '%s' with Dired in other window" + directory-display-string + directory-display-string) + (propertize directory-display-string + 'lsp-full-path full-path))) + +(declare-function evil-set-jump "ext:evil-jumps") + +(lsp-defun lsp-headerline--symbol-with-action ((symbol &as &DocumentSymbol :name) symbol-display-string) + "Build action for SYMBOL and SYMBOL-STRING." + (lsp-headerline--with-action (let ((map (make-sparse-keymap))) + (define-key map [header-line mouse-1] + (lsp-headerline--make-mouse-handler + (when (bound-and-true-p evil-mode) + (evil-set-jump)) + (lsp-headerline--go-to-symbol symbol))) + (define-key map [header-line mouse-2] + (lsp-headerline--make-mouse-handler + (-let (((&DocumentSymbol :range (&RangeToPoint :start :end)) symbol)) + (if (and (eq (point-min) start) (eq (point-max) end)) + (widen) + (lsp-headerline--narrow-to-symbol symbol))))) + map) + (format "mouse-1: go to '%s' symbol\nmouse-2: %s" + name + (-let (((&DocumentSymbol :range (&RangeToPoint :start :end)) symbol)) + (if (and (eq (point-min) start) (eq (point-max) end)) + "widen" + (format "narrow to '%s' range" name)))) + symbol-display-string)) + +(defun lsp-headerline--path-up-to-project-root (root-path path) + "Find recursively the folders until the project ROOT-PATH. +PATH is the current folder to be checked." + (let ((current-path path) + headerline-path-components) + (while (not (lsp-f-same? root-path current-path)) + (push (lsp-headerline--directory-with-action current-path + (f-filename current-path)) + headerline-path-components) + (setq current-path (lsp-f-parent current-path))) + headerline-path-components)) + +(defun lsp-headerline--build-project-string () + "Build the project-segment string for the breadcrumb." + (-if-let (root (lsp-workspace-root)) + (propertize (lsp-headerline--directory-with-action + root + (f-filename root)) + 'font-lock-face + 'lsp-headerline-breadcrumb-project-prefix-face) + (propertize "<unknown>" + 'font-lock-face + 'lsp-headerline-breadcrumb-unknown-project-prefix-face))) + +(defun lsp-headerline--build-file-string () + "Build the file-segment string for the breadcrumb." + (let* ((file-path (buffer-file-name)) + (filename (f-filename file-path))) + (if-let ((file-ext (f-ext file-path))) + (concat (lsp-icons-get-by-file-ext file-ext 'headerline-breadcrumb) + " " + (propertize filename + 'font-lock-face + (lsp-headerline--face-for-path file-path))) + filename))) + + +(defun lsp-headerline--face-for-path (dir) + "Calculate the face for DIR." + (if-let ((diags (lsp-diagnostics-stats-for (directory-file-name dir)))) + (cl-labels ((check-severity + (severity) + (not (zerop (aref diags severity))))) + (cond + ((not lsp-headerline-breadcrumb-enable-diagnostics) + 'lsp-headerline-breadcrumb-path-face) + ((check-severity lsp/diagnostic-severity-error) + 'lsp-headerline-breadcrumb-path-error-face) + ((check-severity lsp/diagnostic-severity-warning) + 'lsp-headerline-breadcrumb-path-warning-face) + ((check-severity lsp/diagnostic-severity-information) + 'lsp-headerline-breadcrumb-path-info-face) + ((check-severity lsp/diagnostic-severity-hint) + 'lsp-headerline-breadcrumb-path-hint-face) + (t 'lsp-headerline-breadcrumb-path-face))) + 'lsp-headerline-breadcrumb-path-face)) + +(defun lsp-headerline--severity-level-for-range (range) + "Get the severiy level for RANGE." + (let ((range-severity 10)) + (mapc (-lambda ((&Diagnostic :range (&Range :start) :severity?)) + (when (lsp-point-in-range? start range) + (setq range-severity (min range-severity severity?)))) + (lsp--get-buffer-diagnostics)) + range-severity)) + +(defun lsp-headerline--build-path-up-to-project-string () + "Build the path-up-to-project segment for the breadcrumb." + (if-let ((root (lsp-workspace-root))) + (let ((segments (or + lsp-headerline--path-up-to-project-segments + (setq lsp-headerline--path-up-to-project-segments + (lsp-headerline--path-up-to-project-root + root + (lsp-f-parent (buffer-file-name))))))) + (mapconcat (lambda (next-dir) + (propertize next-dir + 'font-lock-face + (lsp-headerline--face-for-path + (get-text-property + 0 'lsp-full-path next-dir)))) + segments + (concat " " (lsp-headerline--arrow-icon) " "))) + "")) + +(lsp-defun lsp-headerline--face-for-symbol ((&DocumentSymbol :deprecated? + :range)) + "Get the face for SYMBOL." + (let ((range-severity (lsp-headerline--severity-level-for-range range))) + (cond + (deprecated? 'lsp-headerline-breadcrumb-deprecated-face) + ((not lsp-headerline-breadcrumb-enable-diagnostics) + 'lsp-headerline-breadcrumb-symbols-face) + ((= range-severity lsp/diagnostic-severity-error) + 'lsp-headerline-breadcrumb-symbols-error-face) + ((= range-severity lsp/diagnostic-severity-warning) + 'lsp-headerline-breadcrumb-symbols-warning-face) + ((= range-severity lsp/diagnostic-severity-information) + 'lsp-headerline-breadcrumb-symbols-info-face) + ((= range-severity lsp/diagnostic-severity-hint) + 'lsp-headerline-breadcrumb-symbols-hint-face) + (t 'lsp-headerline-breadcrumb-symbols-face)))) + +(defun lsp-headerline--build-symbol-string () + "Build the symbol segment for the breadcrumb." + (if (lsp-feature? "textDocument/documentSymbol") + (-if-let* ((lsp--document-symbols-request-async t) + (symbols (lsp--get-document-symbols)) + (symbols-hierarchy (lsp--symbols->document-symbols-hierarchy symbols)) + (enumerated-symbols-hierarchy + (-map-indexed (lambda (index elt) + (cons elt (1+ index))) + symbols-hierarchy))) + (mapconcat + (-lambda (((symbol &as &DocumentSymbol :name) + . index)) + (let* ((symbol2-name + (propertize name + 'font-lock-face + (lsp-headerline--face-for-symbol symbol))) + (symbol2-icon (lsp-headerline--symbol-icon symbol)) + (full-symbol-2 + (concat + (if lsp-headerline-breadcrumb-enable-symbol-numbers + (concat + (propertize (number-to-string index) + 'face + 'lsp-headerline-breadcrumb-symbols-face) + " ") + "") + (if symbol2-icon + (concat symbol2-icon symbol2-name) + symbol2-name)))) + (lsp-headerline--symbol-with-action symbol full-symbol-2))) + enumerated-symbols-hierarchy + (concat " " (lsp-headerline--arrow-icon) " ")) + "") + "")) + +(defun lsp-headerline--build-string () + "Build the header-line string." + (string-trim-right + (mapconcat + (lambda (segment) + (let ((segment-string + (pcase segment + ('project (lsp-headerline--build-project-string)) + ('file (lsp-headerline--build-file-string)) + ('path-up-to-project (lsp-headerline--build-path-up-to-project-string)) + ('symbols (lsp-headerline--build-symbol-string)) + (_ (lsp-log "'%s' is not a valid entry for `lsp-headerline-breadcrumb-segments'" + (symbol-name segment)) + "")))) + (if (eq segment-string "") + "" + (concat (lsp-headerline--arrow-icon) + " " + segment-string + " ")))) + lsp-headerline-breadcrumb-segments + ""))) + +(defun lsp-headerline--check-breadcrumb (&rest _) + "Request for document symbols to build the breadcrumb." + (setq lsp-headerline--string (lsp-headerline--build-string)) + (force-mode-line-update)) + +(defun lsp-headerline--enable-breadcrumb () + "Enable headerline breadcrumb mode." + (when (and lsp-headerline-breadcrumb-enable + (lsp-feature? "textDocument/documentSymbol")) + (lsp-headerline-breadcrumb-mode 1))) + +(defun lsp-headerline--disable-breadcrumb () + "Disable headerline breadcrumb mode." + (lsp-headerline-breadcrumb-mode -1)) + +;;;###autoload +(define-minor-mode lsp-headerline-breadcrumb-mode + "Toggle breadcrumb on headerline." + :group 'lsp-headerline + :global nil + (cond + (lsp-headerline-breadcrumb-mode + (add-to-list 'header-line-format '(t (:eval lsp-headerline--string))) + + (add-hook 'xref-after-jump-hook #'lsp-headerline--check-breadcrumb nil t) + + (add-hook 'lsp-on-idle-hook #'lsp-headerline--check-breadcrumb nil t) + (add-hook 'lsp-configure-hook #'lsp-headerline--enable-breadcrumb nil t) + (add-hook 'lsp-unconfigure-hook #'lsp-headerline--disable-breadcrumb nil t)) + (t + (remove-hook 'lsp-on-idle-hook #'lsp-headerline--check-breadcrumb t) + (remove-hook 'lsp-configure-hook #'lsp-headerline--enable-breadcrumb t) + (remove-hook 'lsp-unconfigure-hook #'lsp-headerline--disable-breadcrumb t) + + (remove-hook 'xref-after-jump-hook #'lsp-headerline--check-breadcrumb t) + + (setq lsp-headerline--path-up-to-project-segments nil) + (setq header-line-format (remove '(t (:eval lsp-headerline--string)) header-line-format))))) + +;;;###autoload +(defun lsp-breadcrumb-go-to-symbol (symbol-position) + "Go to the symbol on breadcrumb at SYMBOL-POSITION." + (interactive "P") + (if (numberp symbol-position) + (if (lsp-feature? "textDocument/documentSymbol") + (-if-let* ((lsp--document-symbols-request-async t) + (symbols (lsp--get-document-symbols)) + (symbols-hierarchy (lsp--symbols->document-symbols-hierarchy symbols))) + (lsp-headerline--go-to-symbol (nth (1- symbol-position) symbols-hierarchy)) + (lsp--info "Symbol not found for position %s" symbol-position)) + (lsp--info "Server does not support breadcrumb.")) + (lsp--info "Call this function with a number representing the symbol position on breadcrumb"))) + +(declare-function evil-set-command-property "ext:evil-common") + +(with-eval-after-load 'evil + (evil-set-command-property 'lsp-breadcrumb-go-to-symbol :jump t)) + +;;;###autoload +(defun lsp-breadcrumb-narrow-to-symbol (symbol-position) + "Narrow to the symbol range on breadcrumb at SYMBOL-POSITION." + (interactive "P") + (if (numberp symbol-position) + (if (lsp-feature? "textDocument/documentSymbol") + (-if-let* ((lsp--document-symbols-request-async t) + (symbols (lsp--get-document-symbols)) + (symbols-hierarchy (lsp--symbols->document-symbols-hierarchy symbols))) + (lsp-headerline--narrow-to-symbol (nth (1- symbol-position) symbols-hierarchy)) + (lsp--info "Symbol not found for position %s" symbol-position)) + (lsp--info "Server does not support breadcrumb.")) + (lsp--info "Call this function with a number representing the symbol position on breadcrumb"))) + +(lsp-consistency-check lsp-headerline) + +(provide 'lsp-headerline) +;;; lsp-headerline.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-html.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-html.el new file mode 100644 index 0000000..0b44e16 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-html.el @@ -0,0 +1,198 @@ +;;; lsp-html.el --- vscode-html-languageserver configuration -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Vibhav Pant + +;; Author: Vibhav Pant <vibhavp@gmail.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-html nil + "LSP support for HTML, using vscode-html-languageserver." + :group 'lsp-mode + :link '(url-link "https://github.com/vscode-langservers/vscode-html-languageserver") + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-experimental-custom-data nil + "A list of JSON file paths that define custom tags, properties and other HTML +syntax constructs. Only workspace folder setting will be read." + :type '(choice (const nil) string) + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-format-enable t + "Enable/disable default HTML formatter." + :type 'boolean + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-format-wrap-line-length 120 + "Maximum amount of characters per line (0 = disable)." + :type 'number + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-format-unformatted "wbr" + nil + :type '(choice (const nil) string) + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-format-content-unformatted "pre,code,textarea" + nil + :group 'lsp-html + :type '(choice (const nil) string) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-format-indent-inner-html nil + nil + :type 'boolean + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-format-preserve-new-lines t + "Controls whether existing line breaks before elements should be preserved. +Only works before elements, not inside tags or for text." + :type 'boolean + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-format-max-preserve-new-lines nil + nil + :type '(choice (const nil) integer) + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-format-indent-handlebars nil nil + :type 'boolean + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-format-end-with-newline nil + "End with a newline." + :type 'boolean + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-format-extra-liners "head, body, /html" + nil + :type '(choice (const nil) string) + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-format-wrap-attributes "auto" + "Wrap attributes." + :type '(choice + (const "auto") + (const "force") + (const "force-aligned") + (const "force-expand-multiline") + (const "aligned-multiple") + (const "preserve") + (const "preserve-aligned")) + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-suggest-html5 t + "Controls whether the built-in HTML language support suggests HTML5 tags, +properties and values." + :type 'boolean + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-validate-scripts t + "Controls whether the built-in HTML language support validates embedded +scripts." + :type 'boolean + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-validate-styles t + "Controls whether the built-in HTML language support validates embedded +styles." + :type 'boolean + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-auto-closing-tags t + "Enable/disable autoclosing of HTML tags." + :type 'boolean + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-html-trace-server "off" + "Traces the communication between VS Code and the HTML language server." + :type '(choice + (const "off") + (const "messages") + (const "verbose")) + :group 'lsp-html + :package-version '(lsp-mode . "6.1")) + +(lsp-register-custom-settings + '(("html.trace.server" lsp-html-trace-server) + ("html.autoClosingTags" lsp-html-auto-closing-tags t) + ("html.validate.styles" lsp-html-validate-styles t) + ("html.validate.scripts" lsp-html-validate-scripts t) + ("html.suggest.html5" lsp-html-suggest-html5 t) + ("html.format.wrapAttributes" lsp-html-format-wrap-attributes) + ("html.format.extraLiners" lsp-html-format-extra-liners) + ("html.format.endWithNewline" lsp-html-format-end-with-newline t) + ("html.format.indentHandlebars" lsp-html-format-indent-handlebars t) + ("html.format.maxPreserveNewLines" lsp-html-format-max-preserve-new-lines) + ("html.format.preserveNewLines" lsp-html-format-preserve-new-lines t) + ("html.format.indentInnerHtml" lsp-html-format-indent-inner-html t) + ("html.format.contentUnformatted" lsp-html-format-content-unformatted) + ("html.format.unformatted" lsp-html-format-unformatted) + ("html.format.wrapLineLength" lsp-html-format-wrap-line-length) + ("html.format.enable" lsp-html-format-enable t) + ("html.experimental.customData" lsp-html-experimental-custom-data))) + +(defcustom lsp-html-server-command-args '("--stdio") + "Command to start html-languageserver." + :type '(repeat string) + :group 'lsp-html + :package-version '(lsp-mode . "6.3")) + +(lsp-dependency 'html-language-server + '(:system "html-languageserver") + '(:npm :package "vscode-html-languageserver-bin" + :path "html-languageserver")) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (lambda () + (cons (lsp-package-path 'html-language-server) + lsp-html-server-command-args))) + :activation-fn (lsp-activate-on "html") + :priority -4 + :completion-in-comments? t + :server-id 'html-ls + :initialized-fn (lambda (w) + (with-lsp-workspace w + (lsp--set-configuration + (lsp-configuration-section "html")))) + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure + 'html-language-server callback + error-callback)))) + +(lsp-consistency-check lsp-html) + +(provide 'lsp-html) +;;; lsp-html.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-icons.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-icons.el new file mode 100644 index 0000000..7bd8bc6 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-icons.el @@ -0,0 +1,96 @@ +;;; lsp-icons.el --- LSP icons management -*- lexical-binding: t; -*- +;; +;; Copyright (C) 2020 emacs-lsp maintainers +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. +;; +;;; Commentary: +;; +;; LSP icons management +;; +;;; Code: +(require 'lsp-mode) + +(defgroup lsp-icons nil + "LSP icons" + :group 'lsp-mode + :tag "LSP Icons") + +(defcustom lsp-headerline-breadcrumb-icons-enable t + "If non-nil, icons support is enabled for headerline-breadcrumb." + :type 'boolean + :group 'lsp-icons) + +(declare-function all-the-icons-material "ext:all-the-icons" t t) +(declare-function lsp-treemacs-symbol-icon "ext:lsp-treemacs" (kind)) +(declare-function lsp-treemacs-get-icon "ext:lsp-treemacs" (icon-name)) + +(defun lsp-icons--enabled-for-feature (feature) + "Check if icons support is enabled for FEATURE." + (cond + ((eq feature 'headerline-breadcrumb) lsp-headerline-breadcrumb-icons-enable) + (t t))) + +(defun lsp-icons--fix-image-background (image) + "Fix IMAGE background if it is a file otherwise return as an icon." + (if image + (let ((display-image (get-text-property 0 'display image))) + (if (and (listp display-image) + (plist-member (cl-copy-list (cl-rest display-image)) :type)) + (propertize " " 'display + (cl-list* 'image + (plist-put + (cl-copy-list + (cl-rest display-image)) + :background (face-attribute 'header-line :background nil t)))) + (if (stringp display-image) + (replace-regexp-in-string "\s\\|\t" "" display-image) + (replace-regexp-in-string "\s\\|\t" "" image)))) + "")) + +(defun lsp-icons-get-by-file-ext (file-ext &optional feature) + "Get an icon by file FILE-EXT. +FEATURE is the feature that will use the icon which we should check +if its enabled." + (when (and file-ext + (lsp-icons--enabled-for-feature feature) + (functionp 'lsp-treemacs-get-icon)) + (lsp-icons--fix-image-background + (lsp-treemacs-get-icon file-ext)))) + +(defun lsp-icons-get-by-symbol-kind (kind &optional feature) + "Get an icon by symbol KIND. +FEATURE is the feature that will use the icon which we should check +if its enabled." + (when (and kind + (lsp-icons--enabled-for-feature feature) + (functionp 'lsp-treemacs-symbol-icon)) + (lsp-icons--fix-image-background + (lsp-treemacs-symbol-icon kind)))) + +(defun lsp-icons-all-the-icons-material-icon (icon-name face fallback &optional feature) + "Get a material icon from all-the-icons by ICON-NAME using FACE. +Fallback to FALLBACK string if not found or not available. +FEATURE is the feature that will use the icon which we should check +if its enabled." + (if (and (functionp 'all-the-icons-material) + (lsp-icons--enabled-for-feature feature)) + (all-the-icons-material icon-name + :face face) + (propertize fallback 'face face))) + +(lsp-consistency-check lsp-icons) + +(provide 'lsp-icons) +;;; lsp-icons.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-ido.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-ido.el new file mode 100644 index 0000000..ac34dd7 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-ido.el @@ -0,0 +1,142 @@ +;;; lsp-ido.el --- `ido' integration -*- lexical-binding: t -*- +;; +;; Copyright (C) 2021 emacs-lsp maintainers +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This module provides an interactive ido interface to the workspace symbol +;; functionality offered by lsp-mode. + +;;; Code: + +(require 'ido) +(require 'lsp-protocol) +(require 'lsp-mode) + +(defgroup lsp-ido nil + "LSP support for ido-based symbol completion" + :group 'lsp-mode + :tag "LSP ido") + +(defcustom lsp-ido-symbol-kind-to-string + [" " ; Unknown - 0 + "File" ; File - 1 + "Modu" ; Module - 2 + "Nmsp" ; Namespace - 3 + "Pack" ; Package - 4 + "Clss" ; Class - 5 + "Meth" ; Method - 6 + "Prop" ; Property - 7 + "Fld " ; Field - 8 + "Cons" ; Constructor - 9 + "Enum" ; Enum - 10 + "Intf" ; Interface - 11 + "Func" ; Function - 12 + "Var " ; Variable - 13 + "Cnst" ; Constant - 14 + "Str " ; String - 15 + "Num " ; Number - 16 + "Bool " ; Boolean - 17 + "Arr " ; Array - 18 + "Obj " ; Object - 19 + "Key " ; Key - 20 + "Null" ; Null - 21 + "EmMm" ; EnumMember - 22 + "Srct" ; Struct - 23 + "Evnt" ; Event - 24 + "Op " ; Operator - 25 + "TPar"] ; TypeParameter - 26 + "A vector of 26 itens representing the SymbolKind." + :group 'lsp-ido + :type 'vector) + +(defcustom lsp-ido-show-symbol-filename + t + "Whether to show the project-relative path to a symbol's point of definition." + :group 'lsp-ido + :type 'boolean) + +(defcustom lsp-ido-show-symbol-kind + t + "Whether to show the symbol's kind when showing lsp symbols." + :group 'lsp-ido + :type 'boolean) + +(eval-when-compile + (lsp-interface + (lsp-ido:FormattedSymbolInformation + (:kind :name :location :textualRepresentation) + (:containerName :deprecated)))) + +(lsp-defun lsp-ido--transform-candidate + ((symbol-information &as &SymbolInformation :kind :location (&Location :uri)) + lsp-ido--results project-root) + (let* ((sanitized-kind (if (< kind (length lsp-ido-symbol-kind-to-string)) kind 0)) + (type (elt lsp-ido-symbol-kind-to-string sanitized-kind)) + (typestr (if lsp-ido-show-symbol-kind + (format "[%s] " type) + "")) + (pathstr (if lsp-ido-show-symbol-filename + (propertize (format " . %s" (file-relative-name (lsp--uri-to-path uri) project-root)) + 'face 'font-lock-comment-face) + "")) + (textual-representation + (lsp-render-symbol-information symbol-information ".")) + (entry (concat typestr textual-representation pathstr))) + (puthash entry symbol-information lsp-ido--results))) + +(lsp-defun lsp-ido--jump-selected-candidate + ((&SymbolInformation + :location (&Location :uri :range (&Range :start (&Position :line :character))))) + "Jump to selected candidate." + (find-file (lsp--uri-to-path uri)) + (goto-char (point-min)) + (forward-line line) + (forward-char character)) + +(defun lsp-ido--workspace-symbol (workspaces query) + "Search against WORKSPACES based on QUERY." + (let* ((lsp-ido--results (make-hash-table :test 'equal)) + (workspace-root (lsp-workspace-root)) + (raw-choices + (with-lsp-workspaces workspaces + (lsp-request + "workspace/symbol" + (lsp-make-workspace-symbol-params :query query))))) + (mapc (lambda (it) + (lsp-ido--transform-candidate it lsp-ido--results workspace-root)) + raw-choices) + lsp-ido--results)) + +;;;###autoload +(defun lsp-ido-workspace-symbol (arg) + "`ido' for lsp workspace/symbol. +When called with prefix ARG the default selection will be symbol at point." + (interactive "P") + (let* ((query (if arg "" (read-string "Workspace symbol: "))) + (hash-table-candidates (lsp-ido--workspace-symbol (lsp-workspaces) query)) + (choice (ido-completing-read + "Workspace symbol: " + (hash-table-keys hash-table-candidates) + nil + nil + (when arg (thing-at-point 'symbol))))) + (lsp-ido--jump-selected-candidate (gethash choice hash-table-candidates)))) + +(lsp-consistency-check lsp-ido) + +(provide 'lsp-ido) +;;; lsp-ido.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-iedit.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-iedit.el new file mode 100644 index 0000000..ff1af0d --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-iedit.el @@ -0,0 +1,101 @@ +;;; lsp-iedit.el --- `iedit' integration -*- lexical-binding: t -*- +;; +;; Copyright (C) 2020 emacs-lsp maintainers +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This module provides features that allow starting `iedit' on various +;; different lsp-based, semantic units (like documentHighlights, and +;; linkedEditingRanges in the future). + +;;; Code: + +(require 'lsp-mode) +(require 'dash) + +(declare-function iedit-make-occurrence-overlay "iedit-lib" (begin end)) +(declare-function iedit-start-buffering "iedit-lib" ()) +(declare-function iedit-lib-start "iedit-lib" (mode-exit-func)) +(declare-function iedit-done "iedit" ()) +(declare-function evil-multiedit-state "evil-multiedit" ()) + +(defvar iedit-mode) +(defvar iedit-auto-buffering) +(defvar iedit-occurrences-overlays) +(defvar iedit-occurrence-keymap) +(defvar iedit-mode-occurrence-keymap) +(defvar evil-multiedit--dont-recall) + +(defun lsp-iedit--on-ranges (ranges) + "Start an `iedit' operation using RANGES. +RANGES shall be a list of lsp-`&Range's. They can be acquired +from various lsp protocol requests, e.g. +`textDocument/documentHighlight', ...." + (require 'iedit) + (unless (seq-empty-p ranges) + (mapc (-lambda ((&RangeToPoint :start :end)) + (push (iedit-make-occurrence-overlay start end) + iedit-occurrences-overlays)) + ranges) + ;; See `iedit-start'; TODO: upstream this + (setq iedit-occurrence-keymap iedit-mode-occurrence-keymap) + (setq iedit-mode t) + (when iedit-auto-buffering + (iedit-start-buffering)) + (iedit-lib-start 'iedit-done) + (run-hooks 'iedit-mode-hook) + (add-hook 'before-revert-hook 'iedit-done nil t) + (add-hook 'kbd-macro-termination-hook 'iedit-done nil t) + (add-hook 'change-major-mode-hook 'iedit-done nil t) + (add-hook 'iedit-aborting-hook 'iedit-done nil t) + (message "%d occurrences of \"%s\"" + (seq-length ranges) + (lsp--range-text (lsp-seq-first ranges))))) + +;;;###autoload +(defun lsp-iedit-highlights () + "Start an `iedit' operation on the documentHighlights at point. +This can be used as a primitive `lsp-rename' replacement if the +language server doesn't support renaming. + +See also `lsp-enable-symbol-highlighting'." + (interactive) + (let ((highlights (lsp-request "textDocument/documentHighlight" + (lsp--text-document-position-params))) + (-compare-fn (-lambda ((&Location :range (&Range :start l-start :end l-end)) + (&Location :range (&Range :start r-start :end r-end))) + (and (lsp--position-equal l-start r-start) + (lsp--position-equal l-end r-end))))) + (lsp-iedit--on-ranges (mapcar #'lsp:document-highlight-range (-distinct highlights))))) + +;;;###autoload +(defun lsp-evil-multiedit-highlights () + "Start an `evil-multiedit' operation on the documentHighlights at point. +This can be used as a primitive `lsp-rename' replacement if the +language server doesn't support renaming. + +See also `lsp-enable-symbol-highlighting'." + (interactive) + (require 'evil-multiedit) + (when (fboundp 'ahs-clear) (ahs-clear)) + (setq evil-multiedit--dont-recall t) + (lsp-iedit-highlights) + (evil-multiedit-state)) + +(lsp-consistency-check lsp-iedit) + +(provide 'lsp-iedit) +;;; lsp-iedit.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-javascript.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-javascript.el new file mode 100644 index 0000000..2f9e61f --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-javascript.el @@ -0,0 +1,334 @@ +;;; lsp-javascript.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the JavaScript and TypeScript Programming Languages. + +;;; Code: + +(require 'lsp-mode) + +(lsp-dependency 'javascript-typescript-langserver + '(:system "javascript-typescript-stdio") + '(:npm :package "javascript-typescript-langserver" + :path "javascript-typescript-stdio")) + +(defgroup lsp-typescript-javascript nil + "Support for TypeScript/JavaScript, using Sourcegraph's JavaScript/TypeScript language server." + :group 'lsp-mode + :link '(url-link "https://github.com/sourcegraph/javascript-typescript-langserver")) + +(defcustom lsp-clients-typescript-javascript-server-args '() + "Extra arguments for the typescript-language-server language server." + :group 'lsp-typescript-javascript + :risky t + :type '(repeat string)) + +(defun lsp-typescript-javascript-tsx-jsx-activate-p (filename &optional _) + "Check if the javascript-typescript language server should be enabled based on FILENAME." + (or (string-match-p "\\.mjs\\|\\.[jt]sx?\\'" filename) + (and (derived-mode-p 'js-mode 'typescript-mode) + (not (derived-mode-p 'json-mode))))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection (lambda () + (cons (lsp-package-path 'javascript-typescript-langserver) + lsp-clients-typescript-javascript-server-args))) + :activation-fn 'lsp-typescript-javascript-tsx-jsx-activate-p + :priority -3 + :completion-in-comments? t + :server-id 'jsts-ls + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure + 'javascript-typescript-langserver + callback + error-callback)))) + + +(defgroup lsp-typescript nil + "LSP support for TypeScript, using Theia/Typefox's TypeScript Language Server." + :group 'lsp-mode + :link '(url-link "https://github.com/theia-ide/typescript-language-server")) + +(defcustom lsp-clients-typescript-tls-path "typescript-language-server" + "Path to the typescript-language-server binary." + :group 'lsp-typescript + :risky t + :type 'string) + +(defcustom lsp-clients-typescript-server-args '("--stdio") + "Extra arguments for the typescript-language-server language server." + :group 'lsp-typescript + :risky t + :type '(repeat string)) + +(defcustom lsp-clients-typescript-log-verbosity "info" + "The server log verbosity." + :group 'lsp-typescript + :type 'string) + +(defcustom lsp-clients-typescript-plugins (vector) + "The list of plugins to load. +It should be a vector of plist with keys `:location' and `:name' +where `:name' is the name of the package and `:location' is the +directory containing the package. Example: +\(vector + \(list :name \"@vsintellicode/typescript-intellicode-plugin\" + :location \"<path>.vscode/extensions/visualstudioexptteam. + vscodeintellicode-1.1.9/\"))" + :group 'lsp-typescript + :type '(restricted-sexp :tag "Vector" + :match-alternatives + (lambda (xs) + (and (vectorp xs) (seq-every-p + (-lambda ((&plist :name :location)) + (and name location)) + xs))))) + +(lsp-dependency 'typescript-language-server + '(:system lsp-clients-typescript-tls-path) + '(:npm :package "typescript-language-server" + :path "typescript-language-server")) + +(lsp-dependency 'typescript + '(:system "tsserver") + '(:npm :package "typescript" + :path "tsserver")) + +(defun lsp-javascript--rename (_workspace args) + (let ((path (lsp--uri-to-path (lsp-get (lsp-get args :textDocument) :uri)))) + (if (f-exists? path) + (with-current-buffer (find-file path) + (goto-char (lsp--position-to-point + (lsp-get args :position)))) + (error "There is no file %s" path))) + (call-interactively #'lsp-rename) + nil) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection (lambda () + `(,(lsp-package-path 'typescript-language-server) + "--tsserver-path" + ,(lsp-package-path 'typescript) + ,@lsp-clients-typescript-server-args))) + :activation-fn 'lsp-typescript-javascript-tsx-jsx-activate-p + :priority -2 + :completion-in-comments? t + :initialization-options (lambda () + (list :plugins lsp-clients-typescript-plugins + :logVerbosity lsp-clients-typescript-log-verbosity + :tsServerPath (lsp-package-path 'typescript))) + :ignore-messages '("readFile .*? requested by TypeScript but content not available") + :server-id 'ts-ls + :request-handlers (ht ("_typescript.rename" #'lsp-javascript--rename)) + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure + 'typescript + (-partial #'lsp-package-ensure + 'typescript-language-server + callback + error-callback) + error-callback)))) + + +(defgroup lsp-flow nil + "LSP support for the Flow Javascript type checker." + :group 'lsp-mode + :link '(url-link "https://flow.org")) + +(defcustom lsp-clients-flow-server "flow" + "The Flow executable to use. +Leave as just the executable name to use the default behavior of +finding the executable with variable `exec-path'." + :group 'lsp-flow + :risky t + :type 'file) + +(defcustom lsp-clients-flow-server-args '("lsp") + "Extra arguments for starting the Flow language server." + :group 'lsp-flow + :risky t + :type '(repeat string)) + +(defun lsp-clients-flow-tag-file-present-p (file-name) + "Check if the '// @flow' or `/* @flow */' tag is present in +the contents of FILE-NAME." + (if-let ((buffer (find-buffer-visiting file-name))) + (with-current-buffer buffer + (lsp-clients-flow-tag-string-present-p)) + (with-temp-buffer + (insert-file-contents file-name) + (lsp-clients-flow-tag-string-present-p)))) + +(defun lsp-clients-flow-tag-string-present-p () + "Helper for `lsp-clients-flow-tag-file-present-p' that works +with the file contents." + (save-excursion + (goto-char (point-min)) + (let (stop found) + (while (not stop) + (unless (re-search-forward "[^\n[:space:]]" nil t) + (setq stop t)) + (if (= (point) (point-min)) (setq stop t) (backward-char)) + (cond ((or (looking-at "//+[ ]*@flow") + (looking-at "/\\**[ ]*@flow") + (looking-at "[ ]*\\*[ ]*@flow")) + (setq found t) (setq stop t)) + ((or (looking-at "//") (looking-at "*")) + (forward-line)) + ((looking-at "/\\*") + (save-excursion + (unless (re-search-forward "*/" nil t) (setq stop t))) + (forward-line)) + (t (setq stop t)))) + found))) + +(defun lsp-clients-flow-project-p (file-name) + "Check if FILE-NAME is part of a Flow project, that is, if +there is a .flowconfig file in the folder hierarchy." + (locate-dominating-file file-name ".flowconfig")) + +(defun lsp-clients-flow-activate-p (file-name _mode) + "Check if the Flow language server should be enabled for a +particular FILE-NAME and MODE." + (and (derived-mode-p 'js-mode 'web-mode 'js2-mode 'flow-js2-mode 'rjsx-mode) + (not (derived-mode-p 'json-mode)) + (or (lsp-clients-flow-project-p file-name) + (lsp-clients-flow-tag-file-present-p file-name)))) + +(lsp-register-client + (make-lsp-client :new-connection + (lsp-stdio-connection (lambda () + (cons lsp-clients-flow-server + lsp-clients-flow-server-args))) + :priority -1 + :activation-fn 'lsp-clients-flow-activate-p + :server-id 'flow-ls)) + +(defgroup lsp-deno nil + "LSP support for the Deno language server." + :group 'lsp-mode + :link '(url-link "https://deno.land/")) + +(defcustom lsp-clients-deno-server "deno" + "The Deno executable to use. +Leave as just the executable name to use the default behavior of +finding the executable with variable `exec-path'." + :group 'lsp-deno + :risky t + :type 'file + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-clients-deno-server-args '("lsp") + "Extra arguments for starting the Deno language server." + :group 'lsp-deno + :risky t + :type '(repeat string) + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-clients-deno-enable-lint t + "Controls if linting information will be provided by the Deno Language Server." + :group 'lsp-deno + :risky t + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-clients-deno-enable-code-lens-references t + "Enables or disables the display of code lens information." + :group 'lsp-deno + :risky t + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-clients-deno-enable-code-lens-references-all-functions t + "Enables or disables the display of code lens information for all functions. +Setting this variable to `non-nil' implicitly enables +`lsp-clients-deno-enable-code-lens-references'." + :group 'lsp-deno + :risky t + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-clients-deno-enable-code-lens-implementations t + "Enables or disables the display of code lens information for implementations." + :group 'lsp-deno + :risky t + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-clients-deno-config nil + "The file path to a tsconfig.json file. +The path can be either be relative to the workspace, or an +absolute path. + +Examples: `./tsconfig.json', +`/path/to/tsconfig.json', `C:\\path\\to\\tsconfig.json'" + :group 'lsp-deno + :risky t + :type 'file + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-clients-deno-import-map nil + "The file path to an import map. +Import maps provide a way to relocate modules based on their +specifiers. The path can either be relative to the workspace, or +an absolute path. + +Examples: `./import-map.json', +`/path/to/import-map.json', `C:\\path\\to\\import-map.json'." + :group 'lsp-deno + :risky t + :type 'file + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-clients-deno-enable-unstable nil + "Controls if code will be type checked with Deno's unstable APIs." + :group 'lsp-deno + :risky t + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defun lsp-clients-deno--make-init-options () + "Initialization options for the Deno language server." + `(:enable t + :config ,lsp-clients-deno-config + :importMap ,lsp-clients-deno-import-map + :lint ,(lsp-json-bool lsp-clients-deno-enable-lint) + :unstable ,(lsp-json-bool lsp-clients-deno-enable-unstable) + :codeLens (:implementations ,(lsp-json-bool lsp-clients-deno-enable-code-lens-implementations) + :references ,(lsp-json-bool (or lsp-clients-deno-enable-code-lens-references + lsp-clients-deno-enable-code-lens-references-all-functions)) + :referencesAllFunctions ,(lsp-json-bool lsp-clients-deno-enable-code-lens-references-all-functions)))) + +(lsp-register-client + (make-lsp-client :new-connection + (lsp-stdio-connection (lambda () + (cons lsp-clients-deno-server + lsp-clients-deno-server-args))) + :initialization-options #'lsp-clients-deno--make-init-options + :priority -5 + :activation-fn #'lsp-typescript-javascript-tsx-jsx-activate-p + :server-id 'deno-ls)) + +(lsp-consistency-check lsp-javascript) + +(provide 'lsp-javascript) +;;; lsp-javascript.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-json.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-json.el new file mode 100644 index 0000000..127d5e4 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-json.el @@ -0,0 +1,131 @@ +;;; lsp-json.el --- vscode-json-languageserver integration -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Kien Nguyen + +;; Author: kien.n.quang at gmail.com +;; Keywords: lsp + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; + +;;; Code: + +(require 'lsp-mode) +(require 'ht) +(require 'url) +(require 'url-util) + +(defgroup lsp-json nil + "LSP support for JSON, using vscode-json-languageserver." + :group 'lsp-mode + :link '(url-link "https://github.com/vscode-langservers/vscode-json-languageserver") + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-json-schemas nil + "Associate schemas to JSON files in the current project" + :type '(repeat alist) + :group 'lsp-json + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-http-proxy nil + "The URL of the proxy server to use when fetching schema." + :type 'string + :group 'lsp-json + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-http-proxyStrictSSL t + "The URL of the proxy server to use when fetching schema." + :type 'boolean + :group 'lsp-json + :package-version '(lsp-mode . "6.3")) + +(lsp-register-custom-settings + '(("json.schemas" lsp-json-schemas) + ("http.proxy" lsp-http-proxy) + ("http.proxyStrictSSL" lsp-http-proxyStrictSSL))) + +(defvar lsp-json--extra-init-params + `(:provideFormatter t + :handledSchemaProtocols ["file" "http" "https"])) + +(defvar lsp-json--schema-associations + `(:/*.css-data.json ["https://raw.githubusercontent.com/Microsoft/vscode-css-languageservice/master/docs/customData.schema.json"] + :/package.json ["http://json.schemastore.org/package"] + :/*.html-data.json ["https://raw.githubusercontent.com/Microsoft/vscode-html-languageservice/master/docs/customData.schema.json"] + :/*.schema.json ["http://json-schema.org/draft-07/schema#"] + :/bower.json ["http://json.schemastore.org/bower"] + :/composer.json ["http://json.schemastore.org/composer"] + :/tsconfig.json ["http://json.schemastore.org/tsconfig"] + :/tsconfig.*.json ["http://json.schemastore.org/tsconfig"] + :/typings.json ["http://json.schemastore.org/typings"] + :/.bowerrc ["http://json.schemastore.org/bowerrc"] + :/.babelrc ["http://json.schemastore.org/babelrc"] + :/.babelrc.json ["http://json.schemastore.org/babelrc"] + :/babel.config.json ["http://json.schemastore.org/babelrc"] + :/jsconfig.json ["http://json.schemastore.org/jsconfig"] + :/jsconfig.*.json ["http://json.schemastore.org/jsconfig"] + :/project.json ["http://json.schemastore.org/project"] + :/omnisharp.json ["http://json.schemastore.org/omnisharp"] + :/.eslintrc.json ["http://json.schemastore.org/eslintrc"] + :/.eslintrc ["http://json.schemastore.org/eslintrc"]) + "Default json schemas.") + +(defun lsp-json--get-content (_workspace uri callback) + "Get content from URI." + (ignore-errors + (url-retrieve uri + (lambda (_status callback) + (goto-char (point-min)) + (re-search-forward "\n\n" nil 'noerror) + (funcall + callback + (decode-coding-string (buffer-substring (point) (point-max)) + 'utf-8-unix))) + (list callback)))) + +(lsp-dependency 'vscode-json-languageserver + '(:system "vscode-json-languageserver") + '(:npm :package "vscode-json-languageserver" + :path "vscode-json-languageserver")) + +(lsp-register-client + (make-lsp-client + :new-connection + (lsp-stdio-connection + (lambda () (list (lsp-package-path 'vscode-json-languageserver) "--stdio"))) + :activation-fn (lsp-activate-on "json" "jsonc") + :server-id 'json-ls + :priority 0 + :multi-root t + :completion-in-comments? t + :initialization-options lsp-json--extra-init-params + :async-request-handlers (ht ("vscode/content" #'lsp-json--get-content)) + :initialized-fn + (lambda (w) + (with-lsp-workspace w + (lsp--set-configuration + (ht-merge (lsp-configuration-section "json") + (lsp-configuration-section "http"))) + (lsp-notify "json/schemaAssociations" lsp-json--schema-associations))) + :download-server-fn + (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'vscode-json-languageserver callback error-callback)))) + +(lsp-consistency-check lsp-json) + +(provide 'lsp-json) +;;; lsp-json.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-kotlin.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-kotlin.el new file mode 100644 index 0000000..329debc --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-kotlin.el @@ -0,0 +1,121 @@ +;;; lsp-kotlin.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, kotlin + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the Kotlin Programming Language. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-kotlin nil + "LSP support for Kotlin, using KotlinLanguageServer." + :group 'lsp-mode + :link '(url-link "https://github.com/fwcd/KotlinLanguageServer")) + +(define-obsolete-variable-alias + 'lsp-kotlin-language-server-path + 'lsp-clients-kotlin-server-executable + "lsp-mode 6.4") + +(defcustom lsp-clients-kotlin-server-executable "kotlin-language-server" + "The kotlin-language-server executable to use. +Leave as just the executable name to use the default behavior of finding the +executable with `exec-path'." + :type 'string + :group 'lsp-kotlin) + +(defcustom lsp-kotlin-trace-server "off" + "Traces the communication between VSCode and the Kotlin language server." + :type '(choice (:tag "off" "messages" "verbose")) + :group 'lsp-kotlin + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-kotlin-compiler-jvm-target "1.8" + "Specifies the JVM target, e.g. \"1.6\" or \"1.8\"." + :type 'string + :group 'lsp-kotlin + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-kotlin-linting-debounce-time 250 + "[DEBUG] Specifies the debounce time limit. +Lower to increase responsiveness at the cost of possible stability issues." + :type 'number + :group 'lsp-kotlin + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-kotlin-completion-snippets-enabled t + "Specifies whether code completion should provide snippets (true) or +plain-text items (false)." + :type 'boolean + :group 'lsp-kotlin + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-kotlin-debug-adapter-enabled t + "[Recommended] Specifies whether the debug adapter should be used. +When enabled a debugger for Kotlin will be available." + :type 'boolean) + +(defcustom lsp-kotlin-debug-adapter-path "" + "Optionally a custom path to the debug adapter executable." + :type 'string + :group 'lsp-kotlin + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-kotlin-external-sources-use-kls-scheme t + "[Recommended] Specifies whether URIs inside JARs should be represented +using the 'kls'-scheme." + :type 'boolean + :group 'lsp-kotlin + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-kotlin-external-sources-auto-convert-to-kotlin t + "Specifies whether decompiled/external classes should be auto-converted +to Kotlin." + :type 'boolean + :group 'lsp-kotlin + :package-version '(lsp-mode . "6.1")) + +(lsp-register-custom-settings + '(("kotlin.externalSources.autoConvertToKotlin" lsp-kotlin-external-sources-auto-convert-to-kotlin t) + ("kotlin.externalSources.useKlsScheme" lsp-kotlin-external-sources-use-kls-scheme t) + ("kotlin.debugAdapter.path" lsp-kotlin-debug-adapter-path) + ("kotlin.debugAdapter.enabled" lsp-kotlin-debug-adapter-enabled t) + ("kotlin.completion.snippets.enabled" lsp-kotlin-completion-snippets-enabled t) + ("kotlin.linting.debounceTime" lsp-kotlin-linting-debounce-time) + ("kotlin.compiler.jvm.target" lsp-kotlin-compiler-jvm-target) + ("kotlin.trace.server" lsp-kotlin-trace-server) + ("kotlin.languageServer.path" lsp-clients-kotlin-server-executable))) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection lsp-clients-kotlin-server-executable) + :major-modes '(kotlin-mode) + :priority -1 + :server-id 'kotlin-ls + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration (lsp-configuration-section "kotlin")))))) + +(lsp-consistency-check lsp-kotlin) + +(provide 'lsp-kotlin) +;;; lsp-kotlin.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-lens.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-lens.el new file mode 100644 index 0000000..d08580a --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-lens.el @@ -0,0 +1,425 @@ +;;; lsp-lens.el --- LSP lens -*- lexical-binding: t; -*- +;; +;; Copyright (C) 2020 emacs-lsp maintainers +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. +;; +;;; Commentary: +;; +;; LSP lens +;; +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-lens nil + "LSP support for lens" + :prefix "lsp-lens-" + :group 'lsp-mode + :tag "LSP Lens") + +(defcustom lsp-lens-debounce-interval 0.001 + "Debounce interval for loading lenses." + :group 'lsp-lens + :type 'number) + +(defcustom lsp-lens-place-position 'end-of-line + "The position to place lens relative to returned lens position." + :group 'lsp-lens + :type '(choice (const above-line) + (const end-of-line)) + :package-version '(lsp-mode . "7.1")) + +(defface lsp-lens-mouse-face + '((t :height 0.8 :inherit link)) + "The face used for code lens overlays." + :group 'lsp-lens) + +(defface lsp-lens-face + '((t :inherit lsp-details-face)) + "The face used for code lens overlays." + :group 'lsp-lens) + +(defvar-local lsp-lens--modified? nil) + +(defvar-local lsp-lens--overlays nil + "Current lenses.") + +(defvar-local lsp-lens--page nil + "Pair of points which holds the last window location the lenses were loaded.") + +(defvar-local lsp-lens--last-count nil + "The number of lenses the last time they were rendered.") + +(defvar lsp-lens-backends '(lsp-lens--backend) + "Backends providing lenses.") + +(defvar-local lsp-lens--refresh-timer nil + "Refresh timer for the lenses.") + +(defvar-local lsp-lens--data nil + "Pair of points which holds the last window location the lenses were loaded.") + +(defvar-local lsp-lens--backend-cache nil) + +(defun lsp-lens--text-width (from to) + "Measure the width of the text between FROM and TO. +Results are meaningful only if FROM and TO are on the same line." + ;; `current-column' takes prettification into account + (- (save-excursion (goto-char to) (current-column)) + (save-excursion (goto-char from) (current-column)))) + +(defun lsp-lens--update (ov) + "Redraw quick-peek overlay OV." + (let* ((offset (lsp-lens--text-width (save-excursion + (beginning-of-visual-line) + (point)) + (save-excursion + (beginning-of-line-text) + (point)))) + (str (if (eq 'end-of-line lsp-lens-place-position) + (overlay-get ov 'lsp--lens-contents) + (concat (make-string offset ?\s) + (overlay-get ov 'lsp--lens-contents))))) + (save-excursion + (goto-char (overlay-start ov)) + (if (eq 'end-of-line lsp-lens-place-position) + (overlay-put ov 'after-string (propertize (concat " " str) 'cursor t)) + (overlay-put ov 'before-string (concat str "\n"))) + (overlay-put ov 'lsp-original str)))) + +(defun lsp-lens--overlay-ensure-at (pos) + "Find or create a lens for the line at POS." + (-doto (save-excursion + (goto-char pos) + (if (eq 'end-of-line lsp-lens-place-position) + (make-overlay (point-at-eol) -1 nil t t) + (make-overlay (point-at-bol) (1+ (point-at-eol)) nil t t))) + (overlay-put 'lsp-lens t) + (overlay-put 'evaporate t) + (overlay-put 'lsp-lens-position pos))) + +(defun lsp-lens--show (str pos metadata) + "Show STR in an inline window at POS including METADATA." + (let ((ov (lsp-lens--overlay-ensure-at pos))) + (save-excursion + (goto-char pos) + (setf (overlay-get ov 'lsp--lens-contents) str) + (setf (overlay-get ov 'lsp--metadata) metadata) + (lsp-lens--update ov) + ov))) + +(defun lsp-lens--idle-function (&optional buffer) + "Create idle function for buffer BUFFER." + (when (and (or (not buffer) (eq (current-buffer) buffer)) + (not (equal (cons (window-start) (window-end)) lsp-lens--page))) + (lsp-lens--schedule-refresh nil))) + +(defun lsp-lens--overlay-matches-pos (ov pos) + "Check if OV is a lens covering POS." + (and (overlay-get ov 'lsp-lens) + (overlay-start ov) + (<= (overlay-start ov) pos) + (< pos (overlay-end ov)))) + +(defun lsp-lens--after-save () + "Handler for `after-save-hook' for lens mode." + (lsp-lens--schedule-refresh t)) + +(defun lsp-lens--schedule-refresh (&optional buffer-modified?) + "Call each of the backend. +BUFFER-MODIFIED? determines whether the buffer was modified or +not." + (-some-> lsp-lens--refresh-timer cancel-timer) + + (setq lsp-lens--page (cons (window-start) (window-end))) + (setq lsp-lens--refresh-timer + (run-with-timer lsp-lens-debounce-interval + nil + #'lsp-lens-refresh + (or lsp-lens--modified? buffer-modified?) + (current-buffer)))) + +(defun lsp-lens--schedule-refresh-modified () + "Schedule a lens refresh due to a buffer-modification. +See `lsp-lens--schedule-refresh' for details." + (lsp-lens--schedule-refresh t)) + +(defun lsp-lens--keymap (command) + "Build the lens keymap for COMMAND." + (-doto (make-sparse-keymap) + (define-key [mouse-1] (lsp-lens--create-interactive-command command)))) + +(defun lsp-lens--create-interactive-command (command?) + "Create an interactive COMMAND? for the lens. +COMMAND? shall be an `&Command' (e.g. `&CodeLens' :command?) and +mustn't be nil." + (if (functionp (lsp:command-command command?)) + (lsp:command-command command?) + (lambda () + (interactive) + (lsp--execute-command command?)))) + +(defun lsp-lens--display (lenses) + "Show LENSES." + ;; rerender only if there are lenses which are not processed or if their count + ;; has changed(e. g. delete lens should trigger redisplay). + (let ((scroll-preserve-screen-position t)) + (setq lsp-lens--modified? nil) + (when (or (-any? (-lambda ((&CodeLens :_processed processed)) + (not processed)) + lenses) + (eq (length lenses) lsp-lens--last-count) + (not lenses)) + (setq lsp-lens--last-count (length lenses)) + (mapc #'delete-overlay lsp-lens--overlays) + (setq lsp-lens--overlays + (->> lenses + (-filter #'lsp:code-lens-command?) + (--map (prog1 it (lsp-put it :_processed t))) + (-group-by (-compose #'lsp:position-line #'lsp:range-start #'lsp:code-lens-range)) + (-map + (-lambda ((_ . lenses)) + (let* ((sorted (-sort (-on #'< (-compose #'lsp:position-character + #'lsp:range-start + #'lsp:code-lens-range)) + lenses)) + (data (-map + (-lambda ((lens &as &CodeLens + :command? (command &as + &Command :title :_face face))) + (propertize + title + 'face (or face 'lsp-lens-face) + 'action (lsp-lens--create-interactive-command command) + 'pointer 'hand + 'mouse-face 'lsp-lens-mouse-face + 'local-map (lsp-lens--keymap command))) + sorted))) + (lsp-lens--show + (s-join (propertize "|" 'face 'lsp-lens-face) data) + (-> sorted cl-first lsp:code-lens-range lsp:range-start lsp--position-to-point) + data))))))))) + +(defun lsp-lens-refresh (buffer-modified? &optional buffer) + "Refresh lenses using lenses backend. +BUFFER-MODIFIED? determines whether the BUFFER is modified or not." + (let ((buffer (or buffer (current-buffer)))) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (dolist (backend lsp-lens-backends) + (funcall backend buffer-modified? + (lambda (lenses version) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (lsp-lens--process backend lenses version)))))))))) + +(defun lsp-lens--process (backend lenses version) + "Process LENSES originated from BACKEND. +VERSION is the version of the file. The lenses has to be +refreshed only when all backends have reported for the same +version." + (setq lsp-lens--data (or lsp-lens--data (make-hash-table))) + (puthash backend (cons version (append lenses nil)) lsp-lens--data) + + (-let [backend-data (->> lsp-lens--data ht-values (-filter #'cl-rest))] + (when (and + (= (length lsp-lens-backends) (ht-size lsp-lens--data)) + (seq-every-p (-lambda ((version)) + (or (not version) (eq version lsp--cur-version))) + backend-data)) + ;; display the data only when the backends have reported data for the + ;; current version of the file + (lsp-lens--display (apply #'append (-map #'cl-rest backend-data))))) + version) + +(lsp-defun lsp--lens-backend-not-loaded? ((&CodeLens :range + (&Range :start) + :command? + :_pending pending)) + "Return t if LENS has to be loaded." + (and (< (window-start) (lsp--position-to-point start) (window-end)) + (not command?) + (not pending))) + +(lsp-defun lsp--lens-backend-present? ((&CodeLens :range (&Range :start) :command?)) + "Return t if LENS has to be loaded." + (or command? + (not (< (window-start) (lsp--position-to-point start) (window-end))))) + +(defun lsp-lens--backend-fetch-missing (lenses callback file-version) + "Fetch LENSES without command in for the current window. + +TICK is the buffer modified tick. If it does not match +`buffer-modified-tick' at the time of receiving the updates the +updates must be discarded.. +CALLBACK - the callback for the lenses. +FILE-VERSION - the version of the file." + (seq-each + (lambda (it) + (with-lsp-workspace (lsp-get it :_workspace) + (lsp-put it :_pending t) + (lsp-put it :_workspace nil) + (lsp-request-async "codeLens/resolve" it + (-lambda ((&CodeLens :command?)) + (lsp-put it :_pending nil) + (lsp-put it :command command?) + (when (seq-every-p #'lsp--lens-backend-present? lenses) + (funcall callback lenses file-version))) + :mode 'tick))) + (seq-filter #'lsp--lens-backend-not-loaded? lenses))) + +(defun lsp-lens--backend (modified? callback) + "Lenses backend using `textDocument/codeLens'. +MODIFIED? - t when buffer is modified since the last invocation. +CALLBACK - callback for the lenses." + (when (lsp--find-workspaces-for "textDocument/codeLens") + (if modified? + (progn + (setq lsp-lens--backend-cache nil) + (lsp-request-async "textDocument/codeLens" + `(:textDocument (:uri ,(lsp--buffer-uri))) + (lambda (lenses) + (setq lsp-lens--backend-cache + (seq-mapcat + (-lambda ((workspace . workspace-lenses)) + ;; preserve the original workspace so we can later use it to resolve the lens + (seq-do (-rpartial #'lsp-put :_workspace workspace) workspace-lenses) + workspace-lenses) + lenses)) + (if (-every? #'lsp:code-lens-command? lsp-lens--backend-cache) + (funcall callback lsp-lens--backend-cache lsp--cur-version) + (lsp-lens--backend-fetch-missing lsp-lens--backend-cache callback lsp--cur-version))) + :error-handler #'ignore + :mode 'tick + :no-merge t + :cancel-token (concat (buffer-name (current-buffer)) "-lenses"))) + (if (-all? #'lsp--lens-backend-present? lsp-lens--backend-cache) + (funcall callback lsp-lens--backend-cache lsp--cur-version) + (lsp-lens--backend-fetch-missing lsp-lens--backend-cache callback lsp--cur-version))))) + +;;;###autoload +(defun lsp-lens--enable () + "Enable lens mode." + (when (and lsp-lens-enable + (lsp-feature? "textDocument/codeLens")) + (lsp-lens-mode 1))) + +(defun lsp-lens--disable () + "Disable lens mode." + (lsp-lens-mode -1)) + +;;;###autoload +(defun lsp-lens-show () + "Display lenses in the buffer." + (interactive) + (->> (lsp-request "textDocument/codeLens" + `(:textDocument (:uri + ,(lsp--path-to-uri buffer-file-name)))) + (seq-map (-lambda ((lens &as &CodeAction :command?)) + (if command? + lens + (lsp-request "codeLens/resolve" lens)))) + lsp-lens--display)) + +;;;###autoload +(defun lsp-lens-hide () + "Delete all lenses." + (interactive) + (let ((scroll-preserve-screen-position t)) + (seq-do #'delete-overlay lsp-lens--overlays) + (setq lsp-lens--overlays nil))) + +;;;###autoload +(define-minor-mode lsp-lens-mode + "Toggle code-lens overlays." + :group 'lsp-lens + :global nil + :init-value nil + :lighter " Lens" + (cond + (lsp-lens-mode + (add-hook 'lsp-unconfigure-hook #'lsp-lens--disable nil t) + (add-hook 'lsp-configure-hook #'lsp-lens--enable nil t) + (add-hook 'lsp-on-idle-hook #'lsp-lens--idle-function nil t) + (add-hook 'lsp-on-change-hook #'lsp-lens--schedule-refresh-modified nil t) + (add-hook 'after-save-hook #'lsp-lens--after-save nil t) + (add-hook 'before-revert-hook #'lsp-lens-hide nil t) + (lsp-lens-refresh t)) + (t + (remove-hook 'lsp-on-idle-hook #'lsp-lens--idle-function t) + (remove-hook 'lsp-on-change-hook #'lsp-lens--schedule-refresh-modified t) + (remove-hook 'after-save-hook #'lsp-lens--after-save t) + (remove-hook 'before-revert-hook #'lsp-lens-hide t) + (when lsp-lens--refresh-timer + (cancel-timer lsp-lens--refresh-timer)) + (setq lsp-lens--refresh-timer nil) + (lsp-lens-hide) + (setq lsp-lens--last-count nil) + (setq lsp-lens--backend-cache nil) + (remove-hook 'lsp-configure-hook #'lsp-lens--enable t) + (remove-hook 'lsp-unconfigure-hook #'lsp-lens--disable t)))) + + +;; avy integration + +(declare-function avy-process "ext:avy" (candidates &optional overlay-fn cleanup-fn)) +(declare-function avy--key-to-char "ext:avy" (c)) +(defvar avy-action) + +;;;###autoload +(defun lsp-avy-lens () + "Click lsp lens using `avy' package." + (interactive) + (unless lsp-lens--overlays + (user-error "No lenses in current buffer")) + (let* ((avy-action 'identity) + (action (cl-third + (avy-process + (-mapcat + (lambda (overlay) + (-map-indexed + (lambda (index lens-token) + (list overlay index + (get-text-property 0 'action lens-token))) + (overlay-get overlay 'lsp--metadata))) + lsp-lens--overlays) + (-lambda (path ((ov index) . _win)) + (let* ((path (mapcar #'avy--key-to-char path)) + (str (propertize (string (car (last path))) + 'face 'avy-lead-face)) + (old-str (overlay-get ov 'before-string)) + (old-str-tokens (s-split "|" old-str)) + (old-token (seq-elt old-str-tokens index)) + (tokens `(,@(-take index old-str-tokens) + ,(-if-let ((_ prefix suffix) + (s-match "\\(^[[:space:]]+\\)\\(.*\\)" old-token)) + (concat prefix str suffix) + (concat str old-token)) + ,@(-drop (1+ index) old-str-tokens))) + (new-str (s-join (propertize "|" 'face 'lsp-lens-face) tokens)) + (new-str (if (s-ends-with? "\n" new-str) + new-str + (concat new-str "\n")))) + (overlay-put ov 'before-string new-str))) + (lambda () + (--map (overlay-put it 'before-string + (overlay-get it 'lsp-original)) + lsp-lens--overlays)))))) + (when action (funcall-interactively action)))) + +(lsp-consistency-check lsp-lens) + +(provide 'lsp-lens) +;;; lsp-lens.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-lua.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-lua.el new file mode 100644 index 0000000..2e76745 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-lua.el @@ -0,0 +1,678 @@ +;;; lsp-lua.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 E. Alexander Barbosa + +;; Author: E. Alexander Barbosa <elxbarbosa@outlook.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the Lua Programming Language + +;;; Code: + +(require 'lsp-mode) +(require 'f) +(require 'files) + +(defgroup lsp-emmy-lua nil + "Lua LSP client, provided by the EmmyLua Language Server." + :group 'lsp-mode + :version "7.1" + :link '(url-link "https://github.com/EmmyLua/EmmyLua-LanguageServer")) + +(defcustom lsp-clients-emmy-lua-java-path "java" + "Java Runtime binary location." + :group 'lsp-emmy-lua + :version "7.1" + :risky t + :type 'file) + +(defcustom lsp-clients-emmy-lua-jar-path (f-join lsp-server-install-dir "EmmyLua-LS-all.jar") + "Emmy Lua language server jar file." + :group 'lsp-emmy-lua + :version "7.1" + :risky t + :type 'file) + +(defcustom lsp-clients-emmy-lua-args '("-jar") + "Arguments to the Lua Language server." + :group 'lsp-emmy-lua + :version "7.1" + :risky t + :type '(repeat string)) + +(defcustom lsp-clients-emmy-lua-command nil + "Final command to call the Lua Language server." + :group 'lsp-emmy-lua + :version "7.1" + :risky t + :type '(repeat string)) + +(defun lsp-clients-emmy-lua-test () + "Test the Emmy Lua binaries and files." + (and (executable-find lsp-clients-emmy-lua-java-path) + (f-exists? lsp-clients-emmy-lua-jar-path))) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection (lambda () (or lsp-clients-emmy-lua-command + `(,lsp-clients-emmy-lua-java-path + ,@lsp-clients-emmy-lua-args + ,lsp-clients-emmy-lua-jar-path))) + #'lsp-clients-emmy-lua-test) + :major-modes '(lua-mode) + :server-id 'emmy-lua + :priority -1 + :notification-handlers (lsp-ht ("emmy/progressReport" #'ignore)))) + + +;;; lua-language-server +(defgroup lsp-lua-language-server nil + "Lua LSP client, provided by the Lua Language Server." + :group 'lsp-mode + :version "7.1" + :link '(url-link "https://github.com/sumneko/lua-language-server")) + +(defcustom lsp-clients-lua-language-server-install-dir (f-join lsp-server-install-dir "lua-language-server/") + "Installation directory for Lua Language Server." + :group 'lsp-lua-language-server + :version "7.1" + :risky t + :type 'directory) + +(defcustom lsp-clients-lua-language-server-bin + (f-join lsp-clients-lua-language-server-install-dir + "extension/server/bin/" + (pcase system-type + ('gnu/linux "Linux/lua-language-server") + ('darwin "macOS/lua-language-server") + ('windows-nt "Windows/lua-language-server.exe") + (_ "Linux/lua-language-server"))) + "Location of Lua Language Server." + :group 'lsp-lua-language-server + :version "7.1" + :risky t + :type 'file) + +(defcustom lsp-clients-lua-language-server-main-location + (f-join lsp-clients-lua-language-server-install-dir + "extension/server/main.lua") + "Location of Lua Language Server main.lua." + :group 'lsp-lua-language-server + :version "7.1" + :risky t + :type 'file) + +(defcustom lsp-clients-lua-language-server-args '("-E") + "Arguments to run the Lua Language server." + :group 'lsp-lua-language-server + :version "7.1" + :risky t + :type '(repeat string)) + +(defcustom lsp-clients-lua-language-server-command nil + "Command to start Lua Language server." + :group 'lsp-lua-language-server + :type '(repeat string)) + + +(defun lsp-clients-lua-language-server-test () + "Test Lua language server binaries and files." + (and (f-exists? lsp-clients-lua-language-server-main-location) + (f-exists? lsp-clients-lua-language-server-bin))) + +(defcustom lsp-lua-color-mode "Semantic" + "Color mode." + :type '(choice (:tag "Grammar" "Semantic")) + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-completion-call-snippet "Disable" + "Shows function call snippets." + :type '(choice (:tag "Disable" "Both" "Replace")) + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-completion-display-context 6 + "Previewing the relevant code snippet of the suggestion may help you +understand the usage of the suggestion. + +The number set indicates the number of intercepted lines in the code +fragment. If it is set to `0`, this feature can be disabled." + :type 'number + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-completion-enable t + "Enable completion." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-completion-keyword-snippet "Replace" + "Shows keyword syntax snippets." + :type '(choice (:tag "Disable" "Both" "Replace")) + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-completion-workspace-word t + "Show words within the workspace." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-develop-debugger-port 11412 + "Listen port of debugger." + :type 'number + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-develop-debugger-wait nil + "Suspend before debugger connects." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-develop-enable nil + "Developer mode. Do not enable, performance will be affected." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-diagnostics-disable nil + "Disabled diagnostic (Use code in hover brackets). +```json +\"Lua.diagnostics.disable\" : [ +\"unused-local\", +\"lowercase-global\" +] +```" + :type 'lsp-string-vector + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-diagnostics-enable t + "Enable diagnostics." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-diagnostics-globals nil + "Defined global variables. +```json +\"Lua.diagnostics.globals\" : [ +\"GLOBAL1\", +\"GLOBAL2\" +] +```" + :type 'lsp-string-vector + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-diagnostics-needed-file-status nil + "If you want to check only opened files, choice Opened; else choice Any. +```json +\"Lua.diagnostics.neededFileStatus\" : { +\"ambiguity-1\" : \"Any\", +\"circle-doc-class\" : \"Opened\" +} +```" + :type 'alist + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-diagnostics-severity nil + "Modified diagnostic severity. +```json +\"Lua.diagnostics.severity\" : { +\"redefined-local\" : \"Warning\", +\"emmy-lua\" : \"Hint\" +} +```" + :type 'alist + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-diagnostics-workspace-delay 0 + "Latency (milliseconds) for workspace diagnostics. When you start the +workspace, or edit any file, the entire workspace will be re-diagnosed in the +background. Set to negative to disable workspace diagnostics." + :type 'number + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-diagnostics-workspace-rate 100 + "Workspace diagnostics run rate (%). Decreasing this value reduces CPU usage, +but also reduces the speed of workspace diagnostics. The diagnosis of the file +you are currently editing is always done at full speed and is not affected by +this setting." + :type 'number + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-hint-enable nil + "Enable hint." + :type 'boolean + :package-version '(lsp-mmode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-hint-param-name t + "Hint parameter name when the parameter called is literal." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-hint-param-type t + "Show type hints at the parameter of the function." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-hint-set-type nil + "Hint type at assignment operation." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-hover-enable t + "Enable hover." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-hover-field-infer 3000 + "When hovering to view a table, type infer will be performed for each field. +When the accumulated time of type infer reaches the set value (MS), the type +infer of subsequent fields will be skipped." + :type 'number + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-hover-preview-fields 100 + "When hovering to view a table, limits the maximum number of previews for +fields." + :type 'number + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-hover-view-number t + "Hover to view numeric content (only if literal is not decimal)." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-hover-view-string t + "Hover to view the contents of a string (only if the literal contains an +escape character)." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-hover-view-string-max 1000 + "The maximum length of a hover to view the contents of a string." + :type 'number + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-intelli-sense-search-depth 0 + "Set the search depth for IntelliSense. Increasing this value increases +accuracy, but decreases performance. Different workspace have different +tolerance for this setting. Please adjust it to the appropriate value." + :type 'number + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-runtime-file-encoding "utf8" + "File encoding. The 'ansi' option is only available under the 'Windows' +platform." + :type '(choice (:tag "utf8" "ansi")) + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-runtime-nonstandard-symbol nil + "Supports non-standard symbols. Make sure that your runtime environment +supports these symbols." + :type 'lsp-string-vector + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-runtime-path + ["?.lua" "?/init.lua" "?/?.lua"] + "`package.path`." + :type 'lsp-string-vector + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-runtime-plugin nil + "(Proposed) Plugin path. Default is `.vscode/lua/plugin.lua`" + :type 'file + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-runtime-special nil + "The custom global variables are regarded as some special built-in variables, +and the language server will provide special support. +```json +\"Lua.runtime.special\" : { +\"include\" : \"require\" +} +```" + :type 'alist + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-runtime-unicode-name nil + "Allows Unicode characters in name." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-runtime-version "Lua 5.4" + "Lua runtime version." + :type '(choice (:tag "Lua 5.1" "Lua 5.2" "Lua 5.3" "Lua 5.4" "LuaJIT")) + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-signature-help-enable t + "Enable signature help." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-telemetry-enable nil + "Enable telemetry to send your editor information and error logs over the +network." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-window-progress-bar t + "Show progress bar in status bar." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-window-status-bar t + "Show extension status in status bar." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-workspace-ignore-dir + [".vscode"] + "Ignored directories (Use `.gitignore` grammar). +```json +\"Lua.workspace.ignoreDir\" : [ +\"temp/*.*\", +\"!temp/*.lua\" +] +```" + :type 'lsp-string-vector + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-workspace-ignore-submodules t + "Ignore submodules." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-workspace-library nil + "Load external library. + +This feature can load external Lua files, which can be used for definition, +automatic completion and other functions. Note that the language server does +not monitor changes in external files and needs to restart if the external +files are modified. The following example shows loaded files in `C:/lua` +and `../lib` ,exclude `../lib/temp`. + +```json +\"Lua.workspace.library\": { +\"C:/lua\": true, +\"../lib\": [ +\"temp/*\" +] +} +```" + :type 'alist + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-workspace-max-preload 1000 + "Max preloaded files." + :type 'number + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-workspace-preload-file-size 100 + "Skip files larger than this value (KB) when preloading." + :type 'number + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-workspace-use-git-ignore t + "Ignore files list in `.gitignore` ." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-files-associations nil + "Files.associations." + :type 'alist + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(defcustom lsp-lua-files-exclude nil + "Files.exclude." + :type 'alist + :package-version '(lsp-mode . "7.1") + :group 'lsp-lua-language-server) + +(lsp-register-custom-settings + '(("files.associations" lsp-lua-files-associations t) + ("files.exclude" lsp-lua-files-exclude t) + ("Lua.workspace.useGitIgnore" lsp-lua-workspace-use-git-ignore t) + ("Lua.workspace.preloadFileSize" lsp-lua-workspace-preload-file-size) + ("Lua.workspace.maxPreload" lsp-lua-workspace-max-preload) + ("Lua.workspace.library" lsp-lua-workspace-library) + ("Lua.workspace.ignoreSubmodules" lsp-lua-workspace-ignore-submodules t) + ("Lua.workspace.ignoreDir" lsp-lua-workspace-ignore-dir) + ("Lua.window.statusBar" lsp-lua-window-status-bar t) + ("Lua.window.progressBar" lsp-lua-window-progress-bar t) + ("Lua.telemetry.enable" lsp-lua-telemetry-enable t) + ("Lua.signatureHelp.enable" lsp-lua-signature-help-enable t) + ("Lua.runtime.version" lsp-lua-runtime-version) + ("Lua.runtime.unicodeName" lsp-lua-runtime-unicode-name nil) + ("Lua.runtime.special" lsp-lua-runtime-special) + ("Lua.runtime.plugin" lsp-lua-runtime-plugin) + ("Lua.runtime.path" lsp-lua-runtime-path) + ("Lua.runtime.nonstandardSymbol" lsp-lua-runtime-nonstandard-symbol) + ("Lua.runtime.fileEncoding" lsp-lua-runtime-file-encoding) + ("Lua.intelliSense.searchDepth" lsp-lua-intelli-sense-search-depth) + ("Lua.hover.viewStringMax" lsp-lua-hover-view-string-max) + ("Lua.hover.viewString" lsp-lua-hover-view-string t) + ("Lua.hover.viewNumber" lsp-lua-hover-view-number t) + ("Lua.hover.previewFields" lsp-lua-hover-preview-fields) + ("Lua.hover.fieldInfer" lsp-lua-hover-field-infer) + ("Lua.hover.enable" lsp-lua-hover-enable t) + ("Lua.hint.setType" lsp-lua-hint-set-type nil) + ("Lua.hint.paramType" lsp-lua-hint-param-type t) + ("Lua.hint.paramName" lsp-lua-hint-param-name t) + ("Lua.hint.enable" lsp-lua-hint-enable t) + ("Lua.diagnostics.workspaceRate" lsp-lua-diagnostics-workspace-rate) + ("Lua.diagnostics.workspaceDelay" lsp-lua-diagnostics-workspace-delay) + ("Lua.diagnostics.severity" lsp-lua-diagnostics-severity) + ("Lua.diagnostics.neededFileStatus" lsp-lua-diagnostics-needed-file-status) + ("Lua.diagnostics.globals" lsp-lua-diagnostics-globals) + ("Lua.diagnostics.enable" lsp-lua-diagnostics-enable t) + ("Lua.diagnostics.disable" lsp-lua-diagnostics-disable) + ("Lua.develop.enable" lsp-lua-develop-enable t) + ("Lua.develop.debuggerWait" lsp-lua-develop-debugger-wait t) + ("Lua.develop.debuggerPort" lsp-lua-develop-debugger-port) + ("Lua.completion.workspaceWord" lsp-lua-completion-workspace-word t) + ("Lua.completion.keywordSnippet" lsp-lua-completion-keyword-snippet) + ("Lua.completion.enable" lsp-lua-completion-enable t) + ("Lua.completion.displayContext" lsp-lua-completion-display-context) + ("Lua.completion.callSnippet" lsp-lua-completion-call-snippet) + ("Lua.color.mode" lsp-lua-color-mode))) + +(defun lsp-lua-language-server-install (client callback error-callback update?) + "Download the latest version of lua-language-server and extract it to +`lsp-lua-language-server-install-dir'." + (ignore client update?) + (let ((store-path (expand-file-name "vs-lua" lsp-clients-lua-language-server-install-dir))) + (lsp-download-install + (lambda (&rest _) + (set-file-modes lsp-clients-lua-language-server-bin #o0700) + (funcall callback)) + error-callback + :url (lsp-vscode-extension-url "sumneko" "lua" "1.17.4") + :store-path store-path + :decompress :zip))) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection (lambda () (or lsp-clients-lua-language-server-command + `(,lsp-clients-lua-language-server-bin + ,@lsp-clients-lua-language-server-args + ,lsp-clients-lua-language-server-main-location))) + #'lsp-clients-lua-language-server-test) + :major-modes '(lua-mode) + :priority -2 + :server-id 'lua-language-server + :download-server-fn #'lsp-lua-language-server-install)) + + +;;; lua-lsp +(defgroup lsp-lua-lsp nil + "Lua LSP client, provided by the Lua-Lsp." + :group 'lsp-mode + :version "7.1" + :link '(url-link "https://github.com/Alloyed/lua-lsp")) + +(defcustom lsp-clients-luarocks-bin-dir (f-join (getenv "HOME") ".luarocks/bin/") + "LuaRocks bin directory." + :group 'lsp-lua-lsp + :version "7.1" + :risky t + :type 'directory) + +(defcustom lsp-clients-lua-lsp-server-install-dir nil + "Installation directory for Lua-Lsp Language Server." + :group 'lsp-lua-lsp + :version "7.1" + :risky t + :type 'file) + +(defun lsp-clients-lua-lsp-test () + "Test Lua-lsp language server files." + (and (f-exists? lsp-clients-lua-lsp-server-install-dir))) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection (lambda () + (or lsp-clients-lua-lsp-server-install-dir + (f-join lsp-clients-luarocks-bin-dir "lua-lsp"))) + #'lsp-clients-lua-lsp-test) + :major-modes '(lua-mode) + :priority -3 + :server-id 'lsp-lua-lsp)) + +;;; lua-roblox-language-server +(defgroup lsp-lua-roblox-language-server nil + "Roblox Lua LSP client, provided by the Roblox Lua Language Server." + :group 'lsp-mode + :version "7.1" + :link '(url-link "https://github.com/NightrainsRbx/RobloxLsp")) + +(defcustom lsp-lua-roblox-language-server-install-dir (f-join lsp-server-install-dir "lua-roblox-language-server/") + "Installation directory for Lua Language Server." + :group 'lsp-lua-roblox-language-server + :version "7.1" + :risky t + :type 'directory) + +(defcustom lsp-lua-roblox-language-server-bin + (f-join lsp-lua-roblox-language-server-install-dir + "extension/server/bin/" + (pcase system-type + ('gnu/linux "Linux/lua-language-server") + ('darwin "macOS/lua-language-server") + ('windows-nt "Windows/lua-language-server.exe") + (_ "Linux/lua-language-server"))) + "Location of Roblox Lua Language Server." + :group 'lsp-lua-roblox-language-server + :version "7.1" + :risky t + :type 'file) + +(defcustom lsp-lua-roblox-language-server-main-location + (f-join lsp-lua-roblox-language-server-install-dir + "extension/server/main.lua") + "Location of Roblox Lua Language Server main.lua." + :group 'lsp-lua-roblox-language-server + :version "7.1" + :risky t + :type 'file) + +(defcustom lsp-lua-roblox-server-download-url + (lsp-vscode-extension-url "Nightrains" "robloxlsp" "0.15.8") + "Download url for Roblox Lua vscode extension." + :group 'lsp-lua-roblox-language-server + :version "7.1" + :type 'string) + +(defcustom lsp-lua-roblox-server-store-path + (expand-file-name "vs-lua-roblox" lsp-lua-roblox-language-server-install-dir) + "Server file name for the vscode extension." + :group 'lsp-lua-roblox-language-server + :version "7.1" + :type 'string) + +(defun lsp-lua-roblox-language-server-test () + "Test Lua language server binaries and files." + (and (f-exists? lsp-lua-roblox-language-server-main-location) + (f-exists? lsp-lua-roblox-language-server-bin))) + +(defun lsp-lua-roblox-language-server-install (_client callback error-callback _update?) + "Download the latest version of lua-language-server and extract it to +`lsp-lua-roblox-language-server-download-url'." + (lsp-download-install + (lambda (&rest _) + (set-file-modes lsp-lua-roblox-language-server-bin #o0700) + (funcall callback)) + error-callback + :url lsp-lua-roblox-server-download-url + :store-path lsp-lua-roblox-server-store-path + :decompress :zip)) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection (lambda () (or lsp-clients-lua-language-server-command + `(,lsp-lua-roblox-language-server-bin + ,@lsp-clients-lua-language-server-args + ,lsp-lua-roblox-language-server-main-location))) + #'lsp-lua-roblox-language-server-test) + :major-modes '(lua-mode) + :priority -4 + :server-id 'lua-roblox-language-server + :download-server-fn #'lsp-lua-roblox-language-server-install)) + +(lsp-consistency-check lsp-lua) + +(provide 'lsp-lua) +;;; lsp-lua.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-markdown.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-markdown.el new file mode 100644 index 0000000..ae01dfa --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-markdown.el @@ -0,0 +1,105 @@ +;;; lsp-markdown.el --- lsp-mode markdown integration -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 lsp-mode maintainers + +;; Author: lsp-mode maintainers +;; Keywords: languages + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP client for unified-language-server + +;;; Code: + +(require 'lsp-mode) + +;;; Markdown +(defgroup lsp-markdown nil + "Settings for the markdown language server client." + :group 'lsp-mode + :link '(url-link "https://github.com/unifiedjs/unified-language-server") + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-markdown-server-command "unified-language-server" + "The binary (or full path to binary) which executes the server." + :type 'string + :group 'lsp-markdown + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-markdown-server-command-args '("--parser=remark-parse" "--stdio") + "Command-line arguments for the markdown lsp server." + :type '(repeat 'string) + :group 'lsp-markdown + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-markdown-remark-plugins [["#remark-preset-lint-markdown-style-guide"]] + "The JSON configuration object for plugins. + +For a complete list of plugins, check: + https://github.com/unifiedjs/unified-language-server/blob/main/CONFIGURATION.md#re-using-settings" + :type 'lsp-string-vector + :group 'lsp-markdown + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-markdown-remark-check-text-with-setting "retext-english" + "Configure `checkTextWith' subproperty. + +For a complete list of plugins, check: + https://github.com/unifiedjs/unified-language-server/blob/main/CONFIGURATION.md#re-using-settings" + :type '(choice ( + (const "retext-english") + (const "remark-parse"))) + :group 'lsp-markdown + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-markdown-remark-check-text-with-mutator ["#remark-retext" "#parse-latin"] + "Vector of additional mutators. + +For a complete list of plugins, check: + https://github.com/unifiedjs/unified-language-server/blob/main/CONFIGURATION.md#re-using-settings" + :type 'lsp-string-vector + :group 'lsp-markdown + :package-version '(lsp-mode . "7.1")) + +(lsp-dependency 'unified-language-server + '(:system "unified-language-server") + '(:npm :package "unified-language-server" + :path "unified-language-server")) + +(lsp-register-custom-settings + `(("unified-language-server.remark-parse.plugins" lsp-markdown-remark-plugins) + ("unified-language-server.remark-parse.checkTextWith.setting" lsp-markdown-remark-check-text-with-setting) + ("unified-language-server.remark-parse.checkTextWith.mutator" lsp-markdown-remark-check-text-with-mutator))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (lambda () + (cons (or (executable-find lsp-markdown-server-command) + (lsp-package-path 'unified-language-server)) + lsp-markdown-server-command-args))) + :activation-fn (lsp-activate-on "markdown") + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration (lsp-configuration-section "unified-language-server")))) + :major-modes '(markdown-mode) + :priority -1 + :major-modes '(markdown-mode) + :server-id 'unified)) + +(lsp-consistency-check lsp-markdown) + +(provide 'lsp-markdown) +;;; lsp-markdown.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-mode-autoloads.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-mode-autoloads.el new file mode 100644 index 0000000..6f040a4 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-mode-autoloads.el @@ -0,0 +1,745 @@ +;;; lsp-mode-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "lsp-actionscript" "lsp-actionscript.el" (0 +;;;;;; 0 0 0)) +;;; Generated autoloads from lsp-actionscript.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-actionscript" '("lsp-actionscript-"))) + +;;;*** + +;;;### (autoloads nil "lsp-ada" "lsp-ada.el" (0 0 0 0)) +;;; Generated autoloads from lsp-ada.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-ada" '("lsp-ada-"))) + +;;;*** + +;;;### (autoloads nil "lsp-angular" "lsp-angular.el" (0 0 0 0)) +;;; Generated autoloads from lsp-angular.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-angular" '("lsp-client"))) + +;;;*** + +;;;### (autoloads nil "lsp-bash" "lsp-bash.el" (0 0 0 0)) +;;; Generated autoloads from lsp-bash.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-bash" '("lsp-bash-"))) + +;;;*** + +;;;### (autoloads nil "lsp-beancount" "lsp-beancount.el" (0 0 0 0)) +;;; Generated autoloads from lsp-beancount.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-beancount" '("lsp-beancount-"))) + +;;;*** + +;;;### (autoloads nil "lsp-clangd" "lsp-clangd.el" (0 0 0 0)) +;;; Generated autoloads from lsp-clangd.el + +(autoload 'lsp-cpp-flycheck-clang-tidy-error-explainer "lsp-clangd" "\ +Explain a clang-tidy ERROR by scraping documentation from llvm.org. + +\(fn ERROR)" nil nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-clangd" '("lsp-c"))) + +;;;*** + +;;;### (autoloads nil "lsp-clojure" "lsp-clojure.el" (0 0 0 0)) +;;; Generated autoloads from lsp-clojure.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-clojure" '("lsp-clojure-"))) + +;;;*** + +;;;### (autoloads nil "lsp-completion" "lsp-completion.el" (0 0 0 +;;;;;; 0)) +;;; Generated autoloads from lsp-completion.el + +(define-obsolete-variable-alias 'lsp-prefer-capf 'lsp-completion-provider "lsp-mode 7.0.1") + +(define-obsolete-variable-alias 'lsp-enable-completion-at-point 'lsp-completion-enable "lsp-mode 7.0.1") + +(autoload 'lsp-completion-at-point "lsp-completion" "\ +Get lsp completions." nil nil) + +(autoload 'lsp-completion--enable "lsp-completion" "\ +Enable LSP completion support." nil nil) + +(autoload 'lsp-completion-mode "lsp-completion" "\ +Toggle LSP completion support. + +If called interactively, enable Lsp-Completion mode if ARG is +positive, and disable it if ARG is zero or negative. If called +from Lisp, also enable the mode if ARG is omitted or nil, and +toggle it if ARG is `toggle'; disable the mode otherwise. + +\(fn &optional ARG)" t nil) + +(add-hook 'lsp-configure-hook (lambda nil (when (and lsp-auto-configure lsp-completion-enable) (lsp-completion--enable)))) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-completion" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-crystal" "lsp-crystal.el" (0 0 0 0)) +;;; Generated autoloads from lsp-crystal.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-crystal" '("lsp-clients-crystal-executable"))) + +;;;*** + +;;;### (autoloads nil "lsp-csharp" "lsp-csharp.el" (0 0 0 0)) +;;; Generated autoloads from lsp-csharp.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-csharp" '("lsp-csharp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-css" "lsp-css.el" (0 0 0 0)) +;;; Generated autoloads from lsp-css.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-css" '("lsp-css-"))) + +;;;*** + +;;;### (autoloads nil "lsp-diagnostics" "lsp-diagnostics.el" (0 0 +;;;;;; 0 0)) +;;; Generated autoloads from lsp-diagnostics.el + +(define-obsolete-variable-alias 'lsp-diagnostic-package 'lsp-diagnostics-provider "lsp-mode 7.0.1") + +(define-obsolete-variable-alias 'lsp-flycheck-default-level 'lsp-diagnostics-flycheck-default-level "lsp-mode 7.0.1") + +(autoload 'lsp-diagnostics-lsp-checker-if-needed "lsp-diagnostics" nil nil nil) + +(autoload 'lsp-diagnostics--enable "lsp-diagnostics" "\ +Enable LSP checker support." nil nil) + +(autoload 'lsp-diagnostics-mode "lsp-diagnostics" "\ +Toggle LSP diagnostics integration. + +If called interactively, enable Lsp-Diagnostics mode if ARG is +positive, and disable it if ARG is zero or negative. If called +from Lisp, also enable the mode if ARG is omitted or nil, and +toggle it if ARG is `toggle'; disable the mode otherwise. + +\(fn &optional ARG)" t nil) + +(add-hook 'lsp-configure-hook (lambda nil (when lsp-auto-configure (lsp-diagnostics--enable)))) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-diagnostics" '("lsp-diagnostics-"))) + +;;;*** + +;;;### (autoloads nil "lsp-dired" "lsp-dired.el" (0 0 0 0)) +;;; Generated autoloads from lsp-dired.el + +(defvar lsp-dired-mode nil "\ +Non-nil if Lsp-Dired mode is enabled. +See the `lsp-dired-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `lsp-dired-mode'.") + +(custom-autoload 'lsp-dired-mode "lsp-dired" nil) + +(autoload 'lsp-dired-mode "lsp-dired" "\ +Display `lsp-mode' icons for each file in a dired buffer. + +If called interactively, enable Lsp-Dired mode if ARG is +positive, and disable it if ARG is zero or negative. If called +from Lisp, also enable the mode if ARG is omitted or nil, and +toggle it if ARG is `toggle'; disable the mode otherwise. + +\(fn &optional ARG)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-dired" '("lsp-dired-"))) + +;;;*** + +;;;### (autoloads nil "lsp-dockerfile" "lsp-dockerfile.el" (0 0 0 +;;;;;; 0)) +;;; Generated autoloads from lsp-dockerfile.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-dockerfile" '("lsp-dockerfile-language-server-command"))) + +;;;*** + +;;;### (autoloads nil "lsp-elixir" "lsp-elixir.el" (0 0 0 0)) +;;; Generated autoloads from lsp-elixir.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-elixir" '("lsp-elixir-"))) + +;;;*** + +;;;### (autoloads nil "lsp-elm" "lsp-elm.el" (0 0 0 0)) +;;; Generated autoloads from lsp-elm.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-elm" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-erlang" "lsp-erlang.el" (0 0 0 0)) +;;; Generated autoloads from lsp-erlang.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-erlang" '("lsp-erlang-server-"))) + +;;;*** + +;;;### (autoloads nil "lsp-eslint" "lsp-eslint.el" (0 0 0 0)) +;;; Generated autoloads from lsp-eslint.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-eslint" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-fortran" "lsp-fortran.el" (0 0 0 0)) +;;; Generated autoloads from lsp-fortran.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-fortran" '("lsp-clients-"))) + +;;;*** + +;;;### (autoloads nil "lsp-fsharp" "lsp-fsharp.el" (0 0 0 0)) +;;; Generated autoloads from lsp-fsharp.el + +(autoload 'lsp-fsharp--workspace-load "lsp-fsharp" "\ +Load all of the provided PROJECTS. + +\(fn PROJECTS)" nil nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-fsharp" '("lsp-fsharp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-gdscript" "lsp-gdscript.el" (0 0 0 0)) +;;; Generated autoloads from lsp-gdscript.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-gdscript" '("lsp-gdscript-"))) + +;;;*** + +;;;### (autoloads nil "lsp-go" "lsp-go.el" (0 0 0 0)) +;;; Generated autoloads from lsp-go.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-go" '("lsp-go-"))) + +;;;*** + +;;;### (autoloads nil "lsp-groovy" "lsp-groovy.el" (0 0 0 0)) +;;; Generated autoloads from lsp-groovy.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-groovy" '("lsp-groovy-"))) + +;;;*** + +;;;### (autoloads nil "lsp-hack" "lsp-hack.el" (0 0 0 0)) +;;; Generated autoloads from lsp-hack.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-hack" '("lsp-clients-hack-command"))) + +;;;*** + +;;;### (autoloads nil "lsp-haxe" "lsp-haxe.el" (0 0 0 0)) +;;; Generated autoloads from lsp-haxe.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-haxe" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-headerline" "lsp-headerline.el" (0 0 0 +;;;;;; 0)) +;;; Generated autoloads from lsp-headerline.el + +(autoload 'lsp-headerline-breadcrumb-mode "lsp-headerline" "\ +Toggle breadcrumb on headerline. + +If called interactively, enable Lsp-Headerline-Breadcrumb mode if +ARG is positive, and disable it if ARG is zero or negative. If +called from Lisp, also enable the mode if ARG is omitted or nil, +and toggle it if ARG is `toggle'; disable the mode otherwise. + +\(fn &optional ARG)" t nil) + +(autoload 'lsp-breadcrumb-go-to-symbol "lsp-headerline" "\ +Go to the symbol on breadcrumb at SYMBOL-POSITION. + +\(fn SYMBOL-POSITION)" t nil) + +(autoload 'lsp-breadcrumb-narrow-to-symbol "lsp-headerline" "\ +Narrow to the symbol range on breadcrumb at SYMBOL-POSITION. + +\(fn SYMBOL-POSITION)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-headerline" '("lsp-headerline-"))) + +;;;*** + +;;;### (autoloads nil "lsp-html" "lsp-html.el" (0 0 0 0)) +;;; Generated autoloads from lsp-html.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-html" '("lsp-html-"))) + +;;;*** + +;;;### (autoloads nil "lsp-icons" "lsp-icons.el" (0 0 0 0)) +;;; Generated autoloads from lsp-icons.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-icons" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-ido" "lsp-ido.el" (0 0 0 0)) +;;; Generated autoloads from lsp-ido.el + +(autoload 'lsp-ido-workspace-symbol "lsp-ido" "\ +`ido' for lsp workspace/symbol. +When called with prefix ARG the default selection will be symbol at point. + +\(fn ARG)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-ido" '("lsp-ido-"))) + +;;;*** + +;;;### (autoloads nil "lsp-iedit" "lsp-iedit.el" (0 0 0 0)) +;;; Generated autoloads from lsp-iedit.el + +(autoload 'lsp-iedit-highlights "lsp-iedit" "\ +Start an `iedit' operation on the documentHighlights at point. +This can be used as a primitive `lsp-rename' replacement if the +language server doesn't support renaming. + +See also `lsp-enable-symbol-highlighting'." t nil) + +(autoload 'lsp-evil-multiedit-highlights "lsp-iedit" "\ +Start an `evil-multiedit' operation on the documentHighlights at point. +This can be used as a primitive `lsp-rename' replacement if the +language server doesn't support renaming. + +See also `lsp-enable-symbol-highlighting'." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-iedit" '("lsp-iedit--on-ranges"))) + +;;;*** + +;;;### (autoloads nil "lsp-javascript" "lsp-javascript.el" (0 0 0 +;;;;;; 0)) +;;; Generated autoloads from lsp-javascript.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-javascript" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-json" "lsp-json.el" (0 0 0 0)) +;;; Generated autoloads from lsp-json.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-json" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-kotlin" "lsp-kotlin.el" (0 0 0 0)) +;;; Generated autoloads from lsp-kotlin.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-kotlin" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-lens" "lsp-lens.el" (0 0 0 0)) +;;; Generated autoloads from lsp-lens.el + +(autoload 'lsp-lens--enable "lsp-lens" "\ +Enable lens mode." nil nil) + +(autoload 'lsp-lens-show "lsp-lens" "\ +Display lenses in the buffer." t nil) + +(autoload 'lsp-lens-hide "lsp-lens" "\ +Delete all lenses." t nil) + +(autoload 'lsp-lens-mode "lsp-lens" "\ +Toggle code-lens overlays. + +If called interactively, enable Lsp-Lens mode if ARG is positive, +and disable it if ARG is zero or negative. If called from Lisp, +also enable the mode if ARG is omitted or nil, and toggle it if +ARG is `toggle'; disable the mode otherwise. + +\(fn &optional ARG)" t nil) + +(autoload 'lsp-avy-lens "lsp-lens" "\ +Click lsp lens using `avy' package." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-lens" '("lsp-lens-"))) + +;;;*** + +;;;### (autoloads nil "lsp-lua" "lsp-lua.el" (0 0 0 0)) +;;; Generated autoloads from lsp-lua.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-lua" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-markdown" "lsp-markdown.el" (0 0 0 0)) +;;; Generated autoloads from lsp-markdown.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-markdown" '("lsp-markdown-"))) + +;;;*** + +;;;### (autoloads nil "lsp-mode" "lsp-mode.el" (0 0 0 0)) +;;; Generated autoloads from lsp-mode.el +(put 'lsp-enable-file-watchers 'safe-local-variable #'booleanp) +(put 'lsp-file-watch-threshold 'safe-local-variable (lambda (i) (or (numberp i) (not i)))) + +(autoload 'lsp-load-vscode-workspace "lsp-mode" "\ +Load vscode workspace from FILE + +\(fn FILE)" t nil) + +(autoload 'lsp-save-vscode-workspace "lsp-mode" "\ +Save vscode workspace to FILE + +\(fn FILE)" t nil) + +(autoload 'lsp-install-server "lsp-mode" "\ +Interactively install server. +When prefix UPDATE? is t force installation even if the server is present. + +\(fn UPDATE\\=\\? &optional SERVER-ID)" t nil) + +(autoload 'lsp-ensure-server "lsp-mode" "\ +Ensure server SERVER-ID + +\(fn SERVER-ID)" nil nil) + +(autoload 'lsp "lsp-mode" "\ +Entry point for the server startup. +When ARG is t the lsp mode will start new language server even if +there is language server which can handle current language. When +ARG is nil current file will be opened in multi folder language +server if there is such. When `lsp' is called with prefix +argument ask the user to select which language server to start. + +\(fn &optional ARG)" t nil) + +(autoload 'lsp-deferred "lsp-mode" "\ +Entry point that defers server startup until buffer is visible. +`lsp-deferred' will wait until the buffer is visible before invoking `lsp'. +This avoids overloading the server with many files when starting Emacs." nil nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-mode" '("lsp-" "make-lsp-client" "when-lsp-workspace" "with-lsp-workspace"))) + +;;;*** + +;;;### (autoloads nil "lsp-modeline" "lsp-modeline.el" (0 0 0 0)) +;;; Generated autoloads from lsp-modeline.el + +(define-obsolete-variable-alias 'lsp-diagnostics-modeline-scope 'lsp-modeline-diagnostics-scope "lsp-mode 7.0.1") + +(autoload 'lsp-modeline-code-actions-mode "lsp-modeline" "\ +Toggle code actions on modeline. + +If called interactively, enable Lsp-Modeline-Code-Actions mode if +ARG is positive, and disable it if ARG is zero or negative. If +called from Lisp, also enable the mode if ARG is omitted or nil, +and toggle it if ARG is `toggle'; disable the mode otherwise. + +\(fn &optional ARG)" t nil) + +(define-obsolete-function-alias 'lsp-diagnostics-modeline-mode 'lsp-modeline-diagnostics-mode "lsp-mode 7.0.1") + +(autoload 'lsp-modeline-diagnostics-mode "lsp-modeline" "\ +Toggle diagnostics modeline. + +If called interactively, enable Lsp-Modeline-Diagnostics mode if +ARG is positive, and disable it if ARG is zero or negative. If +called from Lisp, also enable the mode if ARG is omitted or nil, +and toggle it if ARG is `toggle'; disable the mode otherwise. + +\(fn &optional ARG)" t nil) + +(autoload 'lsp-modeline-workspace-status-mode "lsp-modeline" "\ +Toggle workspace status on modeline. + +If called interactively, enable Lsp-Modeline-Workspace-Status +mode if ARG is positive, and disable it if ARG is zero or +negative. If called from Lisp, also enable the mode if ARG is +omitted or nil, and toggle it if ARG is `toggle'; disable the +mode otherwise. + +\(fn &optional ARG)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-modeline" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-nix" "lsp-nix.el" (0 0 0 0)) +;;; Generated autoloads from lsp-nix.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-nix" '("lsp-nix-server-path"))) + +;;;*** + +;;;### (autoloads nil "lsp-ocaml" "lsp-ocaml.el" (0 0 0 0)) +;;; Generated autoloads from lsp-ocaml.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-ocaml" '("lsp-ocaml-l"))) + +;;;*** + +;;;### (autoloads nil "lsp-perl" "lsp-perl.el" (0 0 0 0)) +;;; Generated autoloads from lsp-perl.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-perl" '("lsp-perl-"))) + +;;;*** + +;;;### (autoloads nil "lsp-php" "lsp-php.el" (0 0 0 0)) +;;; Generated autoloads from lsp-php.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-php" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-prolog" "lsp-prolog.el" (0 0 0 0)) +;;; Generated autoloads from lsp-prolog.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-prolog" '("lsp-prolog-server-command"))) + +;;;*** + +;;;### (autoloads nil "lsp-protocol" "lsp-protocol.el" (0 0 0 0)) +;;; Generated autoloads from lsp-protocol.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-protocol" '("dash-expand:&RangeToPoint" "lsp"))) + +;;;*** + +;;;### (autoloads nil "lsp-purescript" "lsp-purescript.el" (0 0 0 +;;;;;; 0)) +;;; Generated autoloads from lsp-purescript.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-purescript" '("lsp-purescript-"))) + +;;;*** + +;;;### (autoloads nil "lsp-pwsh" "lsp-pwsh.el" (0 0 0 0)) +;;; Generated autoloads from lsp-pwsh.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-pwsh" '("lsp-pwsh-"))) + +;;;*** + +;;;### (autoloads nil "lsp-pyls" "lsp-pyls.el" (0 0 0 0)) +;;; Generated autoloads from lsp-pyls.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-pyls" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-pylsp" "lsp-pylsp.el" (0 0 0 0)) +;;; Generated autoloads from lsp-pylsp.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-pylsp" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-r" "lsp-r.el" (0 0 0 0)) +;;; Generated autoloads from lsp-r.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-r" '("lsp-clients-r-server-command"))) + +;;;*** + +;;;### (autoloads nil "lsp-racket" "lsp-racket.el" (0 0 0 0)) +;;; Generated autoloads from lsp-racket.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-racket" '("lsp-racket-lang"))) + +;;;*** + +;;;### (autoloads nil "lsp-rf" "lsp-rf.el" (0 0 0 0)) +;;; Generated autoloads from lsp-rf.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-rf" '("expand-start-command" "lsp-rf-language-server-" "parse-rf-language-server-"))) + +;;;*** + +;;;### (autoloads nil "lsp-rust" "lsp-rust.el" (0 0 0 0)) +;;; Generated autoloads from lsp-rust.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-rust" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-semantic-tokens" "lsp-semantic-tokens.el" +;;;;;; (0 0 0 0)) +;;; Generated autoloads from lsp-semantic-tokens.el + +(autoload 'lsp--semantic-tokens-initialize-buffer "lsp-semantic-tokens" "\ +Initialize the buffer for semantic tokens. +IS-RANGE-PROVIDER is non-nil when server supports range requests." nil nil) + +(autoload 'lsp--semantic-tokens-initialize-workspace "lsp-semantic-tokens" "\ +Initialize semantic tokens for WORKSPACE. + +\(fn WORKSPACE)" nil nil) + +(autoload 'lsp-semantic-tokens--warn-about-deprecated-setting "lsp-semantic-tokens" "\ +Warn about deprecated semantic highlighting variable." nil nil) + +(autoload 'lsp-semantic-tokens--enable "lsp-semantic-tokens" "\ +Enable semantic tokens mode." nil nil) + +(autoload 'lsp-semantic-tokens-mode "lsp-semantic-tokens" "\ +Toggle semantic-tokens support. + +If called interactively, enable Lsp-Semantic-Tokens mode if ARG +is positive, and disable it if ARG is zero or negative. If +called from Lisp, also enable the mode if ARG is omitted or nil, +and toggle it if ARG is `toggle'; disable the mode otherwise. + +\(fn &optional ARG)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-semantic-tokens" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-solargraph" "lsp-solargraph.el" (0 0 0 +;;;;;; 0)) +;;; Generated autoloads from lsp-solargraph.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-solargraph" '("lsp-solargraph-"))) + +;;;*** + +;;;### (autoloads nil "lsp-sorbet" "lsp-sorbet.el" (0 0 0 0)) +;;; Generated autoloads from lsp-sorbet.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-sorbet" '("lsp-sorbet-"))) + +;;;*** + +;;;### (autoloads nil "lsp-sqls" "lsp-sqls.el" (0 0 0 0)) +;;; Generated autoloads from lsp-sqls.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-sqls" '("lsp-sql"))) + +;;;*** + +;;;### (autoloads nil "lsp-steep" "lsp-steep.el" (0 0 0 0)) +;;; Generated autoloads from lsp-steep.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-steep" '("lsp-steep-"))) + +;;;*** + +;;;### (autoloads nil "lsp-svelte" "lsp-svelte.el" (0 0 0 0)) +;;; Generated autoloads from lsp-svelte.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-svelte" '("lsp-svelte-plugin-"))) + +;;;*** + +;;;### (autoloads nil "lsp-terraform" "lsp-terraform.el" (0 0 0 0)) +;;; Generated autoloads from lsp-terraform.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-terraform" '("lsp-terraform-"))) + +;;;*** + +;;;### (autoloads nil "lsp-tex" "lsp-tex.el" (0 0 0 0)) +;;; Generated autoloads from lsp-tex.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-tex" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-v" "lsp-v.el" (0 0 0 0)) +;;; Generated autoloads from lsp-v.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-v" '("lsp-v-vls-executable"))) + +;;;*** + +;;;### (autoloads nil "lsp-vala" "lsp-vala.el" (0 0 0 0)) +;;; Generated autoloads from lsp-vala.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-vala" '("lsp-clients-vala-ls-executable"))) + +;;;*** + +;;;### (autoloads nil "lsp-verilog" "lsp-verilog.el" (0 0 0 0)) +;;; Generated autoloads from lsp-verilog.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-verilog" '("lsp-clients-"))) + +;;;*** + +;;;### (autoloads nil "lsp-vetur" "lsp-vetur.el" (0 0 0 0)) +;;; Generated autoloads from lsp-vetur.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-vetur" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-vhdl" "lsp-vhdl.el" (0 0 0 0)) +;;; Generated autoloads from lsp-vhdl.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-vhdl" '("ghdl-ls-bin-name" "hdl-checker-bin-name" "lsp-vhdl-" "vhdl-"))) + +;;;*** + +;;;### (autoloads nil "lsp-vimscript" "lsp-vimscript.el" (0 0 0 0)) +;;; Generated autoloads from lsp-vimscript.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-vimscript" '("lsp-clients-vim-"))) + +;;;*** + +;;;### (autoloads nil "lsp-xml" "lsp-xml.el" (0 0 0 0)) +;;; Generated autoloads from lsp-xml.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-xml" '("lsp-xml-"))) + +;;;*** + +;;;### (autoloads nil "lsp-yaml" "lsp-yaml.el" (0 0 0 0)) +;;; Generated autoloads from lsp-yaml.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-yaml" '("lsp-yaml-"))) + +;;;*** + +;;;### (autoloads nil "lsp-zig" "lsp-zig.el" (0 0 0 0)) +;;; Generated autoloads from lsp-zig.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-zig" '("lsp-zig-zls-executable"))) + +;;;*** + +;;;### (autoloads nil nil ("lsp-cmake.el" "lsp-d.el" "lsp-dhall.el" +;;;;;; "lsp-mode-pkg.el" "lsp-nim.el" "lsp.el") (0 0 0 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; lsp-mode-autoloads.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-mode-pkg.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-mode-pkg.el new file mode 100644 index 0000000..3093b63 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-mode-pkg.el @@ -0,0 +1,18 @@ +(define-package "lsp-mode" "20210716.2233" "LSP mode" + '((emacs "26.1") + (dash "2.18.0") + (f "0.20.0") + (ht "2.3") + (spinner "1.7.3") + (markdown-mode "2.3") + (lv "0")) + :commit "21dd93ee4add2086d9006e0e6143553bdaa61519" :authors + '(("Vibhav Pant, Fangrui Song, Ivan Yonchovski")) + :maintainer + '("Vibhav Pant, Fangrui Song, Ivan Yonchovski") + :keywords + '("languages") + :url "https://github.com/emacs-lsp/lsp-mode") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-mode.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-mode.el new file mode 100644 index 0000000..0fd635b --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-mode.el @@ -0,0 +1,8656 @@ +;;; lsp-mode.el --- LSP mode -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: Vibhav Pant, Fangrui Song, Ivan Yonchovski +;; Keywords: languages +;; Package-Requires: ((emacs "26.1") (dash "2.18.0") (f "0.20.0") (ht "2.3") (spinner "1.7.3") (markdown-mode "2.3") (lv "0")) +;; Version: 7.1.0 + +;; URL: https://github.com/emacs-lsp/lsp-mode +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Emacs client/library for the Language Server Protocol + +;;; Code: + +(require 'cl-generic) +(require 'cl-lib) +(require 'compile) +(require 'dash) +(require 'epg) +(require 'ewoc) +(require 'f) +(require 'filenotify) +(require 'files) +(require 'ht) +(require 'imenu) +(require 'inline) +(require 'json) +(require 'lv) +(require 'markdown-mode) +(require 'network-stream) +(require 'pcase) +(require 'rx) +(require 's) +(require 'seq) +(require 'spinner) +(require 'subr-x) +(require 'tree-widget) +(require 'url-parse) +(require 'url-util) +(require 'widget) +(require 'xref) +(require 'minibuffer) +(require 'yasnippet nil t) +(require 'lsp-protocol) + +(defgroup lsp-mode nil + "Language Server Protocol client." + :group 'tools + :tag "Language Server (lsp-mode)") + +(declare-function evil-set-command-property "ext:evil-common") +(declare-function projectile-project-root "ext:projectile") +(declare-function yas-expand-snippet "ext:yasnippet") +(declare-function dap-mode "ext:dap-mode") +(declare-function dap-auto-configure-mode "ext:dap-mode") + +(defvar yas-inhibit-overlay-modification-protection) +(defvar yas-indent-line) +(defvar yas-wrap-around-region) +(defvar yas-also-auto-indent-first-line) +(defvar dap-auto-configure-mode) +(defvar dap-ui-menu-items) +(defvar company-minimum-prefix-length) + +(defconst lsp--message-type-face + `((1 . ,compilation-error-face) + (2 . ,compilation-warning-face) + (3 . ,compilation-message-face) + (4 . ,compilation-info-face))) + +(defconst lsp--errors + '((-32700 "Parse Error") + (-32600 "Invalid Request") + (-32601 "Method not Found") + (-32602 "Invalid Parameters") + (-32603 "Internal Error") + (-32099 "Server Start Error") + (-32000 "Server End Error") + (-32002 "Server Not Initialized") + (-32001 "Unknown Error Code") + (-32800 "Request Cancelled")) + "Alist of error codes to user friendly strings.") + +(defconst lsp--empty-ht (make-hash-table)) + +(eval-and-compile + (defun dash-expand:&lsp-wks (key source) + `(,(intern-soft (format "lsp--workspace-%s" (eval key))) ,source)) + + (defun dash-expand:&lsp-cln (key source) + `(,(intern-soft (format "lsp--client-%s" (eval key))) ,source))) + +(define-obsolete-variable-alias 'lsp-print-io 'lsp-log-io "lsp-mode 6.1") + +(defcustom lsp-log-io nil + "If non-nil, log all messages from the language server to a *lsp-log* buffer." + :group 'lsp-mode + :type 'boolean) + +(defcustom lsp-log-max message-log-max + "Maximum number of lines to keep in the log buffer. +If nil, disable message logging. If t, log messages but don’t truncate +the buffer when it becomes large." + :group 'lsp-mode + :type '(choice (const :tag "Disable" nil) + (integer :tag "lines") + (const :tag "Unlimited" t)) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-io-messages-max t + "Maximum number of messages that can be locked in a `lsp-io' buffer." + :group 'lsp-mode + :type '(choice (const :tag "Unlimited" t) + (integer :tag "Messages")) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-keep-workspace-alive t + "If non nil keep workspace alive when the last workspace buffer is closed." + :group 'lsp-mode + :type 'boolean) + +(defcustom lsp-enable-snippet t + "Enable/disable snippet completion support." + :group 'lsp-completion + :type 'boolean) + +(defcustom lsp-enable-folding t + "Enable/disable code folding support." + :group 'lsp-mode + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(define-obsolete-variable-alias 'lsp-enable-semantic-highlighting 'lsp-semantic-tokens-enable "lsp-mode 7.1") + +(defcustom lsp-semantic-tokens-enable nil + "Enable/disable support for semantic tokens. +As defined by the Language Server Protocol 3.16." + :group 'lsp-semantic-tokens + :type 'boolean) + +(defcustom lsp-folding-range-limit nil + "The maximum number of folding ranges to receive from the language server." + :group 'lsp-mode + :type '(choice (const :tag "No limit." nil) + (integer :tag "Number of lines.")) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-folding-line-folding-only nil + "If non-nil, only fold complete lines." + :group 'lsp-mode + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-client-packages + '(ccls lsp-actionscript lsp-ada lsp-angular lsp-bash lsp-beancount lsp-clangd lsp-clojure lsp-cmake + lsp-crystal lsp-csharp lsp-css lsp-d lsp-dart lsp-dhall lsp-dockerfile lsp-elm + lsp-elixir lsp-erlang lsp-eslint lsp-fortran lsp-fsharp lsp-gdscript lsp-go + lsp-hack lsp-grammarly lsp-groovy lsp-haskell lsp-haxe lsp-java lsp-javascript lsp-json + lsp-kotlin lsp-ltex lsp-lua lsp-markdown lsp-nim lsp-nix lsp-metals lsp-ocaml lsp-perl lsp-php lsp-pwsh + lsp-pyls lsp-pylsp lsp-python-ms lsp-purescript lsp-r lsp-rf lsp-rust lsp-solargraph lsp-sorbet + lsp-tex lsp-terraform lsp-v lsp-vala lsp-verilog lsp-vetur lsp-vhdl lsp-vimscript lsp-xml + lsp-yaml lsp-sqls lsp-svelte lsp-steep lsp-zig) + "List of the clients to be automatically required." + :group 'lsp-mode + :type '(repeat symbol)) + +(defcustom lsp-progress-via-spinner t + "If non-nil, display LSP $/progress reports via a spinner in the modeline." + :group 'lsp-mode + :type 'boolean) + +(defvar-local lsp--cur-workspace nil) + +(defvar-local lsp--cur-version 0) +(defvar-local lsp--virtual-buffer-connections nil) +(defvar-local lsp--virtual-buffer nil) +(defvar lsp--virtual-buffer-mappings (ht)) + +(defvar lsp--uri-file-prefix (pcase system-type + (`windows-nt "file:///") + (_ "file://")) + "Prefix for a file-uri.") + +(defvar-local lsp-buffer-uri nil + "If set, return it instead of calculating it using `buffer-file-name'.") + +(define-error 'lsp-error "Unknown lsp-mode error") +(define-error 'lsp-empty-response-error + "Empty response from the language server" 'lsp-error) +(define-error 'lsp-timed-out-error + "Timed out while waiting for a response from the language server" 'lsp-error) +(define-error 'lsp-capability-not-supported + "Capability not supported by the language server" 'lsp-error) +(define-error 'lsp-file-scheme-not-supported + "Unsupported file scheme" 'lsp-error) +(define-error 'lsp-client-already-exists-error + "A client with this server-id already exists" 'lsp-error) +(define-error 'lsp-no-code-actions + "No code actions" 'lsp-error) + +(defcustom lsp-auto-guess-root nil + "Automatically guess the project root using projectile/project. +Do *not* use this setting unless you are familiar with `lsp-mode' +internals and you are sure that all of your projects are +following `projectile'/`project.el' conventions." + :group 'lsp-mode + :type 'boolean) + +(defcustom lsp-restart 'interactive + "Defines how server-exited events must be handled." + :group 'lsp-mode + :type '(choice (const interactive) + (const auto-restart) + (const ignore))) + +(defcustom lsp-session-file (expand-file-name (locate-user-emacs-file ".lsp-session-v1")) + "File where session information is stored." + :group 'lsp-mode + :type 'file) + +(defcustom lsp-auto-configure t + "Auto configure `lsp-mode' main features. +When set to t `lsp-mode' will auto-configure completion, +code-actions, breadcrumb, `flycheck', `flymake', `imenu', symbol highlighting, +lenses, links, and so on. + +For finer granularity you may use `lsp-enable-*' properties." + :group 'lsp-mode + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-disabled-clients nil + "A list of disabled/blacklisted clients. +Each entry in the list can be either: +a symbol, the server-id for the LSP client, or +a cons pair (MAJOR-MODE . CLIENTS), where MAJOR-MODE is the major-mode, +and CLIENTS is either a client or a list of clients. + +This option can also be used as a file- or directory-local variable to +disable a language server for individual files or directories/projects +respectively." + :group 'lsp-mode + :type '(repeat (symbol)) + :safe 'listp + :package-version '(lsp-mode . "6.1")) + +(defvar lsp-clients (make-hash-table :test 'eql) + "Hash table server-id -> client. +It contains all of the clients that are currently registered.") + +(defvar lsp-enabled-clients nil + "List of clients allowed to be used for projects. +When nil, all registered clients are considered candidates.") + +(defvar lsp-last-id 0 + "Last request id.") + +(defcustom lsp-before-initialize-hook nil + "List of functions to be called before a Language Server has been initialized +for a new workspace." + :type 'hook + :group 'lsp-mode) + +(defcustom lsp-after-initialize-hook nil + "List of functions to be called after a Language Server has been initialized +for a new workspace." + :type 'hook + :group 'lsp-mode) + +(defcustom lsp-before-open-hook nil + "List of functions to be called before a new file with LSP support is opened." + :type 'hook + :group 'lsp-mode) + +(defcustom lsp-after-open-hook nil + "List of functions to be called after a new file with LSP support is opened." + :type 'hook + :group 'lsp-mode) + +(defcustom lsp-enable-file-watchers t + "If non-nil lsp-mode will watch the files in the workspace if +the server has requested that." + :type 'boolean + :group 'lsp-mode + :package-version '(lsp-mode . "6.1")) +;;;###autoload(put 'lsp-enable-file-watchers 'safe-local-variable #'booleanp) + +(define-obsolete-variable-alias 'lsp-file-watch-ignored 'lsp-file-watch-ignored-directories "7.1.0") + +(defcustom lsp-file-watch-ignored-directories + '(; SCM tools + "[/\\\\]\\.git\\'" + "[/\\\\]\\.github\\'" + "[/\\\\]\\.circleci\\'" + "[/\\\\]\\.hg\\'" + "[/\\\\]\\.bzr\\'" + "[/\\\\]_darcs\\'" + "[/\\\\]\\.svn\\'" + "[/\\\\]_FOSSIL_\\'" + ;; IDE or build tools + "[/\\\\]\\.idea\\'" + "[/\\\\]\\.ensime_cache\\'" + "[/\\\\]\\.eunit\\'" + "[/\\\\]node_modules" + "[/\\\\]\\.yarn\\'" + "[/\\\\]\\.fslckout\\'" + "[/\\\\]\\.tox\\'" + "[/\\\\]dist\\'" + "[/\\\\]dist-newstyle\\'" + "[/\\\\]\\.stack-work\\'" + "[/\\\\]\\.bloop\\'" + "[/\\\\]\\.metals\\'" + "[/\\\\]target\\'" + "[/\\\\]\\.ccls-cache\\'" + "[/\\\\]\\.vscode\\'" + ;; Autotools output + "[/\\\\]\\.deps\\'" + "[/\\\\]build-aux\\'" + "[/\\\\]autom4te.cache\\'" + "[/\\\\]\\.reference\\'" + ;; Clojure + "[/\\\\]\\.lsp\\'" + "[/\\\\]\\.clj-kondo\\'" + "[/\\\\]\\.shadow-cljs\\'" + "[/\\\\]\\.babel_cache\\'" + "[/\\\\]\\.cpcache\\'" + ;; .Net Core build-output + "[/\\\\]bin/Debug\\'" + "[/\\\\]obj\\'" + ;; OCaml and Dune + "[/\\\\]_opam\\'" + "[/\\\\]_build\\'" + ;; nix-direnv + "[/\\\\]\\.direnv\\'") + "List of regexps matching directory paths which won't be monitored when +creating file watches. Customization of this variable is only honored at +the global level or at a root of an lsp workspace." + :group 'lsp-mode + :type '(repeat string) + :package-version '(lsp-mode . "7.1.0")) + +(define-obsolete-function-alias 'lsp-file-watch-ignored 'lsp-file-watch-ignored-directories "7.0.1") + +(defun lsp-file-watch-ignored-directories () + lsp-file-watch-ignored-directories) + +;; Allow lsp-file-watch-ignored-directories as a file or directory-local variable +(put 'lsp-file-watch-ignored-directories 'safe-local-variable 'lsp--string-listp) + +(defcustom lsp-file-watch-ignored-files + '( + ;; Flycheck tempfiles + "[/\\\\]flycheck_[^/\\\\]+\\'" + ;; lockfiles + "[/\\\\]\\.#[^/\\\\]+\\'" + ;; backup files + "[/\\\\][^/\\\\]+~\\'" ) + "List of regexps matching files for which change events will +not be sent to the server. + +This setting has no impact on whether a file-watch is created for +a directory; it merely prevents notifications pertaining to +matched files from being sent to the server. To prevent a +file-watch from being created for a directory, customize +`lsp-file-watch-ignored-directories' + +Customization of this variable is only honored at the global +level or at a root of an lsp workspace." + :group 'lsp-mode + :type '(repeat string) + :package-version '(lsp-mode . "7.1.0")) + +;; Allow lsp-file-watch-ignored-files as a file or directory-local variable +(put 'lsp-file-watch-ignored-files 'safe-local-variable 'lsp--string-listp) + +(defcustom lsp-after-uninitialized-functions nil + "List of functions to be called after a Language Server has been uninitialized." + :type 'hook + :group 'lsp-mode + :package-version '(lsp-mode . "6.3")) + +(defconst lsp--sync-none 0) +(defconst lsp--sync-full 1) +(defconst lsp--sync-incremental 2) + +(defcustom lsp-debounce-full-sync-notifications t + "If non-nil debounce full sync events. +This flag affects only servers which do not support incremental updates." + :type 'boolean + :group 'lsp-mode + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-debounce-full-sync-notifications-interval 1.0 + "Time to wait before sending full sync synchronization after buffer modification." + :type 'float + :group 'lsp-mode + :package-version '(lsp-mode . "6.1")) + +(defvar lsp--stderr-index 0) + +(defvar lsp--delayed-requests nil) +(defvar lsp--delay-timer nil) + +(defcustom lsp-document-sync-method nil + "How to sync the document with the language server." + :type '(choice (const :tag "Documents should not be synced at all." nil) + (const :tag "Documents are synced by always sending the full content of the document." lsp--sync-full) + (const :tag "Documents are synced by always sending incremental changes to the document." lsp--sync-incremental) + (const :tag "Use the method recommended by the language server." nil)) + :group 'lsp-mode) + +(defcustom lsp-auto-execute-action t + "Auto-execute single action." + :type 'boolean + :group 'lsp-mode) + +(defcustom lsp-enable-links t + "If non-nil, all references to links in a file will be made clickable, if +supported by the language server." + :type 'boolean + :group 'lsp-mode + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-enable-imenu t + "If non-nil, automatically enable `imenu' integration when server provides +`textDocument/documentSymbol'." + :type 'boolean + :group 'lsp-mode + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-enable-dap-auto-configure t + "If non-nil, enable `dap-auto-configure-mode`." + :type 'boolean + :group 'lsp-mode + :package-version '(lsp-mode . "7.0")) + +(defcustom lsp-eldoc-enable-hover t + "If non-nil, `eldoc' will display hover info when it is present." + :type 'boolean + :group 'lsp-mode) + +(defcustom lsp-eldoc-render-all nil + "Display all of the info returned by document/onHover. +If this is set to nil, `eldoc' will show only the symbol information." + :type 'boolean + :group 'lsp-mode) + +(define-obsolete-variable-alias 'lsp-enable-completion-at-point + 'lsp-completion-enable "lsp-mode 7.0.1") + +(defcustom lsp-completion-enable t + "Enable `completion-at-point' integration." + :type 'boolean + :group 'lsp-completion) + +(defcustom lsp-enable-symbol-highlighting t + "Highlight references of the symbol at point." + :type 'boolean + :group 'lsp-mode) + +(defcustom lsp-enable-xref t + "Enable xref integration." + :type 'boolean + :group 'lsp-mode) + +(defcustom lsp-enable-indentation t + "Indent regions using the file formatting functionality provided by the +language server." + :type 'boolean + :group 'lsp-mode) + +(defcustom lsp-enable-on-type-formatting t + "Enable `textDocument/onTypeFormatting' integration." + :type 'boolean + :group 'lsp-mode) + +(defcustom lsp-enable-text-document-color t + "Enable `textDocument/documentColor' integration." + :type 'boolean + :group 'lsp-mode) + +(defcustom lsp-before-save-edits t + "If non-nil, `lsp-mode' will apply edits suggested by the language server +before saving a document." + :type 'boolean + :group 'lsp-mode) + +(defcustom lsp-after-apply-edits-hook nil + "Hooks to run when text edit is applied. +It contains the operation source." + :type 'hook + :group 'lsp-mode + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-modeline-code-actions-enable t + "Whether to show code actions on modeline." + :type 'boolean + :group 'lsp-modeline) + +(defcustom lsp-modeline-diagnostics-enable t + "Whether to show diagnostics on modeline." + :type 'boolean + :group 'lsp-modeline) + +(defcustom lsp-modeline-workspace-status-enable t + "Whether to show workspace status on modeline." + :type 'boolean + :group 'lsp-modeline + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-headerline-breadcrumb-enable t + "Whether to enable breadcrumb on headerline." + :type 'boolean + :group 'lsp-headerline) + +(defcustom lsp-configure-hook nil + "Hooks to run when `lsp-configure-buffer' is called." + :type 'hook + :group 'lsp-mode) + +(defcustom lsp-unconfigure-hook nil + "Hooks to run when `lsp-unconfig-buffer' is called." + :type 'hook + :group 'lsp-mode) + +(defcustom lsp-after-diagnostics-hook nil + "Hooks to run after diagnostics are received. +Note: it runs only if the receiving buffer is open. Use +`lsp-diagnostics-updated-hook'if you want to be notified when +diagnostics have changed." + :type 'hook + :group 'lsp-mode) + +(define-obsolete-variable-alias 'lsp-after-diagnostics-hook + 'lsp-diagnostics-updated-hook "lsp-mode 6.4") + +(defcustom lsp-diagnostics-updated-hook nil + "Hooks to run after diagnostics are received." + :type 'hook + :group 'lsp-mode) + +(define-obsolete-variable-alias 'lsp-workspace-folders-changed-hook + 'lsp-workspace-folders-changed-functions "lsp-mode 6.3") + +(defcustom lsp-workspace-folders-changed-functions nil + "Hooks to run after the folders has changed. +The hook will receive two parameters list of added and removed folders." + :type 'hook + :group 'lsp-mode) + +(defcustom lsp-eldoc-hook '(lsp-hover) + "Hooks to run for eldoc." + :type 'hook + :group 'lsp-mode) + +(defcustom lsp-before-apply-edits-hook nil + "Hooks to run before applying edits." + :type 'hook + :group 'lsp-mode) + +(defgroup lsp-imenu nil + "LSP Imenu." + :group 'lsp-mode + :tag "LSP Imenu") + +(defcustom lsp-imenu-show-container-name t + "Display the symbol's container name in an imenu entry." + :type 'boolean + :group 'lsp-imenu) + +(defcustom lsp-imenu-container-name-separator "/" + "Separator string to use to separate the container name from the symbol while +displaying imenu entries." + :type 'string + :group 'lsp-imenu) + +(defcustom lsp-imenu-sort-methods '(kind name) + "How to sort the imenu items. + +The value is a list of `kind' `name' or `position'. Priorities +are determined by the index of the element." + :type '(repeat (choice (const name) + (const position) + (const kind))) + :group 'lsp-imenu) + +(defcustom lsp-imenu-index-symbol-kinds nil + "Which symbol kinds to show in imenu." + :type '(repeat (choice (const :tag "Miscellaneous" nil) + (const :tag "File" File) + (const :tag "Module" Module) + (const :tag "Namespace" Namespace) + (const :tag "Package" Package) + (const :tag "Class" Class) + (const :tag "Method" Method) + (const :tag "Property" Property) + (const :tag "Field" Field) + (const :tag "Constructor" Constuctor) + (const :tag "Enum" Enum) + (const :tag "Interface" Interface) + (const :tag "Function" Function) + (const :tag "Variable" Variable) + (const :tag "Constant" Constant) + (const :tag "String" String) + (const :tag "Number" Number) + (const :tag "Boolean" Boolean) + (const :tag "Array" Array) + (const :tag "Object" Object) + (const :tag "Key" Key) + (const :tag "Null" Null) + (const :tag "Enum Member" EnumMember) + (const :tag "Struct" Struct) + (const :tag "Event" Event) + (const :tag "Operator" Operator) + (const :tag "Type Parameter" TypeParameter))) + :group 'lsp-imenu) + +;; vibhavp: Should we use a lower value (5)? +(defcustom lsp-response-timeout 10 + "Number of seconds to wait for a response from the language server before +timing out." + :type 'number + :group 'lsp-mode) + +(defcustom lsp-tcp-connection-timeout 2 + "The timeout for tcp connection in seconds." + :type 'number + :group 'lsp-mode + :package-version '(lsp-mode . "6.2")) + +(defconst lsp--imenu-compare-function-alist + (list (cons 'name #'lsp--imenu-compare-name) + (cons 'kind #'lsp--imenu-compare-kind) + (cons 'position #'lsp--imenu-compare-line-col)) + "An alist of (METHOD . FUNCTION). +METHOD is one of the symbols accepted by +`lsp-imenu-sort-methods'. + +FUNCTION takes two hash tables representing DocumentSymbol. It +returns a negative number, 0, or a positive number indicating +whether the first parameter is less than, equal to, or greater +than the second parameter.") + +(defcustom lsp-diagnostic-clean-after-change nil + "When non-nil, clean the diagnostics on change. + +Note that when that setting is nil, `lsp-mode' will show stale +diagnostics until server publishes the new set of diagnostics" + :type 'boolean + :group 'lsp-diagnostics + :package-version '(lsp-mode . "7.0.1")) + +(defcustom lsp-server-trace nil + "Request tracing on the server side. +The actual trace output at each level depends on the language server in use. +Changes take effect only when a new session is started." + :type '(choice (const :tag "Disabled" "off") + (const :tag "Messages only" "messages") + (const :tag "Verbose" "verbose") + (const :tag "Default (disabled)" nil)) + :group 'lsp-mode + :package-version '(lsp-mode . "6.1")) + +(defvar lsp-language-id-configuration '((".*\\.vue$" . "vue") + (".*\\.tsx$" . "typescriptreact") + (".*\\.ts$" . "typescript") + (".*\\.jsx$" . "javascriptreact") + (".*\\.js$" . "javascript") + (".*\\.xml$" . "xml") + (".*\\.hx$" . "haxe") + (".*\\.lua$" . "lua") + (".*\\.sql$" . "sql") + (".*\\.html$" . "html") + (".*\\.css" . "css") + (".*/settings.json$" . "jsonc") + (".*\\.json$" . "json") + (".*\\.jsonc$" . "jsonc") + (".*\\.php$" . "php") + (".*\\.svelte$" . "svelte") + (ada-mode . "ada") + (nxml-mode . "xml") + (sql-mode . "sql") + (vimrc-mode . "vim") + (sh-mode . "shellscript") + (scala-mode . "scala") + (julia-mode . "julia") + (clojure-mode . "clojure") + (clojurec-mode . "clojure") + (clojurescript-mode . "clojurescript") + (java-mode . "java") + (jdee-mode . "java") + (groovy-mode . "groovy") + (python-mode . "python") + (cython-mode . "python") + (lsp--render-markdown . "markdown") + (rust-mode . "rust") + (rustic-mode . "rust") + (kotlin-mode . "kotlin") + (css-mode . "css") + (less-mode . "less") + (less-css-mode . "less") + (lua-mode . "lua") + (sass-mode . "sass") + (scss-mode . "scss") + (xml-mode . "xml") + (c-mode . "c") + (c++-mode . "cpp") + (objc-mode . "objective-c") + (html-mode . "html") + (sgml-mode . "html") + (mhtml-mode . "html") + (go-dot-mod-mode . "go.mod") + (go-mode . "go") + (haskell-mode . "haskell") + (hack-mode . "hack") + (php-mode . "php") + (powershell-mode . "powershell") + (powershell-mode . "PowerShell") + (json-mode . "json") + (jsonc-mode . "jsonc") + (rjsx-mode . "javascript") + (js2-mode . "javascript") + (js-mode . "javascript") + (typescript-mode . "typescript") + (fsharp-mode . "fsharp") + (reason-mode . "reason") + (caml-mode . "ocaml") + (tuareg-mode . "ocaml") + (swift-mode . "swift") + (elixir-mode . "elixir") + (conf-javaprop-mode . "spring-boot-properties") + (yaml-mode . "spring-boot-properties-yaml") + (ruby-mode . "ruby") + (enh-ruby-mode . "ruby") + (fortran-mode . "fortran") + (f90-mode . "fortran") + (elm-mode . "elm") + (dart-mode . "dart") + (erlang-mode . "erlang") + (dockerfile-mode . "dockerfile") + (csharp-mode . "csharp") + (csharp-tree-sitter-mode . "csharp") + (plain-tex-mode . "plaintex") + (latex-mode . "latex") + (v-mode . "v") + (vhdl-mode . "vhdl") + (verilog-mode . "verilog") + (terraform-mode . "terraform") + (ess-julia-mode . "julia") + (ess-r-mode . "r") + (crystal-mode . "crystal") + (nim-mode . "nim") + (dhall-mode . "dhall") + (cmake-mode . "cmake") + (purescript-mode . "purescript") + (gdscript-mode . "gdscript") + (perl-mode . "perl") + (cperl-mode . "perl") + (robot-mode . "robot") + (racket-mode . "racket") + (nix-mode . "nix") + (prolog-mode . "prolog") + (vala-mode . "vala") + (actionscript-mode . "actionscript") + (d-mode . "d") + (zig-mode . "zig") + (text-mode . "plaintext") + (markdown-mode . "markdown") + (beancount-mode . "beancount")) + "Language id configuration.") + +(defvar lsp--last-active-workspaces nil + "Keep track of last active workspace. +We want to try the last workspace first when jumping into a library +directory") + +(defvar lsp-method-requirements + '(("textDocument/callHierarchy" :capability :callHierarchyProvider) + ("textDocument/codeAction" :capability :codeActionProvider) + ("codeAction/resolve" + :check-command (lambda (workspace) + (with-lsp-workspace workspace + (lsp:code-action-options-resolve-provider? + (or (lsp--capability :codeActionProvider) + (when-let ((maybe-capability (lsp--registered-capability "textDocument/codeAction")) + (capability-options (lsp--registered-capability-options maybe-capability))) + capability-options)))))) + ("textDocument/codeLens" :capability :codeLensProvider) + ("textDocument/completion" :capability :completionProvider) + ("completionItem/resolve" + :check-command (lambda (wk) + (with-lsp-workspace wk + (lsp:completion-options-resolve-provider? + (lsp--capability :completionProvider))))) + ("textDocument/declaration" :capability :declarationProvider) + ("textDocument/definition" :capability :definitionProvider) + ("textDocument/documentColor" :capability :colorProvider) + ("textDocument/documentLink" :capability :documentLinkProvider) + ("textDocument/documentHighlight" :capability :documentHighlightProvider) + ("textDocument/documentSymbol" :capability :documentSymbolProvider) + ("textDocument/foldingRange" :capability :foldingRangeProvider) + ("textDocument/formatting" :capability :documentFormattingProvider) + ("textDocument/hover" :capability :hoverProvider) + ("textDocument/implementation" :capability :implementationProvider) + ("textDocument/onTypeFormatting" :capability :documentOnTypeFormattingProvider) + ("textDocument/prepareRename" + :check-command (lambda (workspace) + (with-lsp-workspace workspace + (lsp:rename-options-prepare-provider? + (or (lsp--capability :renameProvider) + (when-let ((maybe-capability (lsp--registered-capability "textDocument/rename"))) + (lsp--registered-capability-options maybe-capability))))))) + ("textDocument/rangeFormatting" :capability :documentRangeFormattingProvider) + ("textDocument/references" :capability :referencesProvider) + ("textDocument/rename" :capability :renameProvider) + ("textDocument/selectionRange" :capability :selectionRangeProvider) + ("textDocument/semanticTokens" :capability :semanticTokensProvider) + ("textDocument/semanticTokensFull" + :check-command (lambda (workspace) + (with-lsp-workspace workspace + (lsp-get (lsp--capability :semanticTokensProvider) :full)))) + ("textDocument/semanticTokensFull/Delta" + :check-command (lambda (workspace) + (with-lsp-workspace workspace + (let ((capFull (lsp-get (lsp--capability :semanticTokensProvider) :full))) + (and (not (booleanp capFull)) (lsp-get capFull :delta)))))) + ("textDocument/semanticTokensRangeProvider" + :check-command (lambda (workspace) + (with-lsp-workspace workspace + (lsp-get (lsp--capability :semanticTokensProvider) :range)))) + ("textDocument/signatureHelp" :capability :signatureHelpProvider) + ("textDocument/typeDefinition" :capability :typeDefinitionProvider) + ("workspace/executeCommand" :capability :executeCommandProvider) + ("workspace/symbol" :capability :workspaceSymbolProvider)) + + "Map methods to requirements. +It is used by request-sending functions to determine which server +must be used for handling a particular message.") + +(defconst lsp--file-change-type + `((created . 1) + (changed . 2) + (deleted . 3))) + +(defconst lsp--watch-kind + `((create . 1) + (change . 2) + (delete . 4))) + +(defvar lsp-window-body-width 40 + "Window body width when rendering doc.") + +(defface lsp-face-highlight-textual + '((t :inherit highlight)) + "Face used for textual occurrences of symbols." + :group 'lsp-mode) + +(defface lsp-face-highlight-read + '((t :inherit highlight :underline t)) + "Face used for highlighting symbols being read." + :group 'lsp-mode) + +(defface lsp-face-highlight-write + '((t :inherit highlight :weight bold)) + "Face used for highlighting symbols being written to." + :group 'lsp-mode) + +(define-obsolete-variable-alias 'lsp-lens-auto-enable + 'lsp-lens-enable "lsp-mode 7.0.1") + +(defcustom lsp-lens-enable nil + "Auto enable lenses if server supports." + :group 'lsp-lens + :type 'boolean + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-symbol-highlighting-skip-current nil + "If non-nil skip current symbol when setting symbol highlights." + :group 'lsp-mode + :type 'boolean) + +(defcustom lsp-file-watch-threshold 1000 + "Show warning if the files to watch are more than. +Set to nil to disable the warning." + :type 'number + :group 'lsp-mode) +;;;###autoload(put 'lsp-file-watch-threshold 'safe-local-variable (lambda (i) (or (numberp i) (not i)))) + +(defvar lsp-custom-markup-modes + '((rust-mode "no_run" "rust,no_run" "rust,ignore" "rust,should_panic")) + "Mode to uses with markdown code blocks. +They are added to `markdown-code-lang-modes'") + +(defcustom lsp-signature-render-documentation t + "Display signature documentation in `eldoc'." + :type 'boolean + :group 'lsp-mode + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-signature-auto-activate '(:on-trigger-char :on-server-request) + "Auto activate signature conditions." + :type '(repeat (choice (const :tag "On trigger chars pressed." :on-trigger-char) + (const :tag "After selected completion." :after-completion) + (const :tag "When the server has sent show signature help." :on-server-request))) + :group 'lsp-mode + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-signature-doc-lines 20 + "If number, limit the number of lines to show in the docs." + :type 'number + :group 'lsp-mode + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-signature-function 'lsp-lv-message + "The function used for displaying signature info. +It will be called with one param - the signature info. When +called with nil the signature info must be cleared." + :type 'function + :group 'lsp-mode + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-keymap-prefix "s-l" + "LSP-mode keymap prefix." + :group 'lsp-mode + :type 'string + :package-version '(lsp-mode . "6.3")) + +(defvar-local lsp--buffer-workspaces () + "List of the buffer workspaces.") + +(defvar lsp--session nil + "Contain the `lsp-session' for the current Emacs instance.") + +(defvar lsp--tcp-port 10000) + +(defvar lsp--client-packages-required nil + "If nil, `lsp-client-packages' are yet to be required.") + +(defvar lsp--tcp-server-port 0 + "The server socket which is opened when using `lsp-tcp-server' (a server +socket is opened in Emacs and the language server connects to it). The +default value of 0 ensures that a random high port is used. Set it to a positive +integer to use a specific port.") + +(defvar lsp--tcp-server-wait-seconds 10 + "Wait this amount of time for the client to connect to our server socket +when using `lsp-tcp-server'.") + +(defvar-local lsp--document-symbols nil + "The latest document symbols.") + +(defvar-local lsp--document-selection-range-cache nil + "The document selection cache.") + +(defvar-local lsp--document-symbols-request-async nil + "If non-nil, request document symbols asynchronously.") + +(defvar-local lsp--document-symbols-tick -1 + "The value of `buffer-chars-modified-tick' when document + symbols were last retrieved.") + +(defvar-local lsp--have-document-highlights nil + "Set to `t' on symbol highlighting, cleared on +`lsp--cleanup-highlights-if-needed'. Checking a separately +defined flag is substantially faster than unconditionally +calling `remove-overlays'.") + +;; Buffer local variable for storing number of lines. +(defvar lsp--log-lines) + +(defvar-local lsp--eldoc-saved-message nil) + +(defvar lsp--on-change-timer nil) +(defvar lsp--on-idle-timer nil) + +(defvar-local lsp--signature-last nil) +(defvar-local lsp--signature-last-index nil) +(defvar lsp--signature-last-buffer nil) + +(defvar-local lsp--virtual-buffer-point-max nil) + +(cl-defgeneric lsp-execute-command (server command arguments) + "Ask SERVER to execute COMMAND with ARGUMENTS.") + +(defun lsp-elt (sequence n) + "Return Nth element of SEQUENCE or nil if N is out of range." + (cond + ((listp sequence) (elt sequence n)) + ((arrayp sequence) + (and (> (length sequence) n) (aref sequence n))) + (t (and (> (length sequence) n) (elt sequence n))))) + +;; define seq-first and seq-rest for older emacs +(defun lsp-seq-first (sequence) + "Return the first element of SEQUENCE." + (lsp-elt sequence 0)) + +(defun lsp-seq-rest (sequence) + "Return a sequence of the elements of SEQUENCE except the first one." + (seq-drop sequence 1)) + +(defun lsp--string-listp (sequence) + "Return t if all elements of SEQUENCE are strings, else nil." + (not (seq-find (lambda (x) (not (stringp x))) sequence))) + +(defun lsp--string-vector-p (candidate) + "Returns true if CANDIDATE is a vector data structure and +every element of it is of type string, else nil." + (and + (vectorp candidate) + (seq-every-p #'stringp candidate))) + +(make-obsolete 'lsp--string-vector-p nil "lsp-mode 7.1") + +(defun lsp--editable-vector-match (widget value) + "Function for `lsp-editable-vector' :match." + ;; Value must be a list or a vector and all the members must match the type. + (and (or (listp value) (vectorp value)) + (length (cdr (lsp--editable-vector-match-inline widget value))))) + +(defun lsp--editable-vector-match-inline (widget value) + "Value for `lsp-editable-vector' :match-inline." + (let ((type (nth 0 (widget-get widget :args))) + (ok t) + found) + (while (and value ok) + (let ((answer (widget-match-inline type value))) + (if answer + (let ((head (if (vectorp answer) (aref answer 0) (car answer))) + (tail (if (vectorp answer) (seq-drop 1 answer) (cdr answer)))) + (setq found (append found head) + value tail)) + (setq ok nil)))) + (cons found value))) + +(defun lsp--editable-vector-value-to-external (_widget internal-value) + "Convert the internal list value to a vector." + (if (listp internal-value) + (apply 'vector internal-value) + internal-value)) + +(defun lsp--editable-vector-value-to-internal (_widget external-value) + "Convert the external vector value to a list." + (if (vectorp external-value) + (append external-value nil) + external-value)) + +(define-widget 'lsp--editable-vector 'editable-list + "A subclass of `editable-list' that accepts and returns a +vector instead of a list." + :value-to-external 'lsp--editable-vector-value-to-external + :value-to-internal 'lsp--editable-vector-value-to-internal + :match 'lsp--editable-vector-match + :match-inline 'lsp--editable-vector-match-inline) + +(define-widget 'lsp-repeatable-vector 'lsp--editable-vector + "A variable length homogeneous vector." + :tag "Repeat" + :format "%{%t%}:\n%v%i\n") + +(define-widget 'lsp-string-vector 'lazy + "A vector of zero or more elements, every element of which is a string. +Appropriate for any language-specific `defcustom' that needs to +serialize as a JSON array of strings. + +Deprecated. Use `lsp-repeatable-vector' instead. " + :offset 4 + :tag "Vector" + :type '(lsp-repeatable-vector string)) + +(make-obsolete 'lsp-string-vector nil "lsp-mode 7.1") + +(defvar lsp--show-message t + "If non-nil, show debug message from `lsp-mode'.") + +(defun lsp--message (format &rest args) + "Wrapper for `message' + +We `inhibit-message' the message when the cursor is in the +minibuffer and when emacs version is before emacs 27 due to the +fact that we often use `lsp--info', `lsp--warn' and `lsp--error' +in async context and the call to these function is removing the +minibuffer prompt. The issue with async messages is already fixed +in emacs 27. + +See #2049" + (when lsp--show-message + (let ((inhibit-message (and (minibufferp) + (version< emacs-version "27.0")))) + (apply #'message format args)))) + +(defun lsp--info (format &rest args) + "Display lsp info message with FORMAT with ARGS." + (lsp--message "%s :: %s" (propertize "LSP" 'face 'success) (apply #'format format args))) + +(defun lsp--warn (format &rest args) + "Display lsp warn message with FORMAT with ARGS." + (lsp--message "%s :: %s" (propertize "LSP" 'face 'warning) (apply #'format format args))) + +(defun lsp--error (format &rest args) + "Display lsp error message with FORMAT with ARGS." + (lsp--message "%s :: %s" (propertize "LSP" 'face 'error) (apply #'format format args))) + +(defun lsp--eldoc-message (&optional msg) + "Show MSG in eldoc." + (setq lsp--eldoc-saved-message msg) + (run-with-idle-timer 0 nil (lambda () + ;; XXX: new eldoc in Emacs 28 + ;; recommends running the hook variable + ;; `eldoc-documentation-functions' + ;; instead of using eldoc-message + (with-no-warnings + (eldoc-message msg))))) + +(defun lsp-log (format &rest args) + "Log message to the ’*lsp-log*’ buffer. + +FORMAT and ARGS i the same as for `message'." + (when lsp-log-max + (let ((log-buffer (get-buffer "*lsp-log*")) + (inhibit-read-only t)) + (unless log-buffer + (setq log-buffer (get-buffer-create "*lsp-log*")) + (with-current-buffer log-buffer + (buffer-disable-undo) + (view-mode 1) + (set (make-local-variable 'lsp--log-lines) 0))) + (with-current-buffer log-buffer + (save-excursion + (let* ((message (apply 'format format args)) + ;; Count newlines in message. + (newlines (1+ (cl-loop with start = 0 + for count from 0 + while (string-match "\n" message start) + do (setq start (match-end 0)) + finally return count)))) + (goto-char (point-max)) + + ;; in case the buffer is not empty insert before last \n to preserve + ;; the point position(in case it is in the end) + (if (eq (point) (point-min)) + (progn + (insert "\n") + (backward-char)) + (backward-char) + (insert "\n")) + (insert message) + + (setq lsp--log-lines (+ lsp--log-lines newlines)) + + (when (and (integerp lsp-log-max) (> lsp--log-lines lsp-log-max)) + (let ((to-delete (- lsp--log-lines lsp-log-max))) + (goto-char (point-min)) + (forward-line to-delete) + (delete-region (point-min) (point)) + (setq lsp--log-lines lsp-log-max))))))))) + +(defalias 'lsp-message 'lsp-log) + +(defalias 'lsp-ht 'ht) + +(defalias 'lsp-file-local-name 'file-local-name) + +(defun lsp-f-canonical (file-name) + "Return the canonical FILE-NAME, without a trailing slash." + (directory-file-name (expand-file-name file-name))) + +(defalias 'lsp-canonical-file-name 'lsp-f-canonical) + +(defun lsp-f-same? (path-a path-b) + "Return t if PATH-A and PATH-B are references to the same file. +Symlinks are not followed." + (when (and (f-exists? path-a) + (f-exists? path-b)) + (equal + (lsp-f-canonical (directory-file-name (f-expand path-a))) + (lsp-f-canonical (directory-file-name (f-expand path-b)))))) + +(defun lsp-f-parent (path) + "Return the parent directory to PATH. +Symlinks are not followed." + (let ((parent (file-name-directory + (directory-file-name (f-expand path default-directory))))) + (unless (lsp-f-same? path parent) + (if (f-relative? path) + (f-relative parent) + (directory-file-name parent))))) + +(defun lsp-f-ancestor-of? (path-a path-b) + "Return t if PATH-A is an ancestor of PATH-B. +Symlinks are not followed." + (unless (lsp-f-same? path-a path-b) + (s-prefix? (concat (lsp-f-canonical path-a) (f-path-separator)) + (lsp-f-canonical path-b)))) + +(defun lsp--merge-results (results method) + "Merge RESULTS by filtering the empty hash-tables and merging +the lists according to METHOD." + (pcase (--map (if (vectorp it) + (append it nil) it) + (-filter #'identity results)) + (`() ()) + ;; only one result - simply return it + (`(,fst) fst) + ;; multiple results merge it based on strategy + (results + (pcase method + ("textDocument/hover" (pcase (seq-filter + (-compose #'not #'lsp-empty?) + results) + (`(,hover) hover) + (hovers (lsp-make-hover + :contents + (-mapcat + (-lambda ((&Hover :contents)) + (if (and (sequencep contents) + (not (stringp contents))) + (append contents ()) + (list contents))) + hovers))))) + ("textDocument/completion" + (lsp-make-completion-list + :is-incomplete (seq-some + #'lsp:completion-list-is-incomplete + results) + :items (cl-mapcan (lambda (it) (append (if (lsp-completion-list? it) + (lsp:completion-list-items it) + it) + nil)) + results))) + ("completionItem/resolve" + (let ((item (cl-first results))) + (when-let ((details (seq-filter #'identity + (seq-map #'lsp:completion-item-detail? results)))) + (lsp:set-completion-item-detail? + item + (string-join details " "))) + (when-let ((docs (seq-filter #'identity + (seq-map #'lsp:completion-item-documentation? results)))) + (lsp:set-completion-item-documentation? + item + (lsp-make-markup-content + :kind (or (seq-some (lambda (it) + (when (equal (lsp:markup-content-kind it) + lsp/markup-kind-markdown) + lsp/markup-kind-markdown)) + docs) + lsp/markup-kind-plain-text) + :value (string-join (seq-map (lambda (doc) + (or (lsp:markup-content-value doc) + (and (stringp doc) doc))) + docs) + "\n")))) + (when-let ((edits (seq-filter #'identity + (seq-map #'lsp:completion-item-additional-text-edits? results)))) + (lsp:set-completion-item-additional-text-edits? + item + (cl-mapcan (lambda (it) (if (seqp it) it (list it))) edits))) + item)) + (_ (cl-mapcan (lambda (it) (if (seqp it) it (list it))) results)))))) + +(defun lsp--spinner-start () + "Start spinner indication." + (condition-case _err (spinner-start 'progress-bar-filled) (error))) + +(defun lsp--propertize (str type) + "Propertize STR as per TYPE." + (propertize str 'face (alist-get type lsp--message-type-face))) + +(defun lsp-workspaces () + "Return the lsp workspaces associated with the current project." + (if lsp--cur-workspace (list lsp--cur-workspace) lsp--buffer-workspaces)) + +(defun lsp--completing-read (prompt collection transform-fn &optional predicate + require-match initial-input + hist def inherit-input-method) + "Wrap `completing-read' to provide transformation function. + +TRANSFORM-FN will be used to transform each of the items before displaying. + +PROMPT COLLECTION PREDICATE REQUIRE-MATCH INITIAL-INPUT HIST DEF +INHERIT-INPUT-METHOD will be proxied to `completing-read' without changes." + (let* ((col (--map (cons (funcall transform-fn it) it) collection)) + (completion (completing-read prompt col + predicate require-match initial-input hist + def inherit-input-method))) + (cdr (assoc completion col)))) + +(defmacro lsp-with-current-buffer (buffer-id &rest body) + (declare (indent 1) (debug t)) + `(if-let ((wcb (plist-get ,buffer-id :with-current-buffer))) + (with-lsp-workspaces (plist-get ,buffer-id :workspaces) + (funcall wcb (lambda () ,@body))) + (with-current-buffer ,buffer-id + ,@body))) + +(defvar lsp--throw-on-input nil + "Make `lsp-*-while-no-input' throws `input' on interrupted.") + +(defmacro lsp--catch (tag bodyform &rest handlers) + "Catch TAG thrown in BODYFORM. +The return value from TAG will be handled in HANDLERS by `pcase'." + (declare (debug (form form &rest (pcase-PAT body))) (indent 2)) + (let ((re-sym (make-symbol "re"))) + `(let ((,re-sym (catch ,tag ,bodyform))) + (pcase ,re-sym + ,@handlers)))) + +(defmacro lsp--while-no-input (&rest body) + "Wrap BODY in `while-no-input' and respecting `non-essential'. +If `lsp--throw-on-input' is set, will throw if input is pending, else +return value of `body' or nil if interrupted." + (declare (debug t) (indent 0)) + `(if non-essential + (let ((res (while-no-input ,@body))) + (cond + ((and lsp--throw-on-input (equal res t)) + (throw 'input :interrupted)) + ((booleanp res) nil) + (t res))) + ,@body)) + +;; A ‘lsp--client’ object describes the client-side behavior of a language +;; server. It is used to start individual server processes, each of which is +;; represented by a ‘lsp--workspace’ object. Client objects are normally +;; created using ‘lsp-define-stdio-client’ or ‘lsp-define-tcp-client’. Each +;; workspace refers to exactly one client, but there can be multiple workspaces +;; for a single client. +(cl-defstruct lsp--client + ;; ‘language-id’ is a function that receives a buffer as a single argument + ;; and should return the language identifier for that buffer. See + ;; https://microsoft.github.io/language-server-protocol/specification#textdocumentitem + ;; for a list of language identifiers. Also consult the documentation for + ;; the language server represented by this client to find out what language + ;; identifiers it supports or expects. + (language-id nil) + + ;; ‘add-on?’ when set to t the server will be started no matter whether there + ;; is another server handling the same mode. + (add-on? nil) + ;; ‘new-connection’ is a function that should start a language server process + ;; and return a cons (COMMAND-PROCESS . COMMUNICATION-PROCESS). + ;; COMMAND-PROCESS must be a process object representing the server process + ;; just started. COMMUNICATION-PROCESS must be a process (including pipe and + ;; network processes) that ‘lsp-mode’ uses to communicate with the language + ;; server using the language server protocol. COMMAND-PROCESS and + ;; COMMUNICATION-PROCESS may be the same process; in that case + ;; ‘new-connection’ may also return that process as a single + ;; object. ‘new-connection’ is called with two arguments, FILTER and + ;; SENTINEL. FILTER should be used as process filter for + ;; COMMUNICATION-PROCESS, and SENTINEL should be used as process sentinel for + ;; COMMAND-PROCESS. + (new-connection nil) + + ;; ‘ignore-regexps’ is a list of regexps. When a data packet from the + ;; language server matches any of these regexps, it will be ignored. This is + ;; intended for dealing with language servers that output non-protocol data. + (ignore-regexps nil) + + ;; ‘ignore-messages’ is a list of regexps. When a message from the language + ;; server matches any of these regexps, it will be ignored. This is useful + ;; for filtering out unwanted messages; such as servers that send nonstandard + ;; message types, or extraneous log messages. + (ignore-messages nil) + + ;; ‘notification-handlers’ is a hash table mapping notification method names + ;; (strings) to functions handling the respective notifications. Upon + ;; receiving a notification, ‘lsp-mode’ will call the associated handler + ;; function passing two arguments, the ‘lsp--workspace’ object and the + ;; deserialized notification parameters. + (notification-handlers (make-hash-table :test 'equal)) + + ;; ‘request-handlers’ is a hash table mapping request method names + ;; (strings) to functions handling the respective notifications. Upon + ;; receiving a request, ‘lsp-mode’ will call the associated handler function + ;; passing two arguments, the ‘lsp--workspace’ object and the deserialized + ;; request parameters. + (request-handlers (make-hash-table :test 'equal)) + + ;; ‘response-handlers’ is a hash table mapping integral JSON-RPC request + ;; identifiers for pending asynchronous requests to functions handling the + ;; respective responses. Upon receiving a response from the language server, + ;; ‘lsp-mode’ will call the associated response handler function with a + ;; single argument, the deserialized response parameters. + (response-handlers (make-hash-table :test 'eql)) + + ;; ‘prefix-function’ is called for getting the prefix for completion. + ;; The function takes no parameter and returns a cons (start . end) representing + ;; the start and end bounds of the prefix. If it's not set, the client uses a + ;; default prefix function." + (prefix-function nil) + + ;; Contains mapping of scheme to the function that is going to be used to load + ;; the file. + (uri-handlers (make-hash-table :test #'equal)) + + ;; ‘action-handlers’ is a hash table mapping action to a handler function. It + ;; can be used in `lsp-execute-code-action' to determine whether the action + ;; current client is interested in executing the action instead of sending it + ;; to the server. + (action-handlers (make-hash-table :test 'equal)) + + ;; major modes supported by the client. + major-modes + ;; Function that will be called to decide if this language client + ;; should manage a particular buffer. The function will be passed + ;; the file name and major mode to inform the decision. Setting + ;; `activation-fn' will override `major-modes', if + ;; present. + activation-fn + ;; Break the tie when major-mode is supported by multiple clients. + (priority 0) + ;; Unique identifier for representing the client object. + server-id + ;; defines whether the client supports multi root workspaces. + multi-root + ;; Initialization options or a function that returns initialization options. + initialization-options + ;; Overrides semantic tokens faces for specific clients + semantic-tokens-faces-overrides + ;; Provides support for registering LSP Server specific capabilities. + custom-capabilities + ;; Function which returns the folders that are considered to be not projects but library files. + ;; The function accepts one parameter currently active workspace. + ;; See: https://github.com/emacs-lsp/lsp-mode/issues/225. + library-folders-fn + ;; function which will be called when opening file in the workspace to perform + ;; client specific initialization. The function accepts one parameter + ;; currently active workspace. + before-file-open-fn + ;; Function which will be called right after a workspace has been initialized. + initialized-fn + ;; ‘remote?’ indicate whether the client can be used for LSP server over TRAMP. + (remote? nil) + + ;; ‘completion-in-comments?’ t if the client supports completion in comments. + (completion-in-comments? nil) + + ;; ‘path->uri-fn’ the function to use for path->uri conversion for the client. + (path->uri-fn nil) + + ;; ‘uri->path-fn’ the function to use for uri->path conversion for the client. + (uri->path-fn nil) + ;; Function that returns an environment structure that will be used + ;; to set some environment variables when starting the language + ;; server process. These environment variables enable some + ;; additional features in the language server. The environment + ;; structure is an alist of the form (KEY . VALUE), where KEY is a + ;; string (regularly in all caps), and VALUE may be a string, a + ;; boolean, or a sequence of strings. + environment-fn + + ;; ‘after-open-fn’ workspace after open specific hooks. + (after-open-fn nil) + + ;; ‘async-request-handlers’ is a hash table mapping request method names + ;; (strings) to functions handling the respective requests that may take + ;; time to finish. Upon receiving a request, ‘lsp-mode’ will call the + ;; associated handler function passing three arguments, the ‘lsp--workspace’ + ;; object, the deserialized request parameters and the callback which accept + ;; result as its parameter. + (async-request-handlers (make-hash-table :test 'equal)) + download-server-fn + download-in-progress? + buffers) + +(defun lsp-clients-executable-find (find-command &rest args) + "Finds an executable by invoking a search command. + +FIND-COMMAND is the executable finder that searches for the +actual language server executable. ARGS is a list of arguments to +give to FIND-COMMAND to find the language server. Returns the +output of FIND-COMMAND if it exits successfully, nil otherwise. + +Typical uses include finding an executable by invoking 'find' in +a project, finding LLVM commands on macOS with 'xcrun', or +looking up project-specific language servers for projects written +in the various dynamic languages, e.g. 'nvm', 'pyenv' and 'rbenv' +etc." + (when-let* ((find-command-path (executable-find find-command)) + (executable-path + (with-temp-buffer + (when (zerop (apply 'call-process find-command-path nil t nil args)) + (buffer-substring-no-properties (point-min) (point-max)))))) + (string-trim executable-path))) + +(defvar lsp--already-widened nil) + +(defmacro lsp-save-restriction-and-excursion (&rest form) + (declare (indent 0) (debug t)) + `(if lsp--already-widened + (save-excursion ,@form) + (-let [lsp--already-widened t] + (save-restriction + (widen) + (save-excursion ,@form))))) + +;; from http://emacs.stackexchange.com/questions/8082/how-to-get-buffer-position-given-line-number-and-column-number +(defun lsp--line-character-to-point (line character) + "Return the point for character CHARACTER on line LINE." + (or (lsp-virtual-buffer-call :line/character->point line character) + (let ((inhibit-field-text-motion t)) + (lsp-save-restriction-and-excursion + (goto-char (point-min)) + (forward-line line) + ;; server may send character position beyond the current line and we + ;; should fallback to line end. + (-let [line-end (line-end-position)] + (if (> character (- line-end (point))) + line-end + (forward-char character) + (point))))))) + +(lsp-defun lsp--position-to-point ((&Position :line :character)) + "Convert `Position' object in PARAMS to a point." + (lsp--line-character-to-point line character)) + +(lsp-defun lsp--range-to-region ((&RangeToPoint :start :end)) + (cons start end)) + +(lsp-defun lsp--range-text ((&RangeToPoint :start :end)) + (buffer-substring start end)) + +(lsp-defun lsp--find-wrapping-range ((&SelectionRange :parent? :range (&RangeToPoint :start :end))) + (cond + ((and + (region-active-p) + (<= start (region-beginning) end) + (<= start (region-end) end) + (or (not (= start (region-beginning))) + (not (= end (region-end))))) + (cons start end)) + ((and (<= start (point) end) + (not (region-active-p))) + (cons start end)) + (parent? (lsp--find-wrapping-range parent?)))) + +(defun lsp--get-selection-range () + (or + (-when-let ((cache . cache-tick) lsp--document-selection-range-cache) + (when (= cache-tick (buffer-modified-tick)) cache)) + (let ((response (cl-first + (lsp-request + "textDocument/selectionRange" + (list :textDocument (lsp--text-document-identifier) + :positions (vector (lsp--cur-position))))))) + (setq lsp--document-selection-range-cache + (cons response (buffer-modified-tick))) + response))) + +(defun lsp-extend-selection () + "Extend selection." + (interactive) + (unless (lsp--capability :selectionRangeProvider) + (signal 'lsp-capability-not-supported (list "selectionRangeProvider"))) + (-when-let ((start . end) (lsp--find-wrapping-range (lsp--get-selection-range))) + (goto-char start) + (set-mark (point)) + (goto-char end) + (exchange-point-and-mark))) + +(defun lsp-warn (message &rest args) + "Display a warning message made from (`format-message' MESSAGE ARGS...). +This is equivalent to `display-warning', using `lsp-mode' as the type and +`:warning' as the level." + (display-warning 'lsp-mode (apply #'format-message message args))) + +(defun lsp--get-uri-handler (scheme) + "Get uri handler for SCHEME in the current workspace." + (--some (gethash scheme (lsp--client-uri-handlers (lsp--workspace-client it))) + (or (lsp-workspaces) (lsp--session-workspaces (lsp-session))))) + +(defun lsp--fix-path-casing (path) + "On windows, downcases path because the windows file system is +case-insensitive. + +On other systems, returns path without change." + (if (eq system-type 'windows-nt) (downcase path) path)) + +(defun lsp--uri-to-path (uri) + "Convert URI to a file path." + (if-let ((fn (->> (lsp-workspaces) + (-keep (-compose #'lsp--client-uri->path-fn #'lsp--workspace-client)) + (cl-first)))) + (funcall fn uri) + (lsp--uri-to-path-1 uri))) + +(defun lsp-remap-path-if-needed (file-name) + (-if-let ((virtual-buffer &as &plist :buffer) (gethash file-name lsp--virtual-buffer-mappings)) + (propertize (buffer-local-value 'buffer-file-name buffer) + 'lsp-virtual-buffer virtual-buffer) + file-name)) + +(defun lsp--uri-to-path-1 (uri) + "Convert URI to a file path." + (let* ((url (url-generic-parse-url (url-unhex-string uri))) + (type (url-type url)) + (file (decode-coding-string (url-filename url) + (or locale-coding-system 'utf-8))) + (file-name (if (and type (not (string= type "file"))) + (if-let ((handler (lsp--get-uri-handler type))) + (funcall handler uri) + uri) + ;; `url-generic-parse-url' is buggy on windows: + ;; https://github.com/emacs-lsp/lsp-mode/pull/265 + (or (and (eq system-type 'windows-nt) + (eq (elt file 0) ?\/) + (substring file 1)) + file)))) + (->> file-name + (concat (-some #'lsp--workspace-host-root (lsp-workspaces))) + (lsp-remap-path-if-needed)))) + +(defun lsp--buffer-uri () + "Return URI of the current buffer." + (or lsp-buffer-uri + (plist-get lsp--virtual-buffer :buffer-uri) + (lsp--path-to-uri + (or (buffer-file-name) (buffer-file-name (buffer-base-buffer)))))) + +(defun lsp-register-client-capabilities (&rest _args) + "Implemented only to make `company-lsp' happy. +DELETE when `lsp-mode.el' is deleted.") + +(defconst lsp--url-path-allowed-chars + (url--allowed-chars (append '(?/) url-unreserved-chars)) + "`url-unreserved-chars' with additional delim ?/. +This set of allowed chars is enough for hexifying local file paths.") + +(defun lsp--path-to-uri-1 (path) + (concat lsp--uri-file-prefix + (--> path + (expand-file-name it) + (or (file-remote-p it 'localname t) it) + (url-hexify-string it lsp--url-path-allowed-chars)))) + +(defun lsp--path-to-uri (path) + "Convert PATH to a uri." + (if-let ((uri-fn (->> (lsp-workspaces) + (-keep (-compose #'lsp--client-path->uri-fn #'lsp--workspace-client)) + (cl-first)))) + (funcall uri-fn path) + (lsp--path-to-uri-1 path))) + +(defun lsp--string-match-any (regex-list str) + "Return the first regex, if any, within REGEX-LIST matching STR." + (--first (string-match it str) regex-list)) + +(cl-defstruct lsp-watch + (descriptors (make-hash-table :test 'equal)) + root-directory) + +(defun lsp--folder-watch-callback (event callback watch ignored-files ignored-directories) + (let ((file-name (cl-third event)) + (event-type (cl-second event))) + (cond + ((and (file-directory-p file-name) + (equal 'created event-type) + (not (lsp--string-match-any ignored-directories file-name))) + + (lsp-watch-root-folder (file-truename file-name) callback ignored-files ignored-directories watch) + + ;; process the files that are already present in + ;; the directory. + (->> (directory-files-recursively file-name ".*" t) + (seq-do (lambda (f) + (unless (file-directory-p f) + (funcall callback (list nil 'created f))))))) + ((and (memq event-type '(created deleted changed)) + (not (file-directory-p file-name)) + (not (lsp--string-match-any ignored-files file-name))) + (funcall callback event)) + ((and (memq event-type '(renamed)) + (not (file-directory-p file-name)) + (not (lsp--string-match-any ignored-files file-name))) + (funcall callback `(,(cl-first event) deleted ,(cl-third event))) + (funcall callback `(,(cl-first event) created ,(cl-fourth event))))))) + +(defun lsp--ask-about-watching-big-repo (number-of-directories dir) + "Ask the user if they want to watch NUMBER-OF-DIRECTORIES from a repository DIR. +This is useful when there is a lot of files in a repository, as +that may slow Emacs down. Returns t if the user wants to watch +the entire repository, nil otherwise." + (prog1 + (yes-or-no-p + (format + "Watching all the files in %s would require adding watches to %s directories, so watching the repo may slow Emacs down. +Do you want to watch all files in %s? " + dir + number-of-directories + dir)) + (lsp--info + (concat "You can configure this warning with the `lsp-enable-file-watchers' " + "and `lsp-file-watch-threshold' variables")))) + + +(defun lsp--path-is-watchable-directory (path dir ignored-directories) + "Figure out whether PATH (inside of DIR) is meant to have a file watcher set. +IGNORED-DIRECTORIES is a list of regexes to filter out directories we don't want to watch." + (let + ((full-path (f-join dir path))) + (and (f-dir-p full-path) + (not (equal path ".")) + (not (equal path "..")) + (not (lsp--string-match-any ignored-directories full-path))))) + + +(defun lsp--all-watchable-directories (dir ignored-directories) + "Traverse DIR recursively and return a list of paths that should have watchers set on them. +IGNORED-DIRECTORIES will be used for exclusions" + (let* ((dir (if (f-symlink? dir) + (file-truename dir) + dir))) + (apply #'nconc + ;; the directory itself is assumed to be part of the set + (list dir) + ;; collect all subdirectories that are watchable + (-map + (lambda (path) (lsp--all-watchable-directories (f-join dir path) ignored-directories)) + ;; but only look at subdirectories that are watchable + (-filter (lambda (path) (lsp--path-is-watchable-directory path dir ignored-directories)) + (directory-files dir)))))) + +(defun lsp-watch-root-folder (dir callback ignored-files ignored-directories &optional watch warn-big-repo?) + "Create recursive file notification watch in DIR. +CALLBACK will be called when there are changes in any of +the monitored files. WATCHES is a hash table directory->file +notification handle which contains all of the watch that +already have been created. Watches will not be created for +any directory that matches any regex in IGNORED-DIRECTORIES. +Watches will not be created for any file that matches any +regex in IGNORED-FILES." + (let* ((dir (if (f-symlink? dir) + (file-truename dir) + dir)) + (watch (or watch (make-lsp-watch :root-directory dir))) + (dirs-to-watch (lsp--all-watchable-directories dir ignored-directories))) + (lsp-log "Creating watchers for following %s folders:\n %s" + (length dirs-to-watch) + (s-join "\n " dirs-to-watch)) + (when (or + (not warn-big-repo?) + (not lsp-file-watch-threshold) + (let ((number-of-directories (length dirs-to-watch))) + (or + (< number-of-directories lsp-file-watch-threshold) + (condition-case _err + (lsp--ask-about-watching-big-repo number-of-directories dir) + ('quit))))) + (dolist (current-dir dirs-to-watch) + (condition-case err + (progn + (puthash + current-dir + (file-notify-add-watch current-dir + '(change) + (lambda (event) + (lsp--folder-watch-callback event callback watch ignored-files ignored-directories))) + (lsp-watch-descriptors watch))) + (error (lsp-log "Failed to create a watch for %s: message" (error-message-string err))) + (file-missing (lsp-log "Failed to create a watch for %s: message" (error-message-string err)))))) + watch)) + +(defun lsp-kill-watch (watch) + "Delete WATCH." + (-> watch lsp-watch-descriptors hash-table-values (-each #'file-notify-rm-watch)) + (ht-clear! (lsp-watch-descriptors watch))) + +(defun lsp-json-bool (val) + "Convert VAL to JSON boolean." + (if val t :json-false)) + +(defmacro with-lsp-workspace (workspace &rest body) + "Helper macro for invoking BODY in WORKSPACE context." + (declare (debug (form body)) + (indent 1)) + `(let ((lsp--cur-workspace ,workspace)) ,@body)) + +(defmacro with-lsp-workspaces (workspaces &rest body) + "Helper macro for invoking BODY against multiple WORKSPACES." + (declare (debug (form body)) + (indent 1)) + `(let ((lsp--buffer-workspaces ,workspaces)) ,@body)) + + + +(defconst lsp-downstream-deps + '(;; external packages + ccls consult-lsp dap-mode helm-lsp lsp-dart lsp-docker lsp-focus lsp-grammarly + lsp-haskell lsp-ivy lsp-java lsp-javacomp lsp-jedi lsp-julia lsp-latex lsp-ltex + lsp-metals lsp-mssql lsp-origami lsp-p4 lsp-pascal lsp-pyre lsp-pyright + lsp-python-ms lsp-rescript lsp-sonarlint lsp-sourcekit lsp-tailwindcss lsp-treemacs + lsp-ui swift-helpful + ;; clients + lsp-actionscript lsp-ada lsp-angular lsp-bash lsp-beancount lsp-clangd + lsp-clojure lsp-cmake lsp-crystal lsp-csharp lsp-css lsp-d lsp-dhall + lsp-dockerfile lsp-elixir lsp-elm lsp-erlang lsp-eslint lsp-fortran lsp-fsharp lsp-gdscript + lsp-go lsp-groovy lsp-hack lsp-haxe lsp-html lsp-javascript lsp-json lsp-kotlin lsp-lua + lsp-markdown lsp-nim lsp-nix lsp-ocaml lsp-perl lsp-php lsp-prolog lsp-purescript lsp-pwsh + lsp-pyls lsp-pylsp lsp-racket lsp-r lsp-rf lsp-rust lsp-solargraph lsp-sorbet lsp-sqls + lsp-steep lsp-svelte lsp-terraform lsp-tex lsp-v lsp-vala lsp-verilog lsp-vetur lsp-vhdl + lsp-vimscript lsp-xml lsp-yaml lsp-zig) + "List of downstream deps.") + +(defmacro lsp-consistency-check (package) + `(defconst ,(intern (concat (symbol-name package) + "-plist-value-when-compiled")) + (eval-when-compile lsp-use-plists))) + +;; (mapc +;; (lambda (package) +;; (with-eval-after-load package +;; (let ((symbol-name (intern +;; (concat (symbol-name package) +;; "-plist-value-when-compiled")))) +;; (cond +;; ((not (boundp symbol-name)) +;; (warn "We have detected that you are using version of %s that is not compatible with current version of lsp-mode.el, please update it." (propertize (symbol-name package) +;; 'face 'bold))) +;; ((not (eq (symbol-value symbol-name) lsp-use-plists)) +;; (warn "Package %s is inconsistent with lsp-mode.el. This is indication of race during installation. In order to solve that please delete all packages related to lsp-mode, restar Emacs and install them again." (propertize (symbol-name package) 'face 'bold))))))) +;; lsp-downstream-deps) + + +;; loading code-workspace files + +;;;###autoload +(defun lsp-load-vscode-workspace (file) + "Load vscode workspace from FILE" + (interactive "fSelect file to import: ") + (mapc #'lsp-workspace-folders-remove (lsp-session-folders (lsp-session))) + + (let ((dir (f-dirname file))) + (->> file + (json-read-file) + (alist-get 'folders) + (-map (-lambda ((&alist 'path)) + (lsp-workspace-folders-add (expand-file-name path dir))))))) + +;;;###autoload +(defun lsp-save-vscode-workspace (file) + "Save vscode workspace to FILE" + (interactive "FSelect file to save to: ") + + (let ((json-encoding-pretty-print t)) + (f-write-text (json-encode + `((folders . ,(->> (lsp-session) + (lsp-session-folders) + (--map `((path . ,it))))))) + 'utf-8 + file))) + + +(defmacro lsp-foreach-workspace (&rest body) + "Execute BODY for each of the current workspaces." + (declare (debug (form body))) + `(--map (with-lsp-workspace it ,@body) (lsp-workspaces))) + +(defmacro when-lsp-workspace (workspace &rest body) + "Helper macro for invoking BODY in WORKSPACE context if present." + (declare (debug (form body)) + (indent 1)) + `(when-let ((lsp--cur-workspace ,workspace)) ,@body)) + +(lsp-defun lsp--window-show-message (_workspace (&ShowMessageRequestParams :message :type)) + "Send the server's messages to log. +PARAMS - the data sent from _WORKSPACE." + (funcall (cl-case type + (1 'lsp--error) + (2 'lsp--warn) + (t 'lsp--info)) + "%s" + message)) + +(lsp-defun lsp--window-log-message (workspace (&ShowMessageRequestParams :message :type)) + "Send the server's messages to log. +PARAMS - the data sent from WORKSPACE." + (ignore + (let ((client (lsp--workspace-client workspace))) + (when (or (not client) + (cl-notany (-rpartial #'string-match-p message) + (lsp--client-ignore-messages client))) + (lsp-log "%s" (lsp--propertize message type)))))) + +(lsp-defun lsp--window-log-message-request ((&ShowMessageRequestParams :message :type :actions?)) + "Display a message request to the user and send the user's selection back to the server." + (let* ((message (lsp--propertize message type)) + (choices (seq-map #'lsp:message-action-item-title actions?))) + (if choices + (completing-read (concat message " ") (seq-into choices 'list) nil t) + (lsp-log message)))) + +(defcustom lsp-progress-prefix " ⌛ " + "Progress prefix." + :group 'lsp-mode + :type 'string + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-progress-function #'lsp-on-progress-modeline + "Function for handling the progress notifications." + :group 'lsp-mode + :type '(choice + (const :tag "Use modeline" lsp-on-progress-modeline) + (const :tag "Legacy(uses either `progress-reporter' or `spinner' based on `lsp-progress-via-spinner')" + lsp-on-progress-legacy) + (const ignore :tag "Ignore") + (function :tag "Other function")) + :package-version '(lsp-mode . "7.1.0")) + +(defun lsp--progress-status () + "Returns the status of the progress for the current workspaces." + (-let ((progress-status + (s-join + "|" + (-keep + (lambda (workspace) + (let ((tokens (lsp--workspace-work-done-tokens workspace))) + (unless (ht-empty? tokens) + (mapconcat + (-lambda ((&WorkDoneProgressBegin :message? :title :percentage?)) + (concat (if percentage? + (format "%s%%%% " percentage?) + "") + (or message? title))) + (ht-values tokens) + "|")))) + (lsp-workspaces))))) + (unless (s-blank? progress-status) + (concat lsp-progress-prefix progress-status)))) + +(lsp-defun lsp-on-progress-modeline (workspace (&ProgressParams :token :value + (value &as &WorkDoneProgress :kind))) + "PARAMS contains the progress data. +WORKSPACE is the workspace that contains the progress token." + (add-to-list 'global-mode-string '(t (:eval (lsp--progress-status)))) + (pcase kind + ("begin" (lsp-workspace-set-work-done-token token value workspace)) + ("report" (lsp-workspace-set-work-done-token token value workspace)) + ("end" (lsp-workspace-rem-work-done-token token workspace))) + (force-mode-line-update)) + +(lsp-defun lsp-on-progress-legacy (workspace (&ProgressParams :token :value + (value &as &WorkDoneProgress :kind))) + "PARAMS contains the progress data. +WORKSPACE is the workspace that contains the progress token." + (pcase kind + ("begin" + (-let* (((&WorkDoneProgressBegin :title :percentage?) value) + (reporter + (if lsp-progress-via-spinner + (let* ((spinner-strings (alist-get 'progress-bar spinner-types)) + ;; Set message as a tooltip for the spinner strings + (propertized-strings + (seq-map (lambda (string) (propertize string 'help-echo title)) + spinner-strings)) + (spinner-type (vconcat propertized-strings))) + ;; The progress relates to the server as a whole, + ;; display it on all buffers. + (mapcar (lambda (buffer) + (lsp-with-current-buffer buffer + (spinner-start spinner-type)) + buffer) + (lsp--workspace-buffers workspace))) + (if percentage? + (make-progress-reporter title 0 100 percentage?) + ;; No percentage, just progress + (make-progress-reporter title nil nil))))) + (lsp-workspace-set-work-done-token token reporter workspace))) + ("report" + (when-let ((reporter (lsp-workspace-get-work-done-token token workspace))) + (unless lsp-progress-via-spinner + (progress-reporter-update reporter (lsp:work-done-progress-report-percentage? value))))) + + ("end" + (when-let ((reporter (lsp-workspace-get-work-done-token token workspace))) + (if lsp-progress-via-spinner + (mapc (lambda (buffer) + (when (lsp-buffer-live-p buffer) + (lsp-with-current-buffer buffer + (spinner-stop)))) + reporter) + (progress-reporter-done reporter)) + (lsp-workspace-rem-work-done-token token workspace))))) + + +;; diagnostics + +(defvar lsp-diagnostic-filter nil + "A a function which will be called with + `&PublishDiagnosticsParams' and `workspace' which can be used + to filter out the diagnostics. The function should return + `&PublishDiagnosticsParams'. + +Common usecase are: +1. Filter the diagnostics for a particular language server. +2. Filter out the diagnostics under specific level.") + +(defvar lsp-diagnostic-stats (ht)) + +(defun lsp-diagnostics (&optional current-workspace?) + "Return the diagnostics from all workspaces." + (or (pcase (if current-workspace? + (lsp-workspaces) + (lsp--session-workspaces (lsp-session))) + (`() ()) + (`(,workspace) (lsp--workspace-diagnostics workspace)) + (`,workspaces (let ((result (make-hash-table :test 'equal))) + (mapc (lambda (workspace) + (->> workspace + (lsp--workspace-diagnostics) + (maphash (lambda (file-name diagnostics) + (puthash file-name + (append (gethash file-name result) diagnostics) + result))))) + workspaces) + result))) + (ht))) + +(defun lsp-diagnostics-stats-for (path) + "Get diagnostics statistics for PATH. +The result format is vector [_ errors warnings infos hints] or nil." + (gethash (lsp--fix-path-casing path) lsp-diagnostic-stats)) + +(defun lsp-diagnostics--update-path (path new-stats) + (let ((new-stats (copy-sequence new-stats)) + (path (lsp--fix-path-casing (directory-file-name path)))) + (if-let ((old-data (gethash path lsp-diagnostic-stats))) + (dotimes (idx 5) + (cl-callf + (aref old-data idx) + (aref new-stats idx))) + (puthash path new-stats lsp-diagnostic-stats)))) + +(lsp-defun lsp--on-diagnostics-update-stats (workspace + (&PublishDiagnosticsParams :uri :diagnostics)) + (let ((path (lsp--fix-path-casing (lsp--uri-to-path uri))) + (new-stats (make-vector 5 0))) + (mapc (-lambda ((&Diagnostic :severity?)) + (cl-incf (aref new-stats (or severity? 1)))) + diagnostics) + (when-let ((old-diags (gethash path (lsp--workspace-diagnostics workspace)))) + (mapc (-lambda ((&Diagnostic :severity?)) + (cl-decf (aref new-stats (or severity? 1)))) + old-diags)) + (lsp-diagnostics--update-path path new-stats) + (while (not (string= path (setf path (file-name-directory + (directory-file-name path))))) + (lsp-diagnostics--update-path path new-stats)))) + +(defun lsp--on-diagnostics (workspace params) + "Callback for textDocument/publishDiagnostics. +interface PublishDiagnosticsParams { + uri: string; + diagnostics: Diagnostic[]; +} +PARAMS contains the diagnostics data. +WORKSPACE is the workspace that contains the diagnostics." + (when lsp-diagnostic-filter + (setf params (funcall lsp-diagnostic-filter params workspace))) + + (lsp--on-diagnostics-update-stats workspace params) + + (-let* (((&PublishDiagnosticsParams :uri :diagnostics) params) + (lsp--virtual-buffer-mappings (ht)) + (file (lsp--fix-path-casing (lsp--uri-to-path uri))) + (workspace-diagnostics (lsp--workspace-diagnostics workspace))) + + (if (seq-empty-p diagnostics) + (remhash file workspace-diagnostics) + (puthash file (append diagnostics nil) workspace-diagnostics)) + + (run-hooks 'lsp-diagnostics-updated-hook))) + +(defun lsp-diagnostics--workspace-cleanup (workspace) + (->> workspace + (lsp--workspace-diagnostics) + (maphash (lambda (key _) + (lsp--on-diagnostics-update-stats + workspace + (lsp-make-publish-diagnostics-params + :uri (lsp--path-to-uri key) + :diagnostics []))))) + (clrhash (lsp--workspace-diagnostics workspace))) + + + +;; textDocument/foldingRange support + +(cl-defstruct lsp--folding-range beg end kind children) + +(defvar-local lsp--cached-folding-ranges nil) +(defvar-local lsp--cached-nested-folding-ranges nil) + +(defun lsp--folding-range-width (range) + (- (lsp--folding-range-end range) + (lsp--folding-range-beg range))) + +(defun lsp--get-folding-ranges () + "Get the folding ranges for the current buffer." + (unless (eq (buffer-chars-modified-tick) (car lsp--cached-folding-ranges)) + (let* ((ranges (lsp-request "textDocument/foldingRange" + `(:textDocument ,(lsp--text-document-identifier)))) + (sorted-line-col-pairs (->> ranges + (cl-mapcan (-lambda ((&FoldingRange :start-line + :start-character? + :end-line + :end-character?)) + (list (cons start-line start-character?) + (cons end-line end-character?)))) + (-sort #'lsp--line-col-comparator))) + (line-col-to-point-map (lsp--convert-line-col-to-points-batch + sorted-line-col-pairs))) + (setq lsp--cached-folding-ranges + (cons (buffer-chars-modified-tick) + (--> ranges + (seq-map (-lambda ((range &as + &FoldingRange :start-line + :start-character? + :end-line + :end-character? + :kind?)) + (make-lsp--folding-range + :beg (ht-get line-col-to-point-map + (cons start-line start-character?)) + :end (ht-get line-col-to-point-map + (cons end-line end-character?)) + :kind kind?)) + it) + (seq-filter (lambda (folding-range) + (< (lsp--folding-range-beg folding-range) + (lsp--folding-range-end folding-range))) + it) + (seq-into it 'list) + (delete-dups it)))))) + (cdr lsp--cached-folding-ranges)) + +(defun lsp--get-nested-folding-ranges () + "Get a list of nested folding ranges for the current buffer." + (-let [(tick . _) lsp--cached-folding-ranges] + (if (and (eq tick (buffer-chars-modified-tick)) + lsp--cached-nested-folding-ranges) + lsp--cached-nested-folding-ranges + (setq lsp--cached-nested-folding-ranges + (lsp--folding-range-build-trees (lsp--get-folding-ranges)))))) + +(defun lsp--folding-range-build-trees (ranges) + (setq ranges (seq-sort #'lsp--range-before-p ranges)) + (let* ((dummy-node (make-lsp--folding-range + :beg most-negative-fixnum + :end most-positive-fixnum)) + (stack (list dummy-node))) + (dolist (range ranges) + (while (not (lsp--range-inside-p range (car stack))) + (pop stack)) + (push range (lsp--folding-range-children (car stack))) + (push range stack)) + (lsp--folding-range-children dummy-node))) + +(defun lsp--range-inside-p (r1 r2) + "Return non-nil if folding range R1 lies inside R2" + (and (>= (lsp--folding-range-beg r1) (lsp--folding-range-beg r2)) + (<= (lsp--folding-range-end r1) (lsp--folding-range-end r2)))) + +(defun lsp--range-before-p (r1 r2) + "Return non-nil if folding range R1 ends before R2" + ;; Ensure r1 comes before r2 + (or (< (lsp--folding-range-beg r1) + (lsp--folding-range-beg r2)) + ;; If beg(r1) == beg(r2) make sure r2 ends first + (and (= (lsp--folding-range-beg r1) + (lsp--folding-range-beg r2)) + (< (lsp--folding-range-end r2) + (lsp--folding-range-end r1))))) + +(defun lsp--point-inside-range-p (point range) + "Return non-nil if POINT lies inside folding range RANGE." + (and (>= point (lsp--folding-range-beg range)) + (<= point (lsp--folding-range-end range)))) + +(cl-defun lsp--get-current-innermost-folding-range (&optional (point (point))) + "Return the innermost folding range POINT lies in." + (seq-reduce (lambda (innermost-range curr-range) + (if (and (lsp--point-inside-range-p point curr-range) + (or (null innermost-range) + (lsp--range-inside-p curr-range innermost-range))) + curr-range + innermost-range)) + (lsp--get-folding-ranges) + nil)) + +(cl-defun lsp--get-current-outermost-folding-range (&optional (point (point))) + "Return the outermost folding range POINT lies in." + (cdr (seq-reduce (-lambda ((best-pair &as outermost-width . _) curr-range) + (let ((curr-width (lsp--folding-range-width curr-range))) + (if (and (lsp--point-inside-range-p point curr-range) + (or (null best-pair) + (> curr-width outermost-width))) + (cons curr-width curr-range) + best-pair))) + (lsp--get-folding-ranges) + nil))) + +(defun lsp--folding-range-at-point-bounds () + (if (and (or (lsp--capability :foldingRangeProvider) + (lsp--registered-capability "textDocument/foldingRange")) + lsp-enable-folding) + (if-let ((range (lsp--get-current-innermost-folding-range))) + (cons (lsp--folding-range-beg range) + (lsp--folding-range-end range))) + nil)) +(put 'lsp--folding-range 'bounds-of-thing-at-point + #'lsp--folding-range-at-point-bounds) + +(defun lsp--get-nearest-folding-range (&optional backward) + (let ((point (point)) + (found nil)) + (while (not + (or found + (if backward + (<= point (point-min)) + (>= point (point-max))))) + (if backward (cl-decf point) (cl-incf point)) + (setq found (lsp--get-current-innermost-folding-range point))) + found)) + +(defun lsp--folding-range-at-point-forward-op (n) + (when (and (or (lsp--capability :foldingRangeProvider) + (lsp--registered-capability "textDocument/foldingRange")) + lsp-enable-folding + (not (zerop n))) + (cl-block break + (dotimes (_ (abs n)) + (if-let ((range (lsp--get-nearest-folding-range (< n 0)))) + (goto-char (if (< n 0) + (lsp--folding-range-beg range) + (lsp--folding-range-end range))) + (cl-return-from break)))))) +(put 'lsp--folding-range 'forward-op + #'lsp--folding-range-at-point-forward-op) + +(defun lsp--folding-range-at-point-beginning-op () + (goto-char (car (lsp--folding-range-at-point-bounds)))) +(put 'lsp--folding-range 'beginning-op + #'lsp--folding-range-at-point-beginning-op) + +(defun lsp--folding-range-at-point-end-op () + (goto-char (cdr (lsp--folding-range-at-point-bounds)))) +(put 'lsp--folding-range 'end-op + #'lsp--folding-range-at-point-end-op) + +(defun lsp--range-at-point-bounds () + (or (lsp--folding-range-at-point-bounds) + (when-let ((range (and + (lsp--capability :hoverProvider) + (->> (lsp--text-document-position-params) + (lsp-request "textDocument/hover") + (lsp:hover-range?))))) + (lsp--range-to-region range)))) + +;; A more general purpose "thing", useful for applications like focus.el +(put 'lsp--range 'bounds-of-thing-at-point + #'lsp--range-at-point-bounds) + + +;; toggles + +(defun lsp-toggle-trace-io () + "Toggle client-server protocol logging." + (interactive) + (setq lsp-print-io (not lsp-print-io)) + (lsp--info "Server logging %s." (if lsp-print-io "enabled" "disabled"))) + +(defun lsp-toggle-signature-auto-activate () + "Toggle signature auto activate." + (interactive) + (setq lsp-signature-auto-activate + (unless lsp-signature-auto-activate '(:on-trigger-char))) + (lsp--info "Signature autoactivate %s." (if lsp-signature-auto-activate "enabled" "disabled")) + (lsp--update-signature-help-hook)) + +(defun lsp-toggle-on-type-formatting () + "Toggle on type formatting." + (interactive) + (setq lsp-enable-on-type-formatting (not lsp-enable-on-type-formatting)) + (lsp--info "On type formatting is %s." (if lsp-enable-on-type-formatting "enabled" "disabled")) + (lsp--update-on-type-formatting-hook)) + +(defun lsp-toggle-symbol-highlight () + "Toggle symbol highlighting." + (interactive) + (setq lsp-enable-symbol-highlighting (not lsp-enable-symbol-highlighting)) + + (cond + ((and lsp-enable-symbol-highlighting + (lsp-feature? "textDocument/documentHighlight")) + (add-hook 'lsp-on-idle-hook #'lsp--document-highlight nil t) + (lsp--info "Symbol highlighting enabled in current buffer.")) + ((not lsp-enable-symbol-highlighting) + (remove-hook 'lsp-on-idle-hook #'lsp--document-highlight t) + (lsp--remove-overlays 'lsp-highlight) + (lsp--info "Symbol highlighting disabled in current buffer.")))) + + +;; keybindings +(defvar lsp--binding-descriptions nil + "List of key binding/short description pair.") + +(defmacro lsp-define-conditional-key (keymap key def desc cond &rest bindings) + "In KEYMAP, define key sequence KEY as DEF conditionally. +This is like `define-key', except the definition disappears +whenever COND evaluates to nil. +DESC is the short-description for the binding. +BINDINGS is a list of (key def desc cond)." + (declare (indent defun) + (debug (form form form form form &rest sexp))) + (->> (cl-list* key def desc cond bindings) + (-partition 4) + (-mapcat (-lambda ((key def desc cond)) + `((define-key ,keymap ,key + '(menu-item + ,(format "maybe-%s" def) + ,def + :filter + (lambda (item) + (when (with-current-buffer (or (when (buffer-live-p lsp--describe-buffer) + lsp--describe-buffer) + (current-buffer)) + ,cond) + item)))) + (when (stringp ,key) + (setq lsp--binding-descriptions + (nconc lsp--binding-descriptions '(,key ,desc))))))) + macroexp-progn)) + +(defvar lsp--describe-buffer nil) + +(defun lsp-describe-buffer-bindings-advice (fn buffer &optional prefix menus) + (let ((lsp--describe-buffer buffer)) + (funcall fn buffer prefix menus))) + +(advice-add 'describe-buffer-bindings + :around + #'lsp-describe-buffer-bindings-advice) + +(defun lsp--prepend-prefix (mappings) + (->> mappings + (-partition 2) + (-mapcat (-lambda ((key description)) + (list (concat lsp-keymap-prefix " " key) + description))))) + +(defvar lsp-command-map + (-doto (make-sparse-keymap) + (lsp-define-conditional-key + ;; workspaces + "wD" lsp-disconnect "disconnect" (lsp-workspaces) + "wd" lsp-describe-session "describe session" t + "wq" lsp-workspace-shutdown "shutdown server" (lsp-workspaces) + "wr" lsp-workspace-restart "restart server" (lsp-workspaces) + "ws" lsp "start server" t + + ;; formatting + "==" lsp-format-buffer "format buffer" (or (lsp-feature? "textDocument/rangeFormatting") + (lsp-feature? "textDocument/formatting")) + "=r" lsp-format-region "format region" (lsp-feature? "textDocument/rangeFormatting") + + ;; folders + "Fa" lsp-workspace-folders-add "add folder" t + "Fb" lsp-workspace-blacklist-remove "un-blacklist folder" t + "Fr" lsp-workspace-folders-remove "remove folder" t + + ;; toggles + "TD" lsp-modeline-diagnostics-mode "toggle modeline diagnostics" (lsp-feature? + "textDocument/publishDiagnostics") + "TL" lsp-toggle-trace-io "toggle log io" t + "TS" lsp-ui-sideline-mode "toggle sideline" (featurep 'lsp-ui-sideline) + "TT" lsp-treemacs-sync-mode "toggle treemacs integration" (featurep 'lsp-treemacs) + "Ta" lsp-modeline-code-actions-mode "toggle modeline code actions" (lsp-feature? + "textDocument/codeAction") + "Tb" lsp-headerline-breadcrumb-mode "toggle breadcrumb" (lsp-feature? + "textDocument/documentSymbol") + "Td" lsp-ui-doc-mode "toggle documentation popup" (featurep 'lsp-ui-doc) + "Tf" lsp-toggle-on-type-formatting "toggle on type formatting" (lsp-feature? + "textDocument/onTypeFormatting") + "Th" lsp-toggle-symbol-highlight "toggle highlighting" (lsp-feature? "textDocument/documentHighlight") + "Tl" lsp-lens-mode "toggle lenses" (lsp-feature? "textDocument/codeLens") + "Ts" lsp-toggle-signature-auto-activate "toggle signature" (lsp-feature? "textDocument/signatureHelp") + + ;; goto + "ga" xref-find-apropos "find symbol in workspace" (lsp-feature? "workspace/symbol") + "gd" lsp-find-declaration "find declarations" (lsp-feature? "textDocument/declaration") + "ge" lsp-treemacs-errors-list "show errors" (fboundp 'lsp-treemacs-errors-list) + "gg" lsp-find-definition "find definitions" (lsp-feature? "textDocument/definition") + "gh" lsp-treemacs-call-hierarchy "call hierarchy" (and (lsp-feature? "callHierarchy/incomingCalls") + (fboundp 'lsp-treemacs-call-hierarchy)) + "gi" lsp-find-implementation "find implementations" (lsp-feature? "textDocument/implementation") + "gr" lsp-find-references "find references" (lsp-feature? "textDocument/references") + "gt" lsp-find-type-definition "find type definition" (lsp-feature? "textDocument/typeDefinition") + + ;; help + "hg" lsp-ui-doc-glance "glance symbol" (and (featurep 'lsp-ui-doc) + (lsp-feature? "textDocument/hover")) + "hh" lsp-describe-thing-at-point "describe symbol at point" (lsp-feature? "textDocument/hover") + "hs" lsp-signature-activate "signature help" (lsp-feature? "textDocument/signatureHelp") + + ;; refactoring + "ro" lsp-organize-imports "organize imports" (lsp-feature? "textDocument/codeAction") + "rr" lsp-rename "rename" (lsp-feature? "textDocument/rename") + + ;; actions + "aa" lsp-execute-code-action "code actions" (lsp-feature? "textDocument/codeAction") + "ah" lsp-document-highlight "highlight symbol" (lsp-feature? "textDocument/documentHighlight") + "al" lsp-avy-lens "lens" (and (bound-and-true-p lsp-lens-mode) (featurep 'avy)) + + ;; peeks + "Gg" lsp-ui-peek-find-definitions "peek definitions" (and (lsp-feature? "textDocument/definition") + (fboundp 'lsp-ui-peek-find-definitions)) + "Gi" lsp-ui-peek-find-implementation "peek implementations" (and + (fboundp 'lsp-ui-peek-find-implementation) + (lsp-feature? "textDocument/implementation")) + "Gr" lsp-ui-peek-find-references "peek references" (and (fboundp 'lsp-ui-peek-find-references) + (lsp-feature? "textDocument/references")) + "Gs" lsp-ui-peek-find-workspace-symbol "peek workspace symbol" (and (fboundp + 'lsp-ui-peek-find-workspace-symbol) + (lsp-feature? "workspace/symbol"))))) + + +;; which-key integration + +(declare-function which-key-add-major-mode-key-based-replacements "ext:which-key") +(declare-function which-key-add-key-based-replacements "ext:which-key") + +(defun lsp-enable-which-key-integration (&optional all-modes) + "Adds descriptions for `lsp-mode-map' to `which-key-mode' for the current +active `major-mode', or for all major modes when ALL-MODES is t." + (cl-flet ((which-key-fn (if all-modes + 'which-key-add-key-based-replacements + (apply-partially 'which-key-add-major-mode-key-based-replacements major-mode)))) + (apply + #'which-key-fn + (lsp--prepend-prefix + (cl-list* + "" "lsp" + "w" "workspaces" + "F" "folders" + "=" "formatting" + "T" "toggle" + "g" "goto" + "h" "help" + "r" "refactor" + "a" "code actions" + "G" "peek" + lsp--binding-descriptions))))) + + +;; Globbing syntax + +;; We port VSCode's glob-to-regexp code +;; (https://github.com/Microsoft/vscode/blob/466da1c9013c624140f6d1473b23a870abc82d44/src/vs/base/common/glob.ts) +;; since the LSP globbing syntax seems to be the same as that of +;; VSCode. + +(defconst lsp-globstar "**" + "Globstar pattern.") + +(defconst lsp-glob-split ?/ + "The character by which we split path components in a glob +pattern.") + +(defconst lsp-path-regexp "[/\\\\]" + "Forward or backslash to be used as a path separator in +computed regexps.") + +(defconst lsp-non-path-regexp "[^/\\\\]" + "A regexp matching anything other than a slash.") + +(defconst lsp-globstar-regexp + (format "\\(?:%s\\|%s+%s\\|%s%s+\\)*?" + lsp-path-regexp + lsp-non-path-regexp lsp-path-regexp + lsp-path-regexp lsp-non-path-regexp) + "Globstar in regexp form.") + +(defun lsp-split-glob-pattern (pattern split-char) + "Split PATTERN at SPLIT-CHAR while respecting braces and brackets." + (when pattern + (let ((segments nil) + (in-braces nil) + (in-brackets nil) + (current-segment "")) + (dolist (char (string-to-list pattern)) + (cl-block 'exit-point + (if (eq char split-char) + (when (and (null in-braces) + (null in-brackets)) + (push current-segment segments) + (setq current-segment "") + (cl-return-from 'exit-point)) + (pcase char + (?{ + (setq in-braces t)) + (?} + (setq in-braces nil)) + (?\[ + (setq in-brackets t)) + (?\] + (setq in-brackets nil)))) + (setq current-segment (concat current-segment + (char-to-string char))))) + (unless (string-empty-p current-segment) + (push current-segment segments)) + (nreverse segments)))) + +(defun lsp--glob-to-regexp (pattern) + "Helper function to convert a PATTERN from LSP's glob syntax to +an Elisp regexp." + (if (string-empty-p pattern) + "" + (let ((current-regexp "") + (glob-segments (lsp-split-glob-pattern pattern lsp-glob-split))) + (if (-all? (lambda (segment) (eq segment lsp-globstar)) + glob-segments) + ".*" + (let ((prev-segment-was-globstar nil)) + (seq-do-indexed + (lambda (segment index) + (if (string-equal segment lsp-globstar) + (unless prev-segment-was-globstar + (setq current-regexp (concat current-regexp + lsp-globstar-regexp)) + (setq prev-segment-was-globstar t)) + (let ((in-braces nil) + (brace-val "") + (in-brackets nil) + (bracket-val "")) + (dolist (char (string-to-list segment)) + (cond + ((and (not (char-equal char ?\})) + in-braces) + (setq brace-val (concat brace-val + (char-to-string char)))) + ((and in-brackets + (or (not (char-equal char ?\])) + (string-empty-p bracket-val))) + (let ((curr (cond + ((char-equal char ?-) + "-") + ;; NOTE: ?\^ and ?^ are different characters + ((and (memq char '(?^ ?!)) + (string-empty-p bracket-val)) + "^") + ((char-equal char lsp-glob-split) + "") + (t + (regexp-quote (char-to-string char)))))) + (setq bracket-val (concat bracket-val curr)))) + (t + (cl-case char + (?{ + (setq in-braces t)) + (?\[ + (setq in-brackets t)) + (?} + (let* ((choices (lsp-split-glob-pattern brace-val ?\,)) + (brace-regexp (concat "\\(?:" + (mapconcat #'lsp--glob-to-regexp choices "\\|") + "\\)"))) + (setq current-regexp (concat current-regexp + brace-regexp)) + (setq in-braces nil) + (setq brace-val ""))) + (?\] + (setq current-regexp + (concat current-regexp + "[" bracket-val "]")) + (setq in-brackets nil) + (setq bracket-val "")) + (?? + (setq current-regexp + (concat current-regexp + lsp-non-path-regexp))) + (?* + (setq current-regexp + (concat current-regexp + lsp-non-path-regexp "*?"))) + (t + (setq current-regexp + (concat current-regexp + (regexp-quote (char-to-string char))))))))) + (when (and (< index (1- (length glob-segments))) + (or (not (string-equal (nth (1+ index) glob-segments) + lsp-globstar)) + (< (+ index 2) + (length glob-segments)))) + (setq current-regexp + (concat current-regexp + lsp-path-regexp))) + (setq prev-segment-was-globstar nil)))) + glob-segments) + current-regexp))))) + +;; See https://github.com/emacs-lsp/lsp-mode/issues/2365 +(defun lsp-glob-unbrace-at-top-level (glob-pattern) + "If GLOB-PATTERN does not start with a brace, return a singleton list containing GLOB-PATTERN. + +If GLOB-PATTERN does start with a brace, return a list of the +comma-separated globs within the top-level braces." + (if (not (string-prefix-p "{" glob-pattern)) + (list glob-pattern) + (lsp-split-glob-pattern (substring glob-pattern 1 -1) ?\,))) + +(defun lsp-glob-convert-to-wrapped-regexp (glob-pattern) + "Convert GLOB-PATTERN to a regexp wrapped with the beginning- +and end-of-string meta-characters." + (concat "\\`" (lsp--glob-to-regexp (string-trim glob-pattern)) "\\'")) + +(defun lsp-glob-to-regexps (glob-pattern) + "Convert a GLOB-PATTERN to a list of Elisp regexps." + (let* ((trimmed-pattern (string-trim glob-pattern)) + (top-level-unbraced-patterns (lsp-glob-unbrace-at-top-level trimmed-pattern))) + (seq-map #'lsp-glob-convert-to-wrapped-regexp + top-level-unbraced-patterns))) + + + +(defvar lsp-mode-menu) + +(defun lsp-mouse-click (event) + (interactive "e") + (let* ((ec (event-start event)) + (choice (x-popup-menu event lsp-mode-menu)) + (action (lookup-key lsp-mode-menu (apply 'vector choice)))) + + (select-window (posn-window ec)) + + (unless (and (region-active-p) (eq action 'lsp-execute-code-action)) + (goto-char (posn-point ec))) + (run-with-idle-timer + 0.001 nil + (lambda () + (cl-labels ((check (value) (not (null value)))) + (when choice + (call-interactively action))))))) + +(defvar lsp-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-<down-mouse-1>") #'lsp-find-definition-mouse) + (define-key map (kbd "C-<mouse-1>") #'ignore) + (define-key map (kbd "<mouse-3>") #'lsp-mouse-click) + (define-key map (kbd "C-S-SPC") #'lsp-signature-activate) + (when lsp-keymap-prefix + (define-key map (kbd lsp-keymap-prefix) lsp-command-map)) + map) + "Keymap for `lsp-mode'.") + +(define-minor-mode lsp-mode "" + :keymap lsp-mode-map + :lighter + (" LSP[" + (lsp--buffer-workspaces + (:eval (mapconcat #'lsp--workspace-print lsp--buffer-workspaces "][")) + (:propertize "Disconnected" face warning)) + "]") + :group 'lsp-mode) + +(defvar lsp-mode-menu + (easy-menu-create-menu + nil + `(["Go to definition" lsp-find-definition + :active (lsp-feature? "textDocument/definition")] + ["Find references" lsp-find-references + :active (lsp-feature? "textDocument/references")] + ["Find implementations" lsp-find-implementation + :active (lsp-feature? "textDocument/implementation")] + ["Find declarations" lsp-find-declaration + :active (lsp-feature? "textDocument/declaration")] + ["Go to type declaration" lsp-find-type-definition + :active (lsp-feature? "textDocument/typeDefinition")] + "--" + ["Describe" lsp-describe-thing-at-point] + ["Code action" lsp-execute-code-action] + ["Format" lsp-format-buffer] + ["Highlight references" lsp-document-highlight] + ["Type Hierarchy" lsp-java-type-hierarchy + :visible (lsp-can-execute-command? "java.navigate.resolveTypeHierarchy")] + ["Type Hierarchy" lsp-treemacs-type-hierarchy + :visible (and (not (lsp-can-execute-command? "java.navigate.resolveTypeHierarchy")) + (functionp 'lsp-treemacs-type-hierarchy) + (lsp-feature? "textDocument/typeHierarchy"))] + ["Call Hierarchy" lsp-treemacs-call-hierarchy + :visible (and (functionp 'lsp-treemacs-call-hierarchy) + (lsp-feature? "textDocument/callHierarchy"))] + ["Rename" lsp-rename + :active (lsp-feature? "textDocument/rename")] + "--" + ("Session" + ["View logs" lsp-workspace-show-log] + ["Describe" lsp-describe-session] + ["Shutdown" lsp-shutdown-workspace] + ["Restart" lsp-restart-workspace]) + ("Workspace Folders" + ["Add" lsp-workspace-folders-add] + ["Remove" lsp-workspace-folders-remove] + ["Open" lsp-workspace-folders-open]) + ("Toggle features" + ["Lenses" lsp-lens-mode] + ["Headerline breadcrumb" lsp-headerline-breadcrumb-mode] + ["Modeline code actions" lsp-modeline-code-actions-mode] + ["Modeline diagnostics" lsp-modeline-diagnostics-mode]) + "---" + ("Debug" + :active (bound-and-true-p dap-ui-mode) + :filter ,(lambda (_) + (and (boundp 'dap-ui-menu-items) + (nthcdr 3 dap-ui-menu-items)))))) + "Menu for lsp-mode.") + +(defalias 'make-lsp-client 'make-lsp--client) + +(cl-defstruct lsp--registered-capability + (id "") + (method " ") + (options nil)) + +;; A ‘lsp--workspace’ object represents exactly one language server process. +(cl-defstruct lsp--workspace + ;; the `ewoc' object for displaying I/O to and from the server + (ewoc nil) + + ;; ‘server-capabilities’ is a hash table of the language server capabilities. + ;; It is the hash table representation of a LSP ServerCapabilities structure; + ;; cf. https://microsoft.github.io/language-server-protocol/specification#initialize. + (server-capabilities nil) + + ;; ‘registered-server-capabilities’ is a list of hash tables that represent + ;; dynamically-registered Registration objects. See + ;; https://microsoft.github.io/language-server-protocol/specification#client_registerCapability. + (registered-server-capabilities nil) + + ;; ‘root’ is a directory name or a directory file name for the workspace + ;; root. ‘lsp-mode’ passes this directory to the ‘initialize’ method of the + ;; language server; see + ;; https://microsoft.github.io/language-server-protocol/specification#initialize. + (root nil) + + ;; ‘client’ is the ‘lsp--client’ object associated with this workspace. + (client nil) + + ;; ‘host-root’ contains the host root info as derived from `file-remote-p'. It + ;; used to derive the file path in `lsp--uri-to-path' when using tramp + ;; connection. + (host-root nil) + + ;; ‘proc’ is a process object; it may represent a regular process, a pipe, or + ;; a network connection. ‘lsp-mode’ communicates with ‘proc’ using the + ;; language server protocol. ‘proc’ corresponds to the COMMUNICATION-PROCESS + ;; element of the return value of the client’s ‘get-root’ field, which see. + (proc nil) + + ;; ‘proc’ is a process object; it must represent a regular process, not a + ;; pipe or network process. It represents the actual server process that + ;; corresponds to this workspace. ‘cmd-proc’ corresponds to the + ;; COMMAND-PROCESS element of the return value of the client’s ‘get-root’ + ;; field, which see. + (cmd-proc nil) + + ;; ‘buffers’ is a list of buffers associated with this workspace. + (buffers nil) + + ;; if semantic tokens is enabled, `semantic-tokens-faces' contains + ;; one face (or nil) for each token type supported by the language server. + (semantic-tokens-faces nil) + + ;; If semantic highlighting is enabled, `semantic-tokens-modifier-faces' + ;; contains one face (or nil) for each modifier type supported by the language + ;; server + (semantic-tokens-modifier-faces nil) + + ;; Extra client capabilities provided by third-party packages using + ;; `lsp-register-client-capabilities'. It's value is an alist of (PACKAGE-NAME + ;; . CAPS), where PACKAGE-NAME is a symbol of the third-party package name, + ;; and CAPS is either a plist of the client capabilities, or a function that + ;; takes no argument and returns a plist of the client capabilities or nil.") + (extra-client-capabilities nil) + + ;; Workspace status + (status nil) + + ;; ‘metadata’ is a generic storage for workspace specific data. It is + ;; accessed via `lsp-workspace-set-metadata' and `lsp-workspace-set-metadata' + (metadata (make-hash-table :test 'equal)) + + ;; contains all the file notification watches that have been created for the + ;; current workspace in format filePath->file notification handle. + (watches (make-hash-table :test 'equal)) + + ;; list of workspace folders + (workspace-folders nil) + + ;; ‘last-id’ the last request id for the current workspace. + (last-id 0) + + ;; ‘status-string’ allows extensions to specify custom status string based on + ;; the Language Server specific messages. + (status-string nil) + + ;; ‘shutdown-action’ flag used to mark that workspace should not be restarted (e.g. it + ;; was stopped). + shutdown-action + + ;; ‘diagnostics’ a hashmap with workspace diagnostics. + (diagnostics (make-hash-table :test 'equal)) + + ;; contains all the workDone progress tokens that have been created + ;; for the current workspace. + (work-done-tokens (make-hash-table :test 'equal))) + + +(cl-defstruct lsp-session + ;; contains the folders that are part of the current session + folders + ;; contains the folders that must not be imported in the current workspace. + folders-blacklist + ;; contains the list of folders that must be imported in a project in case of + ;; multi root LSP server. + (server-id->folders (make-hash-table :test 'equal)) + ;; folder to list of the servers that are associated with the folder. + (folder->servers (make-hash-table :test 'equal)) + ;; ‘metadata’ is a generic storage for workspace specific data. It is + ;; accessed via `lsp-workspace-set-metadata' and `lsp-workspace-set-metadata' + (metadata (make-hash-table :test 'equal))) + +(defun lsp-workspace-status (status-string &optional workspace) + "Set current workspace status to STATUS-STRING. +If WORKSPACE is not specified defaults to lsp--cur-workspace." + (let ((status-string (when status-string (replace-regexp-in-string "%" "%%" status-string)))) + (setf (lsp--workspace-status-string (or workspace lsp--cur-workspace)) status-string))) + +(defun lsp-session-set-metadata (key value &optional _workspace) + "Associate KEY with VALUE in the WORKSPACE metadata. +If WORKSPACE is not provided current workspace will be used." + (puthash key value (lsp-session-metadata (lsp-session)))) + +(defalias 'lsp-workspace-set-metadata 'lsp-session-set-metadata) + +(defun lsp-session-get-metadata (key &optional _workspace) + "Lookup KEY in WORKSPACE metadata. +If WORKSPACE is not provided current workspace will be used." + (gethash key (lsp-session-metadata (lsp-session)))) + +(defalias 'lsp-workspace-get-metadata 'lsp-session-get-metadata) + +(defun lsp-workspace-set-work-done-token (token value workspace) + "Associate TOKEN with VALUE in the WORKSPACE work-done-tokens." + (puthash token value (lsp--workspace-work-done-tokens workspace))) + +(defun lsp-workspace-get-work-done-token (token workspace) + "Lookup TOKEN in the WORKSPACE work-done-tokens." + (gethash token (lsp--workspace-work-done-tokens workspace))) + +(defun lsp-workspace-rem-work-done-token (token workspace) + "Remove TOKEN from the WORKSPACE work-done-tokens." + (remhash token (lsp--workspace-work-done-tokens workspace))) + + +(defun lsp--make-notification (method &optional params) + "Create notification body for method METHOD and parameters PARAMS." + (list :jsonrpc "2.0" :method method :params params)) + +(defalias 'lsp--make-request 'lsp--make-notification) +(defalias 'lsp-make-request 'lsp--make-notification) + +(defun lsp--make-response (id result) + "Create response for REQUEST with RESULT." + `(:jsonrpc "2.0" :id ,id :result ,result)) + +(defun lsp-make-notification (method &optional params) + "Create notification body for method METHOD and parameters PARAMS." + (lsp--make-notification method params)) + +(defmacro lsp--json-serialize (params) + (if (progn + (require 'json) + (fboundp 'json-serialize)) + `(json-serialize ,params + :null-object nil + :false-object :json-false) + `(let ((json-false :json-false)) + (json-encode ,params)))) + +(defun lsp--make-message (params) + "Create a LSP message from PARAMS, after encoding it to a JSON string." + (let ((body (lsp--json-serialize params))) + (concat "Content-Length: " + (number-to-string (1+ (string-bytes body))) + "\r\n\r\n" + body + "\n"))) + +(cl-defstruct lsp--log-entry timestamp process-time type method id body) + +(defun lsp--make-log-entry (method id body type &optional process-time) + "Create an outgoing log object from BODY with method METHOD and id ID. +If ID is non-nil, then the body is assumed to be a notification. +TYPE can either be 'incoming or 'outgoing" + (cl-assert (memq type '(incoming-req outgoing-req incoming-notif + outgoing-notif incoming-resp + outgoing-resp))) + (make-lsp--log-entry + :timestamp (format-time-string "%I:%M:%S %p") + :process-time process-time + :method method + :id id + :type type + :body body)) + +(defun lsp--log-entry-pp (entry) + (cl-assert (lsp--log-entry-p entry)) + (pcase-let (((cl-struct lsp--log-entry timestamp method id type process-time + body) + entry) + (json-false :json-false) + (json-encoding-pretty-print t) + (str nil)) + (setq str + (concat (format "[Trace - %s] " timestamp) + (pcase type + ('incoming-req (format "Received request '%s - (%s)." method id)) + ('outgoing-req (format "Sending request '%s - (%s)'." method id)) + + ('incoming-notif (format "Received notification '%s'." method)) + ('outgoing-notif (format "Sending notification '%s'." method)) + + ('incoming-resp (format "Received response '%s - (%s)' in %dms." + method id process-time)) + ('outgoing-resp + (format + "Sending response '%s - (%s)'. Processing request took %dms" + method id process-time))) + "\n" + (if (memq type '(incoming-resp ougoing-resp)) + "Result: " + "Params: ") + (json-encode body) + "\n\n\n")) + (setq str (propertize str 'mouse-face 'highlight 'read-only t)) + (insert str))) + +(defvar-local lsp--log-io-ewoc nil) + +(defun lsp--get-create-io-ewoc (workspace) + (if (and (lsp--workspace-ewoc workspace) + (buffer-live-p (ewoc-buffer (lsp--workspace-ewoc workspace)))) + (lsp--workspace-ewoc workspace) + (with-current-buffer (lsp--get-log-buffer-create workspace) + (unless (eq 'lsp-log-io-mode major-mode) (lsp-log-io-mode)) + (setq-local window-point-insertion-type t) + (setq lsp--log-io-ewoc (ewoc-create #'lsp--log-entry-pp nil nil t)) + (setf (lsp--workspace-ewoc workspace) lsp--log-io-ewoc)) + (lsp--workspace-ewoc workspace))) + +(defun lsp--ewoc-count (ewoc) + (let* ((count 0) + (count-fn (lambda (_) (setq count (1+ count))))) + (ewoc-map count-fn ewoc) + count)) + +(defun lsp--log-entry-new (entry workspace) + (let* ((ewoc (lsp--get-create-io-ewoc workspace)) + (count (and (not (eq lsp-io-messages-max t)) (lsp--ewoc-count ewoc))) + (node (if (or (eq lsp-io-messages-max t) + (>= lsp-io-messages-max count)) + nil + (ewoc-nth ewoc (1- lsp-io-messages-max)))) + (prev nil) + (inhibit-read-only t)) + (while node + (setq prev (ewoc-prev ewoc node)) + (ewoc-delete ewoc node) + (setq node prev)) + (ewoc-enter-last ewoc entry))) + +(defun lsp--send-notification (body) + "Send BODY as a notification to the language server." + (lsp-foreach-workspace + (when lsp-print-io + (lsp--log-entry-new (lsp--make-log-entry + (plist-get body :method) + nil (plist-get body :params) 'outgoing-notif) + lsp--cur-workspace)) + (lsp--send-no-wait (lsp--make-message body) + (lsp--workspace-proc lsp--cur-workspace)))) + +(defalias 'lsp-send-notification 'lsp--send-notification) + +(defun lsp-notify (method params) + "Send notification METHOD with PARAMS." + (lsp--send-notification (lsp--make-notification method params))) + +(defun lsp--cur-workspace-check () + "Check whether buffer lsp workspace(s) are set." + (cl-assert (lsp-workspaces) nil + "No language server(s) is associated with this buffer.")) + +(defun lsp--send-request (body &optional no-wait no-merge) + "Send BODY as a request to the language server, get the response. +If NO-WAIT is non-nil, don't synchronously wait for a response. +If NO-MERGE is non-nil, don't merge the results but return an +alist mapping workspace->result." + (lsp-request (plist-get body :method) + (plist-get body :params) + :no-wait no-wait + :no-merge no-merge)) + +(defalias 'lsp-send-request 'lsp--send-request + "Send BODY as a request to the language server and return the response +synchronously. +\n(fn BODY)") + +(cl-defun lsp-request (method params &key no-wait no-merge) + "Send request METHOD with PARAMS. +If NO-MERGE is non-nil, don't merge the results but return alist workspace->result. +If NO-WAIT is non-nil send the request as notification." + (if no-wait + (lsp-notify method params) + (let* ((send-time (time-to-seconds (current-time))) + ;; max time by which we must get a response + (expected-time (+ send-time lsp-response-timeout)) + resp-result resp-error done?) + (unwind-protect + (progn + (lsp-request-async method params + (lambda (res) (setf resp-result (or res :finished)) (throw 'lsp-done '_)) + :error-handler (lambda (err) (setf resp-error err) (throw 'lsp-done '_)) + :no-merge no-merge + :mode 'detached + :cancel-token :sync-request) + (while (not (or resp-error resp-result)) + (catch 'lsp-done + (accept-process-output nil (- expected-time send-time))) + (setq send-time (time-to-seconds (current-time))) + (when (< expected-time send-time) + (error "Timeout while waiting for response. Method: %s" method))) + (setq done? t) + (cond + ((eq resp-result :finished) nil) + (resp-result resp-result) + ((lsp-json-error? resp-error) (error (lsp:json-error-message resp-error))) + ((lsp-json-error? (cl-first resp-error)) + (error (lsp:json-error-message (cl-first resp-error)))))) + (unless done? + (lsp-cancel-request-by-token :sync-request)))))) + +(cl-defun lsp-request-while-no-input (method params) + "Send request METHOD with PARAMS and waits until there is no input. +Return same value as `lsp--while-no-input' and respecting `non-essential'." + (if non-essential + (let* ((send-time (time-to-seconds (current-time))) + ;; max time by which we must get a response + (expected-time (+ send-time lsp-response-timeout)) + resp-result resp-error done?) + (unwind-protect + (progn + (lsp-request-async method params + (lambda (res) (setf resp-result (or res :finished)) (throw 'lsp-done '_)) + :error-handler (lambda (err) (setf resp-error err) (throw 'lsp-done '_)) + :mode 'detached + :cancel-token :sync-request) + (while (not (or resp-error resp-result (input-pending-p))) + (catch 'lsp-done + (sit-for (- expected-time send-time))) + (setq send-time (time-to-seconds (current-time))) + (when (< expected-time send-time) + (error "Timeout while waiting for response. Method: %s" method))) + (setq done? (or resp-error resp-result)) + (cond + ((eq resp-result :finished) nil) + (resp-result resp-result) + ((lsp-json-error? resp-error) (error (lsp:json-error-message resp-error))) + ((lsp-json-error? (cl-first resp-error)) + (error (lsp:json-error-message (cl-first resp-error)))))) + (unless done? + (lsp-cancel-request-by-token :sync-request)) + (when (and (input-pending-p) lsp--throw-on-input) + (throw 'input :interrupted)))) + (lsp-request method params))) + +(defvar lsp--cancelable-requests (ht)) + +(cl-defun lsp-request-async (method params callback + &key mode error-handler cancel-handler no-merge cancel-token) + "Send METHOD with PARAMS as a request to the language server. +Call CALLBACK with the response received from the server +asynchronously. +MODE determines when the callback will be called depending on the +condition of the original buffer. It could be: +- `detached' which means that the callback will be executed no +matter what has happened to the buffer. +- `alive' - the callback will be executed only if the buffer from +which the call was executed is still alive. +- `current' the callback will be executed only if the original buffer +is still selected. +- `tick' - the callback will be executed only if the buffer was not modified. +- `unchanged' - the callback will be executed only if the buffer hasn't +changed and if the buffer is not modified. + +ERROR-HANDLER will be called in case the request has failed. +CANCEL-HANDLER will be called in case the request is being canceled. +If NO-MERGE is non-nil, don't merge the results but return alist +workspace->result. +CANCEL-TOKEN is the token that can be used to cancel request." + (lsp--send-request-async `(:jsonrpc "2.0" :method ,method :params ,params) + callback mode error-handler cancel-handler no-merge cancel-token)) + +(defun lsp--create-request-cancel (id workspaces hook buf method cancel-callback) + (lambda (&rest _) + (unless (and (equal 'post-command-hook hook) + (equal (current-buffer) buf)) + (lsp--request-cleanup-hooks id) + (with-lsp-workspaces workspaces + (lsp--cancel-request id) + (when cancel-callback (funcall cancel-callback))) + (lsp-log "Cancelling %s(%s) in hook %s" method id hook)))) + +(defun lsp--create-async-callback + (callback method no-merge workspaces) + "Create async handler expecting COUNT results, merge them and call CALLBACK. +MODE determines when the callback will be called depending on the +condition of the original buffer. METHOD is the invoked method. +If NO-MERGE is non-nil, don't merge the results but return alist workspace->result. +ID is the request id. " + (let (results errors) + (lambda (result) + (push (cons lsp--cur-workspace result) + (if (eq result :error) errors results)) + (when (and (not (eq (length errors) (length workspaces))) + (eq (+ (length errors) (length results)) (length workspaces))) + (funcall callback + (if no-merge + results + (lsp--merge-results (-map #'cl-rest results) method))))))) + +(defun lsp--create-default-error-handler (method) + "Default error handler. +METHOD is the executed method." + (lambda (error) + (lsp--warn "%s" (or (lsp--error-string error) + (format "%s Request has failed" method))))) + +(defvar lsp--request-cleanup-hooks (ht)) + +(defun lsp--request-cleanup-hooks (request-id) + (when-let ((cleanup-function (gethash request-id lsp--request-cleanup-hooks))) + (funcall cleanup-function) + (remhash request-id lsp--request-cleanup-hooks))) + +(defun lsp-cancel-request-by-token (cancel-token) + "Cancel request using CANCEL-TOKEN." + (-when-let ((request-id . workspaces) (gethash cancel-token lsp--cancelable-requests)) + (with-lsp-workspaces workspaces + (lsp--cancel-request request-id)) + (remhash cancel-token lsp--cancelable-requests) + (lsp--request-cleanup-hooks request-id))) + +(defun lsp--send-request-async (body callback + &optional mode error-callback cancel-callback + no-merge cancel-token) + "Send BODY as a request to the language server. +Call CALLBACK with the response received from the server +asynchronously. +MODE determines when the callback will be called depending on the +condition of the original buffer. It could be: +- `detached' which means that the callback will be executed no +matter what has happened to the buffer. +- `alive' - the callback will be executed only if the buffer from +which the call was executed is still alive. +- `current' the callback will be executed only if the original buffer +is still selected. +- `tick' - the callback will be executed only if the buffer was not modified. +- `unchanged' - the callback will be executed only if the buffer hasn't +changed and if the buffer is not modified. + +ERROR-CALLBACK will be called in case the request has failed. +CANCEL-CALLBACK will be called in case the request is being canceled. +If NO-MERGE is non-nil, don't merge the results but return alist +workspace->result. +CANCEL-TOKEN is the token that can be used to cancel request." + (when cancel-token + (lsp-cancel-request-by-token cancel-token)) + + (if-let ((target-workspaces (lsp--find-workspaces-for body))) + (let* ((start-time (current-time)) + (method (plist-get body :method)) + (id (cl-incf lsp-last-id)) + ;; calculate what are the (hook . local) pairs which will cancel + ;; the request + (hooks (pcase mode + ('alive '((kill-buffer-hook . t))) + ('tick '((kill-buffer-hook . t) (after-change-functions . t))) + ('unchanged '((after-change-functions . t) (post-command-hook . nil))) + ('current '((post-command-hook . nil))))) + (buf (current-buffer)) + ;; note: lambdas in emacs can be compared but we should make sure + ;; that all of the captured arguments are the same - in our case + ;; `lsp--create-request-cancel' will return the same lambda when + ;; called with the same params. + (cleanup-hooks + (lambda () (mapc + (-lambda ((hook . local)) + (if local + (when (buffer-live-p buf) + (with-current-buffer buf + (remove-hook hook + (lsp--create-request-cancel + id target-workspaces hook buf method cancel-callback) + t))) + (remove-hook hook (lsp--create-request-cancel + id target-workspaces hook buf method cancel-callback)))) + hooks) + (remhash cancel-token lsp--cancelable-requests))) + (callback (pcase mode + ((or 'alive 'tick) (lambda (&rest args) + (with-current-buffer buf + (apply callback args)))) + (_ callback))) + (callback (lsp--create-async-callback callback + method + no-merge + target-workspaces)) + (callback (lambda (result) + (lsp--request-cleanup-hooks id) + (funcall callback result))) + (error-callback (lsp--create-async-callback + (or error-callback + (lsp--create-default-error-handler method)) + method + nil + target-workspaces)) + (error-callback (lambda (error) + (funcall callback :error) + (lsp--request-cleanup-hooks id) + (funcall error-callback error))) + (cancel-callback (when cancel-callback + (pcase mode + ((or 'alive 'tick 'unchanged) + (lambda () + (with-current-buffer buf + (funcall cancel-callback)))) + (_ cancel-callback)))) + (body (plist-put body :id id))) + + ;; cancel request in any of the hooks + (mapc (-lambda ((hook . local)) + (add-hook hook + (lsp--create-request-cancel + id target-workspaces hook buf method cancel-callback) + nil local)) + hooks) + (puthash id cleanup-hooks lsp--request-cleanup-hooks) + + (setq lsp--last-active-workspaces target-workspaces) + + (when cancel-token + (puthash cancel-token (cons id target-workspaces) lsp--cancelable-requests)) + + (seq-doseq (workspace target-workspaces) + (when lsp-log-io + (lsp--log-entry-new (lsp--make-log-entry method id + (plist-get body :params) + 'outgoing-req) + workspace)) + (let ((message (lsp--make-message body))) + (puthash id + (list callback error-callback method start-time (current-time)) + (-> workspace + (lsp--workspace-client) + (lsp--client-response-handlers))) + (lsp--send-no-wait message (lsp--workspace-proc workspace)))) + body) + (error "The connected server(s) does not support method %s. +To find out what capabilities support your server use `M-x lsp-describe-session' +and expand the capabilities section" + (plist-get body :method)))) + +;; deprecated, use lsp-request-async. +(defalias 'lsp-send-request-async 'lsp--send-request-async) +(make-obsolete 'lsp-send-request-async 'lsp-request-async "lsp-mode 7.0.1") + +;; Clean up the entire state of lsp mode when Emacs is killed, to get rid of any +;; pending language servers. +(add-hook 'kill-emacs-hook #'lsp--global-teardown) + +(defun lsp--global-teardown () + "Unload working workspaces." + (lsp-foreach-workspace (lsp--shutdown-workspace))) + +(defun lsp--shutdown-workspace (&optional restart) + "Shut down the language server process for ‘lsp--cur-workspace’." + (with-demoted-errors "LSP error: %S" + (let ((lsp-response-timeout 0.5)) + (condition-case _err + (lsp-request "shutdown" lsp--empty-ht) + (error (lsp--error "Timeout while sending shutdown request")))) + (lsp-notify "exit" nil)) + (setf (lsp--workspace-shutdown-action lsp--cur-workspace) (or (and restart 'restart) 'shutdown)) + (lsp--uninitialize-workspace)) + +(defun lsp--uninitialize-workspace () + "Cleanup buffer state. +When a workspace is shut down, by request or from just +disappearing, unset all the variables related to it." + (let ((proc (lsp--workspace-cmd-proc lsp--cur-workspace)) + (buffers (lsp--workspace-buffers lsp--cur-workspace))) + (when (process-live-p proc) + (kill-process proc)) + (mapc (lambda (buf) + (when (lsp-buffer-live-p buf) + (lsp-with-current-buffer buf + (lsp-managed-mode -1)))) + buffers) + (lsp-diagnostics--workspace-cleanup lsp--cur-workspace))) + +(defun lsp--client-capabilities (&optional custom-capabilities) + "Return the client capabilities appending CUSTOM-CAPABILITIES." + (append + `((workspace . ((workspaceEdit . ((documentChanges . t) + (resourceOperations . ["create" "rename" "delete"]))) + (applyEdit . t) + (symbol . ((symbolKind . ((valueSet . ,(apply 'vector (number-sequence 1 26))))))) + (executeCommand . ((dynamicRegistration . :json-false))) + ,@(when lsp-enable-file-watchers '((didChangeWatchedFiles . ((dynamicRegistration . t))))) + (workspaceFolders . t) + (configuration . t) + ,@(when lsp-semantic-tokens-enable '((semanticTokens . ((refreshSupport . t))))) + ,@(when lsp-lens-enable '((codeLens . ((refreshSupport . :json-false))))) + (fileOperations . ((didCreate . :json-false) + (willCreate . :json-false) + (didRename . :json-false) + (willRename . :json-false) + (didDelete . :json-false) + (willDelete . :json-false))))) + (textDocument . ((declaration . ((linkSupport . t))) + (definition . ((linkSupport . t))) + (implementation . ((linkSupport . t))) + (typeDefinition . ((linkSupport . t))) + (synchronization . ((willSave . t) (didSave . t) (willSaveWaitUntil . t))) + (documentSymbol . ((symbolKind . ((valueSet . ,(apply 'vector (number-sequence 1 26))))) + (hierarchicalDocumentSymbolSupport . t))) + (formatting . ((dynamicRegistration . t))) + (rangeFormatting . ((dynamicRegistration . t))) + ,@(when (and lsp-semantic-tokens-enable + (boundp 'lsp-semantic-tokens-capabilities)) + lsp-semantic-tokens-capabilities) + (rename . ((dynamicRegistration . t) (prepareSupport . t))) + (codeAction . ((dynamicRegistration . t) + (isPreferredSupport . t) + (codeActionLiteralSupport . ((codeActionKind . ((valueSet . ["" + "quickfix" + "refactor" + "refactor.extract" + "refactor.inline" + "refactor.rewrite" + "source" + "source.organizeImports"]))))) + (resolveSupport . ((properties . ["edit" "command"]))) + (dataSupport . t))) + (completion . ((completionItem . ((snippetSupport . ,(cond + ((and lsp-enable-snippet (not (featurep 'yasnippet)) t) + (lsp--warn (concat + "Yasnippet is not installed, but `lsp-enable-snippet' is set to `t'. " + "You must either install yasnippet, or disable snippet support.")) + :json-false) + (lsp-enable-snippet t) + (t :json-false))) + (documentationFormat . ["markdown" "plaintext"]) + ;; Remove this after jdtls support resolveSupport + (resolveAdditionalTextEditsSupport . t) + (insertReplaceSupport . t) + (resolveSupport + . ((properties . ["documentation" + "details" + "additionalTextEdits" + "command"]))) + (insertTextModeSupport . ((valueSet . [1 2]))))) + (contextSupport . t))) + (signatureHelp . ((signatureInformation . ((parameterInformation . ((labelOffsetSupport . t))))))) + (documentLink . ((dynamicRegistration . t) + (tooltipSupport . t))) + (hover . ((contentFormat . ["markdown" "plaintext"]))) + (foldingRange . ,(when lsp-enable-folding + `((dynamicRegistration . t) + ,@(when lsp-folding-range-limit + `((rangeLimit . ,lsp-folding-range-limit))) + ,@(when lsp-folding-line-folding-only + `((lineFoldingOnly . t)))))) + (callHierarchy . ((dynamicRegistration . :json-false))) + (publishDiagnostics . ((relatedInformation . t) + (tagSupport . ((valueSet . [1 2]))) + (versionSupport . t))) + (moniker . nil) + (linkedEditingRange . nil))) + (window . ((workDoneProgress . t) + (showMessage . nil) + (showDocument . nil)))) + custom-capabilities)) + +(defun lsp-find-roots-for-workspace (workspace session) + "Get all roots for the WORKSPACE." + (-filter #'identity (ht-map (lambda (folder workspaces) + (when (-contains? workspaces workspace) + folder)) + (lsp-session-folder->servers session)))) + +(defun lsp-session-watches (&optional session) + "Get watches created for SESSION." + (or (gethash "__watches" (lsp-session-metadata (or session (lsp-session)))) + (-let [res (make-hash-table :test 'equal)] + (puthash "__watches" res (lsp-session-metadata (or session (lsp-session)))) + res))) + +(defun lsp--file-process-event (session root-folder event) + "Process file event." + (let* ((changed-file (cl-third event)) + (rel-changed-file (f-relative changed-file root-folder)) + (event-numeric-kind (alist-get (cl-second event) lsp--file-change-type)) + (bit-position (1- event-numeric-kind)) + (watch-bit (ash 1 bit-position))) + (->> + session + lsp-session-folder->servers + (gethash root-folder) + (seq-do (lambda (workspace) + (when (->> + workspace + lsp--workspace-registered-server-capabilities + (-any? + (lambda (capability) + (and + (equal (lsp--registered-capability-method capability) + "workspace/didChangeWatchedFiles") + (->> + capability + lsp--registered-capability-options + (lsp:did-change-watched-files-registration-options-watchers) + (seq-find + (-lambda ((&FileSystemWatcher :glob-pattern :kind?)) + (when (or (null kind?) + (> (logand kind? watch-bit) 0)) + (-let [regexes (lsp-glob-to-regexps glob-pattern)] + (-any? (lambda (re) + (or (string-match re changed-file) + (string-match re rel-changed-file))) + regexes)))))))))) + (with-lsp-workspace workspace + (lsp-notify + "workspace/didChangeWatchedFiles" + `((changes . [((type . ,event-numeric-kind) + (uri . ,(lsp--path-to-uri changed-file)))])))))))))) + +(lsp-defun lsp--server-register-capability ((&Registration :method :id :register-options?)) + "Register capability REG." + (when (and lsp-enable-file-watchers + (equal method "workspace/didChangeWatchedFiles")) + (-let* ((created-watches (lsp-session-watches (lsp-session))) + (root-folders (cl-set-difference + (lsp-find-roots-for-workspace lsp--cur-workspace (lsp-session)) + (ht-keys created-watches)))) + ;; create watch for each root folder without such + (dolist (folder root-folders) + (let* ((watch (make-lsp-watch :root-directory folder)) + (ignored-things (lsp--get-ignored-regexes-for-workspace-root folder)) + (ignored-files-regex-list (car ignored-things)) + (ignored-directories-regex-list (cadr ignored-things))) + (puthash folder watch created-watches) + (lsp-watch-root-folder (file-truename folder) + (-partial #'lsp--file-process-event (lsp-session) folder) + ignored-files-regex-list + ignored-directories-regex-list + watch + t))))) + + (push + (make-lsp--registered-capability :id id :method method :options register-options?) + (lsp--workspace-registered-server-capabilities lsp--cur-workspace))) + +(defmacro lsp--with-workspace-temp-buffer (workspace-root &rest body) + "With a temp-buffer under `WORKSPACE-ROOT' and evaluate `BODY', useful to access dir-local variables." + (declare (indent 1) (debug t)) + `(with-temp-buffer + ;; Set the buffer's name to something under the root so that we can hack the local variables + ;; This file doesn't need to exist and will not be created due to this. + (setq-local buffer-file-name (expand-file-name "lsp-mode-temp" (expand-file-name ,workspace-root))) + (hack-local-variables) + (prog1 ,@body + (setq-local buffer-file-name nil)))) + +(defun lsp--get-ignored-regexes-for-workspace-root (workspace-root) + "Return a list of the form (lsp-file-watch-ignored-files lsp-file-watch-ignored-directories) for the given WORKSPACE-ROOT." + ;; The intent of this function is to provide per-root workspace-level customization of the + ;; lsp-file-watch-ignored-directories and lsp-file-watch-ignored-files variables. + (lsp--with-workspace-temp-buffer workspace-root + (list lsp-file-watch-ignored-files (lsp-file-watch-ignored-directories)))) + + +(defun lsp--cleanup-hanging-watches () + "Cleanup watches in case there are no more workspaces that are interested +in that particular folder." + (let* ((session (lsp-session)) + (watches (lsp-session-watches session))) + (dolist (watched-folder (ht-keys watches)) + (when (-none? (lambda (workspace) + (with-lsp-workspace workspace + (lsp--registered-capability "workspace/didChangeWatchedFiles"))) + (gethash watched-folder (lsp-session-folder->servers (lsp-session)))) + (lsp-log "Cleaning up watches for folder %s. There is no workspace watching this folder..." watched-folder) + (lsp-kill-watch (gethash watched-folder watches)) + (remhash watched-folder watches))))) + +(lsp-defun lsp--server-unregister-capability ((&Unregistration :id :method)) + "Unregister capability UNREG." + (setf (lsp--workspace-registered-server-capabilities lsp--cur-workspace) + (seq-remove (lambda (e) (equal (lsp--registered-capability-id e) id)) + (lsp--workspace-registered-server-capabilities lsp--cur-workspace))) + (when (equal method "workspace/didChangeWatchedFiles") + (lsp--cleanup-hanging-watches))) + +(defun lsp--server-capabilities () + "Return the capabilities of the language server associated with the buffer." + (->> (lsp-workspaces) + (-keep #'lsp--workspace-server-capabilities) + (apply #'lsp-merge))) + +(defun lsp--send-open-close-p () + "Return whether open and close notifications should be sent to the server." + (let ((sync (lsp:server-capabilities-text-document-sync? (lsp--server-capabilities)))) + (or (memq sync '(1 2)) + (lsp:text-document-sync-options-open-close? sync)))) + +(defun lsp--send-will-save-p () + "Return whether willSave notifications should be sent to the server." + (-> (lsp--server-capabilities) + (lsp:server-capabilities-text-document-sync?) + (lsp:text-document-sync-options-will-save?))) + +(defun lsp--send-will-save-wait-until-p () + "Return whether willSaveWaitUntil notifications should be sent to the server." + (-> (lsp--server-capabilities) + (lsp:server-capabilities-text-document-sync?) + (lsp:text-document-sync-options-will-save-wait-until?))) + +(defun lsp--send-did-save-p () + "Return whether didSave notifications should be sent to the server." + (let ((sync (lsp:server-capabilities-text-document-sync? (lsp--server-capabilities)))) + (or (memq sync '(1 2)) + (lsp:text-document-sync-options-save? sync)))) + +(defun lsp--save-include-text-p () + "Return whether save notifications should include the text document's contents." + (->> (lsp--server-capabilities) + (lsp:server-capabilities-text-document-sync?) + (lsp:text-document-sync-options-save?) + (lsp:text-document-save-registration-options-include-text?))) + +(declare-function project-roots "ext:project" (project) t) +(declare-function project-root "ext:project" (project) t) + +(defun lsp--suggest-project-root () + "Get project root." + (or + (when (featurep 'projectile) (condition-case nil + (projectile-project-root) + (error nil))) + (when (featurep 'project) + (when-let ((project (project-current))) + (if (fboundp 'project-root) + (project-root project) + (car (with-no-warnings + (project-roots project)))))) + default-directory)) + +(defun lsp--read-from-file (file) + "Read FILE content." + (when (file-exists-p file) + (cl-first (read-from-string (f-read-text file 'utf-8))))) + +(defun lsp--persist (file-name to-persist) + "Persist TO-PERSIST in FILE-NAME. + +This function creates the parent directories if they don't exist +yet." + (let ((print-length nil) + (print-level nil)) + ;; Create all parent directories: + (apply #'f-mkdir (f-split (f-parent file-name))) + (f-write-text (prin1-to-string to-persist) 'utf-8 file-name))) + +(defun lsp-workspace-folders-add (project-root) + "Add PROJECT-ROOT to the list of workspace folders." + (interactive + (list (read-directory-name "Select folder to add: " + (or (lsp--suggest-project-root) default-directory) nil t))) + (cl-pushnew (lsp-f-canonical project-root) + (lsp-session-folders (lsp-session)) :test 'equal) + (lsp--persist-session (lsp-session)) + + (run-hook-with-args 'lsp-workspace-folders-changed-functions (list project-root) nil)) + +(defun lsp-workspace-folders-remove (project-root) + "Remove PROJECT-ROOT from the list of workspace folders." + (interactive (list (completing-read "Select folder to remove: " + (lsp-session-folders (lsp-session)) + nil t nil nil + (lsp-find-session-folder (lsp-session) default-directory)))) + + (setq project-root (lsp-f-canonical project-root)) + + ;; send remove folder to each multiroot workspace associated with the folder + (dolist (wks (->> (lsp-session) + (lsp-session-folder->servers) + (gethash project-root) + (--filter (lsp--client-multi-root (lsp--workspace-client it))))) + (with-lsp-workspace wks + (lsp-notify "workspace/didChangeWorkspaceFolders" + (lsp-make-did-change-workspace-folders-params + :event (lsp-make-workspace-folders-change-event + :removed (vector (lsp-make-workspace-folder + :uri (lsp--path-to-uri project-root) + :name (f-filename project-root))) + :added []))))) + + ;; turn off servers in the removed directory + (let* ((session (lsp-session)) + (folder->servers (lsp-session-folder->servers session)) + (server-id->folders (lsp-session-server-id->folders session)) + (workspaces (gethash project-root folder->servers))) + + (remhash project-root folder->servers) + + ;; turn off the servers without root folders + (dolist (workspace workspaces) + (when (--none? (-contains? it workspace) (ht-values folder->servers)) + (lsp--info "Shutdown %s since folder %s is removed..." + (lsp--workspace-print workspace) project-root) + (with-lsp-workspace workspace (lsp--shutdown-workspace)))) + + (setf (lsp-session-folders session) + (-remove-item project-root (lsp-session-folders session))) + + (ht-aeach (puthash key + (-remove-item project-root value) + server-id->folders) + server-id->folders) + (lsp--persist-session (lsp-session))) + + (run-hook-with-args 'lsp-workspace-folders-changed-functions nil (list project-root))) + +(defun lsp-workspace-blacklist-remove (project-root) + "Remove PROJECT-ROOT from the workspace blacklist." + (interactive (list (completing-read "Select folder to remove:" + (lsp-session-folders-blacklist (lsp-session)) + nil t))) + (setf (lsp-session-folders-blacklist (lsp-session)) + (delete project-root + (lsp-session-folders-blacklist (lsp-session)))) + (lsp--persist-session (lsp-session))) + +(define-obsolete-function-alias 'lsp-workspace-folders-switch + 'lsp-workspace-folders-open "lsp-mode 6.1") + +(defun lsp-workspace-folders-open (project-root) + "Open the directory located at PROJECT-ROOT" + (interactive (list (completing-read "Open folder: " + (lsp-session-folders (lsp-session)) + nil t))) + (find-file project-root)) + +(defun lsp--maybe-enable-signature-help (trigger-characters) + (let ((ch last-command-event)) + (when (cl-find ch trigger-characters :key #'string-to-char) + (lsp-signature-activate)))) + +(defun lsp--on-type-formatting-handler-create () + (when-let ((provider (lsp--capability :documentOnTypeFormattingProvider))) + (-let [(&DocumentOnTypeFormattingOptions :more-trigger-character? + :first-trigger-character) provider] + (lambda () + (lsp--on-type-formatting first-trigger-character + more-trigger-character?))))) + +(defun lsp--update-on-type-formatting-hook (&optional cleanup?) + (let ((on-type-formatting-handler (lsp--on-type-formatting-handler-create))) + (cond + ((and lsp-enable-on-type-formatting on-type-formatting-handler (not cleanup?)) + (add-hook 'post-self-insert-hook on-type-formatting-handler nil t)) + ((or cleanup? + (not lsp-enable-on-type-formatting)) + (remove-hook 'post-self-insert-hook on-type-formatting-handler t))))) + +(defun lsp--signature-help-handler-create () + (-when-let ((&SignatureHelpOptions? :trigger-characters?) + (lsp--capability :signatureHelpProvider)) + (lambda () + (lsp--maybe-enable-signature-help trigger-characters?)))) + +(defun lsp--update-signature-help-hook (&optional cleanup?) + (let ((signature-help-handler (lsp--signature-help-handler-create))) + (cond + ((and (or (equal lsp-signature-auto-activate t) + (memq :on-trigger-char lsp-signature-auto-activate)) + signature-help-handler) + (add-hook 'post-self-insert-hook signature-help-handler nil t)) + + ((or cleanup? + (not (or (equal lsp-signature-auto-activate t) + (memq :on-trigger-char lsp-signature-auto-activate)))) + (remove-hook 'post-self-insert-hook signature-help-handler t))))) + +(defun lsp--after-set-visited-file-name () + (lsp-disconnect) + (lsp)) + +(define-minor-mode lsp-managed-mode + "Mode for source buffers managed by lsp-mode." + :lighter nil + (cond + (lsp-managed-mode + (when (lsp-feature? "textDocument/hover") + (add-function :before-until (local 'eldoc-documentation-function) #'lsp-eldoc-function) + (eldoc-mode 1)) + + (add-hook 'after-change-functions #'lsp-on-change nil t) + (add-hook 'after-revert-hook #'lsp-on-revert nil t) + (add-hook 'after-save-hook #'lsp-on-save nil t) + (add-hook 'auto-save-hook #'lsp--on-auto-save nil t) + (add-hook 'before-change-functions #'lsp-before-change nil t) + (add-hook 'before-save-hook #'lsp--before-save nil t) + (add-hook 'kill-buffer-hook #'lsp--text-document-did-close nil t) + (add-hook 'post-command-hook #'lsp--post-command nil t) + + (lsp--update-on-type-formatting-hook) + (lsp--update-signature-help-hook) + + (when lsp-enable-xref + (add-hook 'xref-backend-functions #'lsp--xref-backend nil t)) + + (lsp-configure-buffer) + + ;; make sure we turn off lsp-mode in case major mode changes, because major + ;; mode change will wipe the buffer locals. + (add-hook 'change-major-mode-hook #'lsp-disconnect nil t) + (add-hook 'after-set-visited-file-name-hook #'lsp--after-set-visited-file-name nil t) + + (let ((buffer (lsp-current-buffer))) + (run-with-idle-timer + 0.0 nil + (lambda () + (when (lsp-buffer-live-p buffer) + (lsp-with-current-buffer buffer + (lsp--on-change-debounce buffer) + (lsp--on-idle buffer))))))) + (t + (lsp-unconfig-buffer) + (remove-function (local 'eldoc-documentation-function) #'lsp-eldoc-function) + + (remove-hook 'post-command-hook #'lsp--post-command t) + (remove-hook 'after-change-functions #'lsp-on-change t) + (remove-hook 'after-revert-hook #'lsp-on-revert t) + (remove-hook 'after-save-hook #'lsp-on-save t) + (remove-hook 'auto-save-hook #'lsp--on-auto-save t) + (remove-hook 'before-change-functions #'lsp-before-change t) + (remove-hook 'before-save-hook #'lsp--before-save t) + (remove-hook 'kill-buffer-hook #'lsp--text-document-did-close t) + + (lsp--update-on-type-formatting-hook :cleanup) + (lsp--update-signature-help-hook :cleanup) + + (when lsp--on-idle-timer + (cancel-timer lsp--on-idle-timer) + (setq lsp--on-idle-timer nil)) + + (remove-hook 'lsp-on-idle-hook #'lsp--document-links t) + (remove-hook 'lsp-on-idle-hook #'lsp--document-highlight t) + + (lsp--remove-overlays 'lsp-highlight) + (lsp--remove-overlays 'lsp-links) + + (remove-hook 'xref-backend-functions #'lsp--xref-backend t) + (remove-hook 'change-major-mode-hook #'lsp-disconnect t) + (remove-hook 'after-set-visited-file-name-hook #'lsp--after-set-visited-file-name t) + (setq-local lsp-buffer-uri nil)))) + +(defun lsp-configure-buffer () + "Configure LSP features for current buffer." + ;; make sure the core is running in the context of all available workspaces + ;; to avoid misconfiguration in case we are running in `with-lsp-workspace' context + (let ((lsp--buffer-workspaces (cond + (lsp--buffer-workspaces) + (lsp--cur-workspace (list lsp--cur-workspace)))) + lsp--cur-workspace) + (when lsp-auto-configure + (when (and lsp-enable-text-document-color + (lsp-feature? "textDocument/documentColor")) + (add-hook 'lsp-on-change-hook #'lsp--document-color nil t)) + + (when (and lsp-enable-imenu + (lsp-feature? "textDocument/documentSymbol")) + (lsp-enable-imenu)) + + (when (and lsp-enable-indentation + (lsp-feature? "textDocument/rangeFormatting")) + (setq-local indent-region-function #'lsp-format-region)) + + (when (and lsp-enable-symbol-highlighting + (lsp-feature? "textDocument/documentHighlight")) + (add-hook 'lsp-on-idle-hook #'lsp--document-highlight nil t)) + + (when (and lsp-enable-links + (lsp-feature? "textDocument/documentLink")) + (add-hook 'lsp-on-idle-hook #'lsp--document-links nil t)) + + (when (and lsp-enable-dap-auto-configure + (functionp 'dap-mode)) + (dap-auto-configure-mode 1))) + (run-hooks 'lsp-configure-hook))) + +(defun lsp-unconfig-buffer () + "Unconfigure LSP features for buffer." + (run-hooks 'lsp-unconfigure-hook) + + (lsp--remove-overlays 'lsp-color) + (when (eq indent-region-function #'lsp-format-region) + (setq-local indent-region-function nil)) + (remove-hook 'lsp-on-change-hook #'lsp--document-color t) + (remove-hook 'lsp-on-idle-hook #'lsp--document-highlight t) + (remove-hook 'lsp-on-idle-hook #'lsp--document-links t)) + +(defun lsp--buffer-content () + (lsp-save-restriction-and-excursion + (or (lsp-virtual-buffer-call :buffer-string) + (buffer-substring-no-properties (point-min) + (point-max))))) + +(defun lsp--text-document-did-open () + "'document/didOpen' event." + (run-hooks 'lsp-before-open-hook) + (setq lsp--cur-version (or lsp--cur-version 0)) + (cl-pushnew (lsp-current-buffer) (lsp--workspace-buffers lsp--cur-workspace)) + (lsp-notify + "textDocument/didOpen" + (list :textDocument + (list :uri (lsp--buffer-uri) + :languageId (lsp-buffer-language) + :version lsp--cur-version + :text (lsp--buffer-content)))) + + (lsp-managed-mode 1) + + (run-hooks 'lsp-after-open-hook) + (when-let ((client (-some-> lsp--cur-workspace (lsp--workspace-client)))) + (-some-> (lsp--client-after-open-fn client) + (funcall)) + (-some-> (format "lsp-%s-after-open-hook" (lsp--client-server-id client)) + (intern-soft) + (run-hooks)))) + +(defun lsp--text-document-identifier () + "Make TextDocumentIdentifier." + (list :uri (lsp--buffer-uri))) + +(defun lsp--versioned-text-document-identifier () + "Make VersionedTextDocumentIdentifier." + (plist-put (lsp--text-document-identifier) :version lsp--cur-version)) + +(defun lsp--cur-line (&optional point) + (1- (line-number-at-pos point))) + +(defun lsp--cur-position () + "Make a Position object for the current point." + (or (lsp-virtual-buffer-call :cur-position) + (lsp-save-restriction-and-excursion + (list :line (lsp--cur-line) + :character (- (point) (line-beginning-position)))))) + +(defun lsp--point-to-position (point) + "Convert POINT to Position." + (lsp-save-restriction-and-excursion + (goto-char point) + (lsp--cur-position))) + +(defun lsp--range (start end) + "Make Range body from START and END." + ;; make sure start and end are Position objects + (list :start start :end end)) + +(defun lsp--region-to-range (start end) + "Make Range object for the current region." + (lsp--range (lsp--point-to-position start) + (lsp--point-to-position end))) + +(defun lsp--region-or-line () + "The active region or the current line." + (if (use-region-p) + (lsp--region-to-range (region-beginning) (region-end)) + (lsp--region-to-range (point-at-bol) (point-at-eol)))) + +(defun lsp--check-document-changes-version (document-changes) + "Verify that DOCUMENT-CHANGES have the proper version." + (unless (seq-every-p + (-lambda ((&TextDocumentEdit :text-document)) + (or + (not text-document) + (let* ((filename (-> text-document + lsp:versioned-text-document-identifier-uri + lsp--uri-to-path)) + (version (lsp:versioned-text-document-identifier-version? text-document))) + (with-current-buffer (find-file-noselect filename) + (or (null version) (zerop version) + (equal version lsp--cur-version)))))) + document-changes) + (error "Document changes cannot be applied"))) + +(defun lsp--apply-workspace-edit (workspace-edit &optional operation) + "Apply the WorkspaceEdit object WORKSPACE-EDIT. +OPERATION is symbol representing the source of this text edit." + (-let (((&WorkspaceEdit :document-changes? :changes?) workspace-edit)) + (if-let ((document-changes (seq-reverse document-changes?))) + (progn + (lsp--check-document-changes-version document-changes) + (->> document-changes + (seq-filter (-lambda ((&CreateFile :kind)) + (or (not kind) (equal kind "edit")))) + (seq-do (lambda (change) (lsp--apply-text-document-edit change operation)))) + (->> document-changes + (seq-filter (-lambda ((&CreateFile :kind)) + (not (or (not kind) (equal kind "edit"))))) + (seq-do (lambda (change) (lsp--apply-text-document-edit change operation))))) + (lsp-map + (lambda (uri text-edits) + (with-current-buffer (-> uri lsp--uri-to-path find-file-noselect) + (lsp--apply-text-edits text-edits operation))) + changes?)))) + +(defmacro lsp-with-filename (file &rest body) + "Execute BODY with FILE as a context. +Need to handle the case when FILE indicates virtual buffer." + (declare (indent 1) (debug t)) + `(if-let ((lsp--virtual-buffer (get-text-property 0 'lsp-virtual-buffer ,file))) + (lsp-with-current-buffer lsp--virtual-buffer + ,@body) + ,@body)) + +(defun lsp--apply-text-document-edit (edit &optional operation) + "Apply the TextDocumentEdit object EDIT. +OPERATION is symbol representing the source of this text edit. +If the file is not being visited by any buffer, it is opened with +`find-file-noselect'. +Because lsp-mode does not store previous document versions, the edit is only +applied if the version of the textDocument matches the version of the +corresponding file. + +interface TextDocumentEdit { + textDocument: VersionedTextDocumentIdentifier; + edits: TextEdit[]; +}" + (pcase (lsp:edit-kind edit) + ("create" (-let* (((&CreateFile :uri :options?) edit) + (file-name (lsp--uri-to-path uri))) + (mkdir (f-dirname file-name) t) + (f-touch file-name) + (when (lsp:create-file-options-overwrite? options?) + (f-write-text "" nil file-name)))) + ("delete" (-let (((&DeleteFile :uri :options? (&DeleteFileOptions? :recursive?)) edit)) + (f-delete (lsp--uri-to-path uri) recursive?))) + ("rename" (-let* (((&RenameFile :old-uri :new-uri :options? (&RenameFileOptions? :overwrite?)) edit) + (old-file-name (lsp--uri-to-path old-uri)) + (new-file-name (lsp--uri-to-path new-uri)) + (buf (find-buffer-visiting old-file-name))) + (when buf + (lsp-with-current-buffer buf + (save-buffer) + (lsp--text-document-did-close))) + (mkdir (f-dirname new-file-name) t) + (rename-file old-file-name new-file-name overwrite?) + (when buf + (lsp-with-current-buffer buf + (set-buffer-modified-p nil) + (setq lsp-buffer-uri nil) + (set-visited-file-name new-file-name) + (lsp))))) + (_ (let ((file-name (->> edit + (lsp:text-document-edit-text-document) + (lsp:versioned-text-document-identifier-uri) + (lsp--uri-to-path)))) + (lsp-with-current-buffer (find-buffer-visiting file-name) + (lsp-with-filename file-name + (lsp--apply-text-edits (lsp:text-document-edit-edits edit) operation))))))) + +(lsp-defun lsp--position-compare ((&Position :line left-line + :character left-character) + (&Position :line right-line + :character right-character)) + "Return t if position LEFT is greater than RIGHT." + (if (= left-line right-line) + (> left-character right-character) + (> left-line right-line))) + +(lsp-defun lsp-point-in-range? (position (&Range :start :end)) + "Returns if POINT is in RANGE." + (not (or (lsp--position-compare start position) + (lsp--position-compare position end)))) + +(lsp-defun lsp--position-equal ((&Position :line left-line + :character left-character) + (&Position :line right-line + :character right-character)) + "Return whether LEFT and RIGHT positions are equal." + (and (= left-line right-line) + (= left-character right-character))) + +(lsp-defun lsp--text-edit-sort-predicate ((&TextEdit :range (&Range :start left-start :end left-end)) + (&TextEdit :range (&Range :start right-start :end right-end))) + (if (lsp--position-equal left-start right-start) + (lsp--position-compare left-end right-end) + (lsp--position-compare left-start right-start))) + +(lsp-defun lsp--apply-text-edit ((edit &as &TextEdit :range (&RangeToPoint :start :end) :new-text)) + "Apply the edits described in the TextEdit object in TEXT-EDIT." + ;; We sort text edits so as to apply edits that modify latter parts of the + ;; document first. Furthermore, because the LSP spec dictates that: + ;; "If multiple inserts have the same position, the order in the array + ;; defines which edit to apply first." + ;; We reverse the initial list and sort stably to make sure the order among + ;; edits with the same position is preserved. + (setq new-text (s-replace "\r" "" (or new-text ""))) + (lsp:set-text-edit-new-text edit new-text) + (goto-char start) + (delete-region start end) + (insert new-text)) + +;; WORKAROUND: typescript-language might send -1 when applying code actions. +;; see https://github.com/emacs-lsp/lsp-mode/issues/1582 +(lsp-defun lsp--fix-point ((point &as &Position :character :line)) + (-doto point + (lsp:set-position-line (max 0 line)) + (lsp:set-position-character (max 0 character)))) + +(lsp-defun lsp--apply-text-edit-replace-buffer-contents ((edit &as + &TextEdit + :range (&Range :start :end) + :new-text)) + "Apply the edits described in the TextEdit object in TEXT-EDIT. +The method uses `replace-buffer-contents'." + (setq new-text (s-replace "\r" "" (or new-text ""))) + (lsp:set-text-edit-new-text edit new-text) + (-let* ((source (current-buffer)) + ((beg . end) (lsp--range-to-region (lsp-make-range :start (lsp--fix-point start) + :end (lsp--fix-point end))))) + (with-temp-buffer + (insert new-text) + (let ((temp (current-buffer))) + (with-current-buffer source + (save-excursion + (save-restriction + (narrow-to-region beg end) + + ;; On emacs versions < 26.2, + ;; `replace-buffer-contents' is buggy - it calls + ;; change functions with invalid arguments - so we + ;; manually call the change functions here. + ;; + ;; See emacs bugs #32237, #32278: + ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32237 + ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32278 + (let ((inhibit-modification-hooks t) + (length (- end beg))) + (run-hook-with-args 'before-change-functions + beg end) + (replace-buffer-contents temp) + (run-hook-with-args 'after-change-functions + beg (+ beg (length new-text)) + length))))))))) + +(defun lsp--to-yasnippet-snippet (snippet) + "Convert LSP SNIPPET to yasnippet snippet." + ;; LSP snippet doesn't escape "{" and "`", but yasnippet requires escaping it. + (replace-regexp-in-string (rx (or bos (not (any "$" "\\"))) (group (or "{" "`"))) + (rx "\\" (backref 1)) + snippet + nil nil 1)) + +(defvar-local lsp-enable-relative-indentation nil + "Enable relative indentation when insert texts, snippets ... +from language server.") + +(defun lsp--expand-snippet (snippet &optional start end expand-env) + "Wrapper of `yas-expand-snippet' with all of it arguments. +The snippet will be convert to LSP style and indent according to +LSP server result." + (let* ((inhibit-field-text-motion t) + (yas-wrap-around-region nil) + (yas-indent-line 'none) + (yas-also-auto-indent-first-line nil)) + (yas-expand-snippet + (lsp--to-yasnippet-snippet snippet) + start end expand-env))) + +(defun lsp--indent-lines (start end &optional insert-text-mode?) + "Indent from START to END based on INSERT-TEXT-MODE? value. +- When INSERT-TEXT-MODE? is provided + - if it's `lsp/insert-text-mode-as-it', do no editor indentation. + - if it's `lsp/insert-text-mode-adjust-indentation', adjust leading + whitespaces to match the line where text is inserted. +- When it's not provided, using `indent-line-function' for each line." + (save-excursion + (goto-char end) + (let* ((end-line (line-number-at-pos)) + (offset (save-excursion + (goto-char start) + (current-indentation))) + (indent-line-function + (cond ((equal insert-text-mode? lsp/insert-text-mode-as-it) + #'ignore) + ((or (equal insert-text-mode? lsp/insert-text-mode-adjust-indentation) + lsp-enable-relative-indentation + ;; Indenting snippets is extremely slow in `org-mode' buffers + ;; since it has to calculate indentation based on SRC block + ;; position. Thus we use relative indentation as default. + (derived-mode-p 'org-mode)) + (lambda () (save-excursion + (beginning-of-line) + (indent-to-column offset)))) + (t indent-line-function)))) + (goto-char start) + (while (and (equal (forward-line 1) 0) + (<= (line-number-at-pos) end-line)) + (funcall indent-line-function))))) + +(defun lsp--apply-text-edits (edits &optional operation) + "Apply the EDITS described in the TextEdit[] object. +OPERATION is symbol representing the source of this text edit." + (unless (seq-empty-p edits) + (atomic-change-group + (run-hooks 'lsp-before-apply-edits-hook) + (let* ((change-group (prepare-change-group)) + (howmany (length edits)) + (message (format "Applying %s edits to `%s' ..." howmany (current-buffer))) + (_ (lsp--info message)) + (reporter (make-progress-reporter message 0 howmany)) + (done 0) + (apply-edit (if (not lsp--virtual-buffer) + #'lsp--apply-text-edit-replace-buffer-contents + #'lsp--apply-text-edit))) + (unwind-protect + (->> edits + (nreverse) + (seq-sort #'lsp--text-edit-sort-predicate) + (mapc (lambda (edit) + (progress-reporter-update reporter (cl-incf done)) + (funcall apply-edit edit) + (when (lsp:snippet-text-edit-insert-text-format? edit) + (-when-let ((&SnippetTextEdit :range (&RangeToPoint :start) + :insert-text-format? :new-text) edit) + (when (eq insert-text-format? lsp/insert-text-format-snippet) + ;; No `save-excursion' needed since expand snippet will change point anyway + (goto-char (+ start (length new-text))) + (lsp--indent-lines start (point)) + (lsp--expand-snippet new-text start (point))))) + (run-hook-with-args 'lsp-after-apply-edits-hook operation)))) + (undo-amalgamate-change-group change-group) + (progress-reporter-done reporter)))))) + +(defun lsp--create-apply-text-edits-handlers () + "Create (handler cleanup-fn) for applying text edits in async request. +Only works when mode is 'tick or 'alive." + (let* (first-edited + (func (lambda (start &rest _) + (setq first-edited (if first-edited + (min start first-edited) + start))))) + (add-hook 'before-change-functions func nil t) + (list + (lambda (edits) + (if (and first-edited + (seq-find (-lambda ((&TextEdit :range (&RangeToPoint :end))) + ;; Text edit region is overlapped + (> end first-edited)) + edits)) + (lsp--warn "TextEdits will not be applied since document has been modified before of them.") + (lsp--apply-text-edits edits 'completion-cleanup))) + (lambda () + (remove-hook 'before-change-functions func t))))) + +(defun lsp--capability (cap &optional capabilities) + "Get the value of capability CAP. If CAPABILITIES is non-nil, use them instead." + (when (stringp cap) + (setq cap (intern (concat ":" cap)))) + + (lsp-get (or capabilities + (lsp--server-capabilities)) + cap)) + +(defun lsp--registered-capability (method) + "Check whether there is workspace providing METHOD." + (->> (lsp-workspaces) + (--keep (seq-find (lambda (reg) + (equal (lsp--registered-capability-method reg) method)) + (lsp--workspace-registered-server-capabilities it))) + cl-first)) + +(defvar-local lsp--before-change-vals nil + "Store the positions from the `lsp-before-change' function call, for +validation and use in the `lsp-on-change' function.") + +(defun lsp--text-document-content-change-event (start end length) + "Make a TextDocumentContentChangeEvent body for START to END, of length LENGTH." + ;; So (47 54 0) means add 7 chars starting at pos 47 + ;; must become + ;; {"range":{"start":{"line":5,"character":6} + ;; ,"end" :{"line":5,"character":6}} + ;; ,"rangeLength":0 + ;; ,"text":"\nbb = 5"} + ;; + ;; And (47 47 7) means delete 7 chars starting at pos 47 + ;; must become + ;; {"range":{"start":{"line":6,"character":0} + ;; ,"end" :{"line":7,"character":0}} + ;; ,"rangeLength":7 + ;; ,"text":""} + ;; + ;; (208 221 3) means delete 3 chars starting at pos 208, and replace them with + ;; 13 chars. So it must become + ;; {"range":{"start":{"line":5,"character":8} + ;; ,"end" :{"line":5,"character":11}} + ;; ,"rangeLength":3 + ;; ,"text":"new-chars-xxx"} + ;; + + ;; Adding text: + ;; lsp-before-change:(start,end)=(33,33) + ;; lsp-on-change:(start,end,length)=(33,34,0) + ;; + ;; Changing text: + ;; lsp-before-change:(start,end)=(208,211) + ;; lsp-on-change:(start,end,length)=(208,221,3) + ;; + ;; Deleting text: + ;; lsp-before-change:(start,end)=(19,27) + ;; lsp-on-change:(start,end,length)=(19,19,8) + (if (zerop length) + ;; Adding something only, work from start only + `( :range ,(lsp--range + (lsp--point-to-position start) + (lsp--point-to-position start)) + :rangeLength 0 + :text ,(buffer-substring-no-properties start end)) + + (if (eq start end) + ;; Deleting something only + (if (lsp--bracketed-change-p start length) + ;; The before-change value is bracketed, use it + `( :range ,(lsp--range + (lsp--point-to-position start) + (plist-get lsp--before-change-vals :end-pos)) + :rangeLength ,length + :text "") + ;; If the change is not bracketed, send a full change event instead. + (lsp--full-change-event)) + + ;; Deleting some things, adding others + (if (lsp--bracketed-change-p start length) + ;; The before-change value is valid, use it + `( :range ,(lsp--range + (lsp--point-to-position start) + (plist-get lsp--before-change-vals :end-pos)) + :rangeLength ,length + :text ,(buffer-substring-no-properties start end)) + (lsp--full-change-event))))) + +(defun lsp--bracketed-change-p (start length) + "If the before and after positions are the same, and the length +is the size of the start range, we are probably good." + (-let [(&plist :end before-end :start before-start) lsp--before-change-vals] + (and (eq start before-start) + (eq length (- before-end before-start))))) + +(defun lsp--full-change-event () + `(:text ,(lsp--buffer-content))) + +(defun lsp-before-change (start end) + "Executed before a file is changed. +Added to `before-change-functions'." + ;; Note: + ;; + ;; This variable holds a list of functions to call when Emacs is about to + ;; modify a buffer. Each function gets two arguments, the beginning and end of + ;; the region that is about to change, represented as integers. The buffer + ;; that is about to change is always the current buffer when the function is + ;; called. + ;; + ;; WARNING: + ;; + ;; Do not expect the before-change hooks and the after-change hooks be called + ;; in balanced pairs around each buffer change. Also don't expect the + ;; before-change hooks to be called for every chunk of text Emacs is about to + ;; delete. These hooks are provided on the assumption that Lisp programs will + ;; use either before- or the after-change hooks, but not both, and the + ;; boundaries of the region where the changes happen might include more than + ;; just the actual changed text, or even lump together several changes done + ;; piecemeal. + (save-match-data + (lsp-save-restriction-and-excursion + (setq lsp--before-change-vals + (list :start start + :end end + :end-pos (lsp--point-to-position end)))))) + +(defun lsp--flush-delayed-changes () + (let ((inhibit-quit t)) + (when lsp--delay-timer + (cancel-timer lsp--delay-timer)) + (mapc (-lambda ((workspace buffer document change)) + (with-current-buffer buffer + (with-lsp-workspace workspace + (lsp-notify "textDocument/didChange" + (list :textDocument document + :contentChanges (vector change)))))) + (prog1 (nreverse lsp--delayed-requests) + (setq lsp--delayed-requests nil))))) + +(defun lsp--workspace-sync-method (workspace) + (let* ((sync (-> workspace + (lsp--workspace-server-capabilities) + (lsp:server-capabilities-text-document-sync?)))) + (if (lsp-text-document-sync-options? sync) + (lsp:text-document-sync-options-change? sync) + sync))) + +(defun lsp-on-change (start end length &optional content-change-event-fn) + "Executed when a file is changed. +Added to `after-change-functions'." + ;; Note: + ;; + ;; Each function receives three arguments: the beginning and end of the region + ;; just changed, and the length of the text that existed before the change. + ;; All three arguments are integers. The buffer that has been changed is + ;; always the current buffer when the function is called. + ;; + ;; The length of the old text is the difference between the buffer positions + ;; before and after that text as it was before the change. As for the + ;; changed text, its length is simply the difference between the first two + ;; arguments. + ;; + ;; So (47 54 0) means add 7 chars starting at pos 47 + ;; So (47 47 7) means delete 7 chars starting at pos 47 + (save-match-data + (let ((inhibit-quit t)) + ;; A (revert-buffer) call with the 'preserve-modes parameter (eg, as done + ;; by auto-revert-mode) will cause this handler to get called with a nil + ;; buffer-file-name. We need the buffer-file-name to send notifications; + ;; so we skip handling revert-buffer-caused changes and instead handle + ;; reverts separately in lsp-on-revert + (when (not revert-buffer-in-progress-p) + (cl-incf lsp--cur-version) + (mapc + (lambda (workspace) + (pcase (or lsp-document-sync-method + (lsp--workspace-sync-method workspace)) + (1 + (if lsp-debounce-full-sync-notifications + (setq lsp--delayed-requests + (->> lsp--delayed-requests + (-remove (-lambda ((_ buffer)) + (equal (current-buffer) buffer))) + (cons (list workspace + (current-buffer) + (lsp--versioned-text-document-identifier) + (lsp--full-change-event))))) + (with-lsp-workspace workspace + (lsp-notify "textDocument/didChange" + (list :contentChanges (vector (lsp--full-change-event)) + :textDocument (lsp--versioned-text-document-identifier)))))) + (2 + (with-lsp-workspace workspace + (lsp-notify + "textDocument/didChange" + (list :textDocument (lsp--versioned-text-document-identifier) + :contentChanges (vector + (if content-change-event-fn + (funcall content-change-event-fn start end length) + (lsp--text-document-content-change-event + start end length))))))))) + (lsp-workspaces)) + (when lsp--delay-timer (cancel-timer lsp--delay-timer)) + (setq lsp--delay-timer (run-with-idle-timer + lsp-debounce-full-sync-notifications-interval + nil + #'lsp--flush-delayed-changes)) + ;; force cleanup overlays after each change + (lsp--remove-overlays 'lsp-highlight) + (lsp--after-change (current-buffer)) + (setq lsp--signature-last-index nil + lsp--signature-last nil) + ;; cleanup diagnostics + (when lsp-diagnostic-clean-after-change + (lsp-foreach-workspace + (-let [diagnostics (lsp--workspace-diagnostics lsp--cur-workspace)] + (remhash (lsp--fix-path-casing (buffer-file-name)) diagnostics)))))))) + + + +;; facilities for on change hooks. We do not want to make lsp calls on each +;; change event so we add debounce to avoid flooding the server with events. +;; Additionally, we want to have a mechanism for stopping the server calls in +;; particular cases like, e. g. when performing completion. + +(defvar lsp-inhibit-lsp-hooks nil + "Flag to control.") + +(defcustom lsp-on-change-hook nil + "Hooks to run when buffer has changed." + :type 'hook + :group 'lsp-mode) + +(defcustom lsp-idle-delay 0.500 + "Debounce interval for `after-change-functions'." + :type 'number + :group 'lsp-mode) + +(defcustom lsp-on-idle-hook nil + "Hooks to run after `lsp-idle-delay'." + :type 'hook + :group 'lsp-mode) + +(defun lsp--idle-reschedule (buffer) + (when lsp--on-idle-timer + (cancel-timer lsp--on-idle-timer)) + + (setq lsp--on-idle-timer (run-with-idle-timer + lsp-idle-delay + nil + #'lsp--on-idle + buffer))) + +(defun lsp--post-command () + (lsp--cleanup-highlights-if-needed) + (lsp--idle-reschedule (current-buffer))) + +(defun lsp--on-idle (buffer) + "Start post command loop." + (when (and (buffer-live-p buffer) + (equal buffer (current-buffer)) + (not lsp-inhibit-lsp-hooks) + lsp-managed-mode) + (run-hooks 'lsp-on-idle-hook))) + +(defun lsp--on-change-debounce (buffer) + (when (and (buffer-live-p buffer) + (equal buffer (current-buffer)) + (not lsp-inhibit-lsp-hooks) + lsp-managed-mode) + (run-hooks 'lsp-on-change-hook))) + +(defun lsp--after-change (buffer) + (when lsp--on-change-timer + (cancel-timer lsp--on-change-timer)) + (setq lsp--on-change-timer (run-with-idle-timer + lsp-idle-delay + nil + #'lsp--on-change-debounce + buffer)) + (lsp--idle-reschedule buffer)) + + + +(defun lsp--on-type-formatting (first-trigger-characters more-trigger-characters) + "Self insert handling. +Applies on type formatting." + (let ((ch last-command-event)) + (when (or (eq (string-to-char first-trigger-characters) ch) + (cl-find ch more-trigger-characters :key #'string-to-char)) + (lsp-request-async "textDocument/onTypeFormatting" + (lsp-make-document-on-type-formatting-params + :text-document (lsp--text-document-identifier) + :options (lsp-make-formatting-options + :tab-size (symbol-value (lsp--get-indent-width major-mode)) + :insert-spaces (if indent-tabs-mode :json-false t)) + :ch (char-to-string ch) + :position (lsp--cur-position)) + (lambda (data) (lsp--apply-text-edits data 'format)) + :mode 'tick)))) + + +;; links +(defun lsp--document-links () + (when (lsp-feature? "textDocument/documentLink") + (lsp-request-async + "textDocument/documentLink" + `(:textDocument ,(lsp--text-document-identifier)) + (lambda (links) + (lsp--remove-overlays 'lsp-link) + (seq-do + (-lambda ((link &as &DocumentLink :range (&Range :start :end))) + (-doto (make-button (lsp--position-to-point start) + (lsp--position-to-point end) + 'action (lsp--document-link-keymap link) + 'keymap (let ((map (make-sparse-keymap))) + (define-key map [M-return] 'push-button) + (define-key map [mouse-2] 'push-button) + map) + 'help-echo "mouse-2, M-RET: Visit this link") + (overlay-put 'lsp-link t))) + links)) + :mode 'unchanged))) + +(defun lsp--document-link-handle-target (url) + (let* ((parsed-url (url-generic-parse-url (url-unhex-string url))) + (type (url-type parsed-url))) + (pcase type + ("file" + (find-file (lsp--uri-to-path url)) + (-when-let ((_ line column) (s-match (rx "#" (group (1+ num)) "," (group (1+ num))) url)) + (goto-char (lsp--position-to-point + (lsp-make-position :character (1- (string-to-number column)) + :line (1- (string-to-number line))))))) + ((or "http" "https") (browse-url url)) + (type (if-let ((handler (lsp--get-uri-handler type))) + (funcall handler url) + (signal 'lsp-file-scheme-not-supported (list url))))))) + +(lsp-defun lsp--document-link-keymap ((link &as &DocumentLink :target?)) + (if target? + (lambda (_) + (interactive) + (lsp--document-link-handle-target target?)) + (lambda (_) + (interactive) + (when (lsp:document-link-registration-options-resolve-provider? + (lsp--capability :documentLinkProvider)) + (lsp-request-async + "documentLink/resolve" + link + (-lambda ((&DocumentLink :target?)) + (lsp--document-link-handle-target target?))))))) + + + +(defun lsp-buffer-language () + "Get language corresponding current buffer." + (or (->> lsp-language-id-configuration + (-first (-lambda ((mode-or-pattern . language)) + (cond + ((and (stringp mode-or-pattern) + (s-matches? mode-or-pattern (buffer-file-name))) language) + ((eq mode-or-pattern major-mode) language)))) + cl-rest) + (lsp-warn "Unable to calculate the languageId for buffer `%s'. Take a look at `lsp-language-id-configuration'. The `major-mode' is %s" + (buffer-name) + major-mode))) + +(defun lsp-activate-on (&rest languages) + "Returns language activation function. +The function will return t when the `lsp-buffer-language' returns +one of the LANGUAGES." + (lambda (_file-name _mode) + (-contains? languages (lsp-buffer-language)))) + +(defun lsp-workspace-root (&optional path) + "Find the workspace root for the current file or PATH." + (-when-let* ((file-name (or path (buffer-file-name))) + (file-name (lsp-f-canonical file-name))) + (->> (lsp-session) + (lsp-session-folders) + (--filter (and (lsp--files-same-host it file-name) + (or (lsp-f-ancestor-of? it file-name) + (equal it file-name)))) + (--max-by (> (length it) (length other)))))) + +(defun lsp-on-revert () + "Executed when a file is reverted. +Added to `after-revert-hook'." + (let ((n (buffer-size)) + (revert-buffer-in-progress-p nil)) + (lsp-on-change 0 n n))) + +(defun lsp--text-document-did-close (&optional keep-workspace-alive) + "Executed when the file is closed, added to `kill-buffer-hook'. + +If KEEP-WORKSPACE-ALIVE is non-nil, do not shutdown the workspace +if it's closing the last buffer in the workspace." + (lsp-foreach-workspace + (cl-callf2 delq (lsp-current-buffer) (lsp--workspace-buffers lsp--cur-workspace)) + (with-demoted-errors "Error sending didClose notification in ‘lsp--text-document-did-close’: %S" + (lsp-notify "textDocument/didClose" + `(:textDocument ,(lsp--text-document-identifier)))) + (when (and (not lsp-keep-workspace-alive) + (not keep-workspace-alive) + (not (lsp--workspace-buffers lsp--cur-workspace))) + (lsp--shutdown-workspace)))) + +(defun lsp--will-save-text-document-params (reason) + (list :textDocument (lsp--text-document-identifier) + :reason reason)) + +(defun lsp--before-save () + "Before save handler." + (with-demoted-errors "Error in ‘lsp--before-save’: %S" + (let ((params (lsp--will-save-text-document-params 1))) + (when (lsp--send-will-save-p) + (lsp-notify "textDocument/willSave" params)) + (when (and (lsp--send-will-save-wait-until-p) lsp-before-save-edits) + (let ((lsp-response-timeout 0.1)) + (condition-case nil + (lsp--apply-text-edits + (lsp-request "textDocument/willSaveWaitUntil" + params) + 'before-save) + (error))))))) + +(defun lsp--on-auto-save () + "Handler for auto-save." + (when (lsp--send-will-save-p) + (with-demoted-errors "Error in ‘lsp--on-auto-save’: %S" + (lsp-notify "textDocument/willSave" (lsp--will-save-text-document-params 2))))) + +(defun lsp--text-document-did-save () + "Executed when the file is closed, added to `after-save-hook''." + (when (lsp--send-did-save-p) + (with-demoted-errors "Error on ‘lsp--text-document-did-save: %S’" + (lsp-notify "textDocument/didSave" + `( :textDocument ,(lsp--versioned-text-document-identifier) + ,@(when (lsp--save-include-text-p) + (list :text (lsp--buffer-content)))))))) + +(defun lsp--text-document-position-params (&optional identifier position) + "Make TextDocumentPositionParams for the current point in the current document. +If IDENTIFIER and POSITION are non-nil, they will be used as the document identifier +and the position respectively." + (list :textDocument (or identifier (lsp--text-document-identifier)) + :position (or position (lsp--cur-position)))) + +(defun lsp--get-buffer-diagnostics () + "Return buffer diagnostics." + (gethash (or + (plist-get lsp--virtual-buffer :buffer-file-name) + (lsp--fix-path-casing (buffer-file-name))) + (lsp-diagnostics t))) + +(defun lsp-cur-line-diagnostics () + "Return any diagnostics that apply to the current line." + (-let [(&plist :start (&plist :line start) :end (&plist :line end)) (lsp--region-or-line)] + (cl-coerce (-filter + (-lambda ((&Diagnostic :range (&Range :start (&Position :line)))) + (and (>= line start) (<= line end))) + (lsp--get-buffer-diagnostics)) + 'vector))) + +(defalias 'lsp--cur-line-diagnotics 'lsp-cur-line-diagnostics) + +(defun lsp--extract-line-from-buffer (pos) + "Return the line pointed to by POS (a Position object) in the current buffer." + (let* ((point (lsp--position-to-point pos)) + (inhibit-field-text-motion t)) + (save-excursion + (goto-char point) + (buffer-substring (line-beginning-position) (line-end-position))))) + +(lsp-defun lsp--xref-make-item (filename (&Range :start (start &as &Position :character start-char :line start-line) + :end (end &as &Position :character end-char))) + "Return a xref-item from a RANGE in FILENAME." + (let* ((line (lsp--extract-line-from-buffer start)) + (len (length line))) + (add-face-text-property (max (min start-char len) 0) + (max (min end-char len) 0) + 'highlight t line) + ;; LINE is nil when FILENAME is not being current visited by any buffer. + (xref-make (or line filename) + (xref-make-file-location + filename + (lsp-translate-line (1+ start-line)) + (lsp-translate-column start-char))))) + +(defun lsp--location-uri (loc) + (if (lsp-location? loc) + (lsp:location-uri loc) + (lsp:location-link-target-uri loc))) + +(lsp-defun lsp-goto-location ((loc &as &Location :uri :range (&Range :start))) + "Go to location." + (let ((path (lsp--uri-to-path uri))) + (if (f-exists? path) + (with-current-buffer (find-file path) + (goto-char (lsp--position-to-point start))) + (error "There is no file %s" path)))) + +(defun lsp--location-range (loc) + (if (lsp-location? loc) + (lsp:location-range loc) + (lsp:location-link-target-selection-range loc))) + +(defun lsp--locations-to-xref-items (locations) + "Return a list of `xref-item' given LOCATIONS, which can be of +type Location, LocationLink, Location[] or LocationLink[]." + (setq locations + (pcase locations + ((seq (or (Location) + (LocationLink))) + (append locations nil)) + ((or (Location) + (LocationLink)) + (list locations)))) + + (cl-labels ((get-xrefs-in-file + (file-locs) + (-let [(filename . matches) file-locs] + (condition-case err + (let ((visiting (find-buffer-visiting filename)) + (fn (lambda (loc) + (lsp-with-filename filename + (lsp--xref-make-item filename + (lsp--location-range loc)))))) + (if visiting + (with-current-buffer visiting + (seq-map fn matches)) + (when (file-readable-p filename) + (with-temp-buffer + (insert-file-contents-literally filename) + (seq-map fn matches))))) + (error (lsp-warn "Failed to process xref entry for filename '%s': %s" + filename (error-message-string err))) + (file-error (lsp-warn "Failed to process xref entry, file-error, '%s': %s" + filename (error-message-string err))))))) + + (->> locations + (seq-sort #'lsp--location-before-p) + (seq-group-by (-compose #'lsp--uri-to-path #'lsp--location-uri)) + (seq-map #'get-xrefs-in-file) + (apply #'nconc)))) + +(defun lsp--location-before-p (left right) + "Sort first by file, then by line, then by column." + (let ((left-uri (lsp--location-uri left)) + (right-uri (lsp--location-uri right))) + (if (not (string= left-uri right-uri)) + (string< left-uri right-uri) + (-let (((&Range :start left-start) (lsp--location-range left)) + ((&Range :start right-start) (lsp--location-range right))) + (lsp--position-compare right-start left-start))))) + +(defun lsp--make-reference-params (&optional td-position include-declaration) + "Make a ReferenceParam object. +If TD-POSITION is non-nil, use it as TextDocumentPositionParams object instead. +If INCLUDE-DECLARATION is non-nil, request the server to include declarations." + (let ((json-false :json-false)) + (plist-put (or td-position (lsp--text-document-position-params)) + :context `(:includeDeclaration ,(or include-declaration json-false))))) + +(defun lsp--cancel-request (id) + "Cancel request with ID in all workspaces." + (lsp-foreach-workspace + (->> lsp--cur-workspace lsp--workspace-client lsp--client-response-handlers (remhash id)) + (lsp-notify "$/cancelRequest" `(:id ,id)))) + +(defun lsp-eldoc-function () + "`lsp-mode' eldoc function." + (run-hooks 'lsp-eldoc-hook) + eldoc-last-message) + +(defun lsp--point-on-highlight? () + (-some? (lambda (overlay) + (overlay-get overlay 'lsp-highlight)) + (overlays-at (point)))) + +(defun lsp--cleanup-highlights-if-needed () + (when (and lsp-enable-symbol-highlighting + lsp--have-document-highlights + (not (lsp--point-on-highlight?))) + (lsp--remove-overlays 'lsp-highlight) + (setq lsp--have-document-highlights nil) + (lsp-cancel-request-by-token :highlights))) + +(defvar-local lsp--symbol-bounds-of-last-highlight-invocation nil + "The bounds of the symbol from which `lsp--document-highlight' + most recently requested highlights.") + +(defun lsp--document-highlight () + (let ((curr-sym-bounds (bounds-of-thing-at-point 'symbol))) + (unless (or (looking-at "[[:space:]\n]") + (not lsp-enable-symbol-highlighting) + (and lsp--have-document-highlights + curr-sym-bounds + (equal curr-sym-bounds + lsp--symbol-bounds-of-last-highlight-invocation))) + (setq lsp--symbol-bounds-of-last-highlight-invocation + curr-sym-bounds) + (lsp-request-async "textDocument/documentHighlight" + (lsp--text-document-position-params) + #'lsp--document-highlight-callback + :mode 'tick + :cancel-token :highlights)))) + +(defun lsp-describe-thing-at-point () + "Display the type signature and documentation of the thing at +point." + (interactive) + (let ((contents (-some->> (lsp--text-document-position-params) + (lsp--make-request "textDocument/hover") + (lsp--send-request) + (lsp:hover-contents)))) + (if (and contents (not (equal contents ""))) + (let ((lsp-help-buf-name "*lsp-help*")) + (with-current-buffer (get-buffer-create lsp-help-buf-name) + (with-help-window lsp-help-buf-name + (insert (string-trim-right (lsp--render-on-hover-content contents t)))))) + (lsp--info "No content at point.")))) + +(defun lsp--point-in-bounds-p (bounds) + "Return whether the current point is within BOUNDS." + (and (<= (car bounds) (point)) (< (point) (cdr bounds)))) + +(defun lsp-get-renderer (language) + "Get renderer for LANGUAGE." + (lambda (str) + (lsp--render-string str language))) + +(defun lsp--setup-markdown (mode) + "Setup the ‘markdown-mode’ in the frame. +MODE is the mode used in the parent frame." + (make-local-variable 'markdown-code-lang-modes) + (dolist (mark (alist-get mode lsp-custom-markup-modes)) + (add-to-list 'markdown-code-lang-modes (cons mark mode))) + (setq-local markdown-fontify-code-blocks-natively t) + (setq-local markdown-fontify-code-block-default-mode mode) + (setq-local markdown-hide-markup t) + + ;; Render some common HTML entities. + ;; This should really happen in markdown-mode instead, + ;; but it doesn't, so we do it here for now. + (setq prettify-symbols-alist + (cl-loop for i from 0 to 255 + collect (cons (format "&#x%02X;" i) i))) + (push '("<" . ?<) prettify-symbols-alist) + (push '(">" . ?>) prettify-symbols-alist) + (push '("&" . ?&) prettify-symbols-alist) + (push '(" " . ? ) prettify-symbols-alist) + (setq prettify-symbols-compose-predicate + (lambda (_start _end _match) t)) + (prettify-symbols-mode 1)) + +(defun lsp--buffer-string-visible () + "Return visible buffer string. +Stolen from `org-copy-visible'." + (let ((temp (generate-new-buffer " *temp*")) + (beg (point-min)) + (end (point-max))) + (while (/= beg end) + (when (get-char-property beg 'invisible) + (setq beg (next-single-char-property-change beg 'invisible nil end))) + (let* ((next (next-single-char-property-change beg 'invisible nil end)) + (substring (buffer-substring beg next))) + (with-current-buffer temp (insert substring)) + ;; (setq result (concat result substring)) + (setq beg next))) + (setq deactivate-mark t) + (prog1 (with-current-buffer temp + (s-chop-suffix "\n" (buffer-string))) + (kill-buffer temp)))) + +(defvar lsp-buffer-major-mode nil + "Holds the major mode when fontification function is running. +See #2588") + +(defvar view-inhibit-help-message) + +(defun lsp--render-markdown () + "Render markdown." + + (let ((markdown-enable-math nil)) + (goto-char (point-min)) + (while (re-search-forward + (rx (and "\\" (group (or "\\" "`" "*" "_" ":" "/" + "{" "}" "[" "]" "(" ")" + "#" "+" "-" "." "!" "|")))) + nil t) + (replace-match (rx (backref 1)))) + + ;; markdown-mode v2.3 does not yet provide gfm-view-mode + (if (fboundp 'gfm-view-mode) + (let ((view-inhibit-help-message t)) + (gfm-view-mode)) + (gfm-mode)) + + (lsp--setup-markdown lsp-buffer-major-mode))) + +(defvar lsp--display-inline-image-alist + '((lsp--render-markdown + (:regexp + "!\\[.*?\\](data:image/[a-zA-Z]+;base64,\\([A-Za-z0-9+/\n]+?=*?\\)\\(|[^)]+\\)?)" + :sexp + (create-image + (base64-decode-string + (buffer-substring-no-properties (match-beginning 1) (match-end 1))) + nil t)))) + "Replaced string regexp and function returning image. +Each element should have the form (MODE . (PROPERTY-LIST...)). +MODE (car) is function which is defined in `lsp-language-id-configuration'. +Cdr should be list of PROPERTY-LIST. + +Each PROPERTY-LIST should have properties: +:regexp Regexp which determines what string is relpaced to image. + You should also get information of image, by parenthesis constructs. + By default, all matched string is replaced to image, but you can + change index of replaced string by keyword :replaced-index. + +:sexp Return image when evaluated. You can use information of regexp + by using (match-beggining N), (match-end N) or (match-substring N). + +In addition, each can have property: +:replaced-index Determine index which is used to replace regexp to image. + The value means first argument of `match-beginning' and + `match-end'. If omitted, interpreted as index 0.") + +(defcustom lsp-display-inline-image t + "Showing inline image or not." + :group 'lsp-mode + :type 'boolean) + +(defun lsp--display-inline-image (mode) + "Add image property if available." + (let ((plist-list (cdr (assq mode lsp--display-inline-image-alist)))) + (when (and (display-images-p) lsp-display-inline-image) + (cl-loop + for plist in plist-list + with regexp with replaced-index + do + (setq regexp (plist-get plist :regexp)) + (setq replaced-index (or (plist-get plist :replaced-index) 0)) + + (font-lock-remove-keywords nil (list regexp replaced-index)) + (let ((inhibit-read-only t)) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward regexp nil t) + (set-text-properties + (match-beginning replaced-index) (match-end replaced-index) + nil) + (add-text-properties + (match-beginning replaced-index) (match-end replaced-index) + `(display ,(eval (plist-get plist :sexp))))))))))) + +(defun lsp--fontlock-with-mode (str mode) + "Fontlock STR with MODE." + (let ((lsp-buffer-major-mode major-mode)) + (condition-case nil + (with-temp-buffer + (insert str) + (delay-mode-hooks (funcall mode)) + (cl-flet ((window-body-width () lsp-window-body-width)) + ;; This can go wrong in some cases, and the fontification would + ;; not work as expected. + ;; + ;; See #2984 + (ignore-errors (font-lock-ensure)) + (lsp--display-inline-image mode)) + (lsp--buffer-string-visible)) + (error str)))) + +(defun lsp--render-string (str language) + "Render STR using `major-mode' corresponding to LANGUAGE. +When language is nil render as markup if `markdown-mode' is loaded." + (setq str (s-replace "\r" "" (or str ""))) + (if-let ((mode (-some (-lambda ((mode . lang)) + (when (and (equal lang language) (functionp mode)) + mode)) + lsp-language-id-configuration))) + (lsp--fontlock-with-mode str mode) + str)) + +(defun lsp--render-element (content) + "Render CONTENT element." + (let ((inhibit-message t)) + (or + (pcase content + ((MarkedString :value :language) + (lsp--render-string value language)) + ((MarkupContent :value :kind) + (lsp--render-string value kind)) + ;; plain string + ((pred stringp) (lsp--render-string content "markdown")) + ((pred null) "") + (_ (error "Failed to handle %s" content))) + ""))) + +(defun lsp--create-unique-string-fn () + (let (elements) + (lambda (element) + (let ((count (cl-count element elements :test #'string=))) + (prog1 (if (zerop count) + element + (format "%s (%s)" element count)) + (push element elements)))))) + +(defun lsp--select-action (actions) + "Select an action to execute from ACTIONS." + (cond + ((seq-empty-p actions) (signal 'lsp-no-code-actions nil)) + ((and (eq (seq-length actions) 1) lsp-auto-execute-action) + (lsp-seq-first actions)) + (t (let ((completion-ignore-case t)) + (lsp--completing-read "Select code action: " + (seq-into actions 'list) + (-compose (lsp--create-unique-string-fn) + #'lsp:code-action-title) + nil t))))) + +(defun lsp--workspace-server-id (workspace) + "Return the server ID of WORKSPACE." + (-> workspace lsp--workspace-client lsp--client-server-id)) + +(defun lsp--handle-rendered-for-echo-area (contents) + "Return a single line from RENDERED, appropriate for display in the echo area." + (pcase (lsp-workspaces) + (`(,workspace) + (lsp-clients-extract-signature-on-hover contents (lsp--workspace-server-id workspace))) + ;; For projects with multiple active workspaces we also default to + ;; render the first line. + (_ (lsp-clients-extract-signature-on-hover contents nil)))) + +(cl-defgeneric lsp-clients-extract-signature-on-hover (contents _server-id) + "Extract a representative line from CONTENTS, to show in the echo area." + (car (s-lines (s-trim (lsp--render-element contents))))) + +(defun lsp--render-on-hover-content (contents render-all) + "Render the content received from 'document/onHover' request. +CONTENTS - MarkedString | MarkedString[] | MarkupContent +RENDER-ALL - nil if only the signature should be rendered." + (cond + ((lsp-markup-content? contents) + ;; MarkupContent. + ;; It tends to be long and is not suitable to display fully in the echo area. + ;; Just display the first line which is typically the signature. + (if render-all + (lsp--render-element contents) + (lsp--handle-rendered-for-echo-area contents))) + ((and (stringp contents) (not (string-match-p "\n" contents))) + ;; If the contents is a single string containing a single line, + ;; render it always. + (lsp--render-element contents)) + (t + ;; MarkedString -> MarkedString[] + (when (or (lsp-marked-string? contents) (stringp contents)) + (setq contents (list contents))) + ;; Consider the signature consisting of the elements who have a renderable + ;; "language" property. When render-all is nil, ignore other elements. + (string-join + (seq-map + #'lsp--render-element + (if render-all + contents + ;; Only render contents that have an available renderer. + (seq-filter + (-andfn #'lsp-marked-string? + (-compose #'lsp-get-renderer #'lsp:marked-string-language)) + contents))) + (if (bound-and-true-p page-break-lines-mode) + "\n\n" + "\n"))))) + + + +(defvar lsp-signature-mode-map + (-doto (make-sparse-keymap) + (define-key (kbd "M-n") #'lsp-signature-next) + (define-key (kbd "M-p") #'lsp-signature-previous) + (define-key (kbd "M-a") #'lsp-signature-toggle-full-docs) + (define-key (kbd "C-c C-k") #'lsp-signature-stop) + (define-key (kbd "C-g") #'lsp-signature-stop)) + "Keymap for `lsp-signature-mode-map'.") + +(define-minor-mode lsp-signature-mode + "Mode used to show signature popup." + :keymap lsp-signature-mode-map + :lighter "" + :group 'lsp-mode) + +(defun lsp-signature-stop () + "Stop showing current signature help." + (interactive) + (lsp-cancel-request-by-token :signature) + (remove-hook 'post-command-hook #'lsp-signature) + (funcall lsp-signature-function nil) + (lsp-signature-mode -1)) + +(defun lsp-lv-message (message) + (if message + (progn + (setq lsp--signature-last-buffer (current-buffer)) + (let ((lv-force-update t)) + (lv-message "%s" message))) + (lv-delete-window))) + +(declare-function posframe-show "ext:posframe") +(declare-function posframe-hide "ext:posframe") +(declare-function posframe-poshandler-point-bottom-left-corner-upward "ext:posframe") + +(defface lsp-signature-posframe + '((t :inherit tooltip)) + "Background and foreground for `lsp-signature-posframe'." + :group 'lsp-mode) + +(defvar lsp-signature-posframe-params + (list :poshandler #'posframe-poshandler-point-bottom-left-corner-upward + :height 6 + :width 60 + :border-width 10 + :min-width 60) + "Params for signature and `posframe-show'.") + +(defun lsp-signature-posframe (str) + "Use posframe to show the STR signatureHelp string." + (if str + (apply #'posframe-show + (with-current-buffer (get-buffer-create "*lsp-signature*") + (erase-buffer) + (insert str) + (visual-line-mode 1) + (current-buffer)) + (append lsp-signature-posframe-params + (list + :position (point) + :background-color (face-attribute 'lsp-signature-posframe :background nil t) + :foreground-color (face-attribute 'lsp-signature-posframe :foreground nil t) + :border-color (face-attribute 'lsp-signature-posframe :background nil t)))) + (posframe-hide "*lsp-signature*"))) + +(defun lsp--handle-signature-update (signature) + (let ((message + (if (lsp-signature-help? signature) + (lsp--signature->message signature) + (mapconcat #'lsp--signature->message signature "\n")))) + (if (s-present? message) + (funcall lsp-signature-function message) + (lsp-signature-stop)))) + +(defun lsp-signature-activate () + "Activate signature help. +It will show up only if current point has signature help." + (interactive) + (setq lsp--signature-last nil + lsp--signature-last-index nil + lsp--signature-last-buffer (current-buffer)) + (add-hook 'post-command-hook #'lsp-signature) + (lsp-signature-mode t)) + +(defcustom lsp-signature-cycle t + "Whether `lsp-signature-next' and prev should cycle." + :type 'boolean + :group 'lsp-mode) + +(defun lsp-signature-next () + "Show next signature." + (interactive) + (let ((nsigs (length (lsp:signature-help-signatures lsp--signature-last)))) + (when (and lsp--signature-last-index + lsp--signature-last + (or lsp-signature-cycle (< (1+ lsp--signature-last-index) nsigs))) + (setq lsp--signature-last-index (% (1+ lsp--signature-last-index) nsigs)) + (funcall lsp-signature-function (lsp--signature->message lsp--signature-last))))) + +(defun lsp-signature-previous () + "Next signature." + (interactive) + (when (and lsp--signature-last-index + lsp--signature-last + (or lsp-signature-cycle (not (zerop lsp--signature-last-index)))) + (setq lsp--signature-last-index (1- (if (zerop lsp--signature-last-index) + (length (lsp:signature-help-signatures lsp--signature-last)) + lsp--signature-last-index))) + (funcall lsp-signature-function (lsp--signature->message lsp--signature-last)))) + +(defun lsp-signature-toggle-full-docs () + "Toggle full/partial signature documentation." + (interactive) + (let ((all? (not (numberp lsp-signature-doc-lines)))) + (setq lsp-signature-doc-lines (if all? + (or (car-safe lsp-signature-doc-lines) + 20) + (list lsp-signature-doc-lines)))) + (lsp-signature-activate)) + +(defun lsp--signature->message (signature-help) + "Generate eldoc message from SIGNATURE-HELP response." + (setq lsp--signature-last signature-help) + + (when (and signature-help (not (seq-empty-p (lsp:signature-help-signatures signature-help)))) + (-let* (((&SignatureHelp :active-signature? + :active-parameter? + :signatures) signature-help) + (active-signature? (or lsp--signature-last-index active-signature? 0)) + (_ (setq lsp--signature-last-index active-signature?)) + ((signature &as &SignatureInformation? :label :parameters?) (seq-elt signatures active-signature?)) + (prefix (if (= (length signatures) 1) + "" + (concat (propertize (format " %s/%s" + (1+ active-signature?) + (length signatures)) + 'face 'success) + " "))) + (method-docs (when + (and lsp-signature-render-documentation + (or (not (numberp lsp-signature-doc-lines)) (< 0 lsp-signature-doc-lines))) + (let ((docs (lsp--render-element + (lsp:parameter-information-documentation? signature)))) + (when (s-present? docs) + (concat + "\n" + (if (and (numberp lsp-signature-doc-lines) + (> (length (s-lines docs)) lsp-signature-doc-lines)) + (concat (s-join "\n" (-take lsp-signature-doc-lines (s-lines docs))) + (propertize "\nTruncated..." 'face 'highlight)) + docs))))))) + (when (and active-parameter? (not (seq-empty-p parameters?))) + (-when-let* ((param (when (and (< -1 active-parameter? (length parameters?))) + (seq-elt parameters? active-parameter?))) + (selected-param-label (let ((label (lsp:parameter-information-label param))) + (if (stringp label) label (append label nil)))) + (start (if (stringp selected-param-label) + (s-index-of selected-param-label label) + (cl-first selected-param-label))) + (end (if (stringp selected-param-label) + (+ start (length selected-param-label)) + (cl-second selected-param-label)))) + (add-face-text-property start end 'eldoc-highlight-function-argument nil label))) + (concat prefix label method-docs)))) + +(defun lsp-signature () + "Display signature info (based on `textDocument/signatureHelp')" + (if (and lsp--signature-last-buffer + (not (equal (current-buffer) lsp--signature-last-buffer))) + (lsp-signature-stop) + (lsp-request-async "textDocument/signatureHelp" + (lsp--text-document-position-params) + #'lsp--handle-signature-update + :cancel-token :signature))) + + +(defcustom lsp-overlay-document-color-char "â– " + "Display the char represent the document color in overlay" + :type 'string + :group 'lsp-mode) + +;; color presentation +(defun lsp--color-create-interactive-command (color range) + (lambda () + (interactive) + (-let [(&ColorPresentation? :text-edit? + :additional-text-edits?) + (lsp--completing-read + "Select color presentation: " + (lsp-request + "textDocument/colorPresentation" + `( :textDocument ,(lsp--text-document-identifier) + :color ,color + :range ,range)) + #'lsp:color-presentation-label + nil + t)] + (when text-edit? + (lsp--apply-text-edit text-edit?)) + (when additional-text-edits? + (lsp--apply-text-edits additional-text-edits? 'color-presentation))))) + +(defun lsp--number->color (number) + (let ((result (format "%x" + (round (* (or number 0) 255.0))))) + (if (= 1 (length result)) + (concat "0" result) + result))) + +(defun lsp--document-color () + "Document color handler." + (when (lsp-feature? "textDocument/documentColor") + (lsp-request-async + "textDocument/documentColor" + `(:textDocument ,(lsp--text-document-identifier)) + (lambda (result) + (lsp--remove-overlays 'lsp-color) + (seq-do + (-lambda ((&ColorInformation :color (color &as &Color :red :green :blue) + :range)) + (-let* (((beg . end) (lsp--range-to-region range)) + (overlay (make-overlay beg end)) + (command (lsp--color-create-interactive-command color range))) + (overlay-put overlay 'lsp-color t) + (overlay-put overlay 'evaporate t) + (overlay-put overlay + 'before-string + (propertize + lsp-overlay-document-color-char + 'face `((:foreground ,(format + "#%s%s%s" + (lsp--number->color red) + (lsp--number->color green) + (lsp--number->color blue)))) + 'action command + 'mouse-face 'lsp-lens-mouse-face + 'local-map (-doto (make-sparse-keymap) + (define-key [mouse-1] command)))))) + result)) + :mode 'unchanged + :cancel-token :document-color-token))) + + +;; hover + +(defvar-local lsp--hover-saved-bounds nil) + +(defun lsp-hover () + "Display hover info (based on `textDocument/signatureHelp')." + (if (and lsp--hover-saved-bounds + (lsp--point-in-bounds-p lsp--hover-saved-bounds)) + (lsp--eldoc-message lsp--eldoc-saved-message) + (setq lsp--hover-saved-bounds nil + lsp--eldoc-saved-message nil) + (if (looking-at "[[:space:]\n]") + (lsp--eldoc-message nil) + (when (and lsp-eldoc-enable-hover (lsp--capability :hoverProvider)) + (lsp-request-async + "textDocument/hover" + (lsp--text-document-position-params) + (-lambda ((hover &as &Hover? :range? :contents)) + (when hover + (when range? + (setq lsp--hover-saved-bounds (lsp--range-to-region range?))) + (lsp--eldoc-message (and contents + (lsp--render-on-hover-content + contents + lsp-eldoc-render-all))))) + :error-handler #'ignore + :mode 'tick + :cancel-token :eldoc-hover))))) + + + +(defun lsp--action-trigger-parameter-hints (_command) + "Handler for editor.action.triggerParameterHints." + (when (member :on-server-request lsp-signature-auto-activate) + (lsp-signature-activate))) + +(defun lsp--action-trigger-suggest (_command) + "Handler for editor.action.triggerSuggest." + (cond + ((and (bound-and-true-p company-mode) + (fboundp 'company-auto-begin) + (fboundp 'company-post-command)) + (run-at-time 0 nil + (lambda () + (let ((this-command 'company-idle-begin) + (company-minimum-prefix-length 0)) + (company-auto-begin) + (company-post-command))))) + (t + (completion-at-point)))) + +(defconst lsp--default-action-handlers + (ht ("editor.action.triggerParameterHints" #'lsp--action-trigger-parameter-hints) + ("editor.action.triggerSuggest" #'lsp--action-trigger-suggest)) + "Default action handlers.") + +(defun lsp--find-action-handler (command) + "Find action handler for particular COMMAND." + (or + (--some (-some->> it + (lsp--workspace-client) + (lsp--client-action-handlers) + (gethash command)) + (lsp-workspaces)) + (gethash command lsp--default-action-handlers))) + +(defun lsp--text-document-code-action-params (&optional kind) + "Code action params." + (list :textDocument (lsp--text-document-identifier) + :range (if (use-region-p) + (lsp--region-to-range (region-beginning) (region-end)) + (lsp--region-to-range (point) (point))) + :context `( :diagnostics ,(lsp-cur-line-diagnostics) + ,@(when kind (list :only (vector kind)))))) + +(defun lsp-code-actions-at-point (&optional kind) + "Retrieve the code actions for the active region or the current line. +It will filter by KIND if non nil." + (lsp-request "textDocument/codeAction" (lsp--text-document-code-action-params kind))) + +(defun lsp-execute-code-action-by-kind (command-kind) + "Execute code action by COMMAND-KIND." + (if-let ((action (->> (lsp-get-or-calculate-code-actions command-kind) + (-filter (-lambda ((&CodeAction :kind?)) + (and kind? (equal command-kind kind?)))) + lsp--select-action))) + (lsp-execute-code-action action) + (signal 'lsp-no-code-actions '(command-kind)))) + +(defalias 'lsp-get-or-calculate-code-actions 'lsp-code-actions-at-point) + +(lsp-defun lsp--execute-command ((action &as &Command :command :arguments?)) + "Parse and execute a code ACTION represented as a Command LSP type." + (let ((server-id (->> (lsp-workspaces) + (cl-first) + (or lsp--cur-workspace) + (lsp--workspace-client) + (lsp--client-server-id)))) + (condition-case nil + (with-no-warnings + (lsp-execute-command server-id (intern command) arguments?)) + (cl-no-applicable-method + (if-let ((action-handler (lsp--find-action-handler command))) + (funcall action-handler action) + (lsp-send-execute-command command arguments?)))))) + +(lsp-defun lsp-execute-code-action ((action &as &CodeAction :command? :edit?)) + "Execute code action ACTION. +If ACTION is not set it will be selected from `lsp-code-actions-at-point'. +Request codeAction/resolve for more info if server supports." + (interactive (list (lsp--select-action (lsp-code-actions-at-point)))) + (if (and (lsp-feature? "codeAction/resolve") + (not command?) + (not edit?)) + (lsp--execute-code-action (lsp-request "codeAction/resolve" action)) + (lsp--execute-code-action action))) + +(lsp-defun lsp--execute-code-action ((action &as &CodeAction :command? :edit?)) + "Execute code action ACTION." + (when edit? + (lsp--apply-workspace-edit edit? 'code-action)) + + (cond + ((stringp command?) (lsp--execute-command action)) + ((lsp-command? command?) (lsp--execute-command command?)))) + +(defvar lsp--formatting-indent-alist + ;; Taken from `dtrt-indent-mode' + '((c-mode . c-basic-offset) ; C + (c++-mode . c-basic-offset) ; C++ + (d-mode . c-basic-offset) ; D + (java-mode . c-basic-offset) ; Java + (jde-mode . c-basic-offset) ; Java (JDE) + (js-mode . js-indent-level) ; JavaScript + (js2-mode . js2-basic-offset) ; JavaScript-IDE + (js3-mode . js3-indent-level) ; JavaScript-IDE + (json-mode . js-indent-level) ; JSON + (lua-mode . lua-indent-level) ; Lua + (objc-mode . c-basic-offset) ; Objective C + (php-mode . c-basic-offset) ; PHP + (perl-mode . perl-indent-level) ; Perl + (cperl-mode . cperl-indent-level) ; Perl + (raku-mode . raku-indent-offset) ; Perl6/Raku + (erlang-mode . erlang-indent-level) ; Erlang + (ada-mode . ada-indent) ; Ada + (sgml-mode . sgml-basic-offset) ; SGML + (nxml-mode . nxml-child-indent) ; XML + (pascal-mode . pascal-indent-level) ; Pascal + (typescript-mode . typescript-indent-level) ; Typescript + (sh-mode . sh-basic-offset) ; Shell Script + (ruby-mode . ruby-indent-level) ; Ruby + (enh-ruby-mode . enh-ruby-indent-level) ; Ruby + (crystal-mode . crystal-indent-level) ; Crystal (Ruby) + (css-mode . css-indent-offset) ; CSS + (rust-mode . rust-indent-offset) ; Rust + (rustic-mode . rustic-indent-offset) ; Rust + (scala-mode . scala-indent:step) ; Scala + (powershell-mode . powershell-indent) ; PowerShell + (ess-mode . ess-indent-offset) ; ESS (R) + (yaml-mode . yaml-indent-offset) ; YAML + (hack-mode . hack-indent-offset) ; Hack + + (default . standard-indent)) ; default fallback + "A mapping from `major-mode' to its indent variable.") + +(defun lsp--get-indent-width (mode) + "Get indentation offset for MODE." + (or (alist-get mode lsp--formatting-indent-alist) + (lsp--get-indent-width (or (get mode 'derived-mode-parent) 'default)))) + +(defun lsp--make-document-formatting-params () + "Create document formatting params." + (lsp-make-document-formatting-params + :text-document (lsp--text-document-identifier) + :options (lsp-make-formatting-options + :tab-size (symbol-value (lsp--get-indent-width major-mode)) + :insert-spaces (if indent-tabs-mode :json-false t)))) + +(defun lsp-format-buffer () + "Ask the server to format this document." + (interactive "*") + (cond ((lsp-feature? "textDocument/formatting") + (let ((edits (lsp-request "textDocument/formatting" + (lsp--make-document-formatting-params)))) + (if (seq-empty-p edits) + (lsp--info "No formatting changes provided") + (lsp--apply-text-edits edits 'format)))) + ((lsp-feature? "textDocument/rangeFormatting") + (save-restriction + (widen) + (lsp-format-region (point-min) (point-max)))) + (t (signal 'lsp-capability-not-supported (list "documentFormattingProvider"))))) + +(defun lsp-format-region (s e) + "Ask the server to format the region, or if none is selected, the current line." + (interactive "r") + (let ((edits (lsp-request + "textDocument/rangeFormatting" + (lsp--make-document-range-formatting-params s e)))) + (if (seq-empty-p edits) + (lsp--info "No formatting changes provided") + (lsp--apply-text-edits edits 'format)))) + +(defmacro lsp-make-interactive-code-action (func-name code-action-kind) + "Define an interactive function FUNC-NAME that attempts to +execute a CODE-ACTION-KIND action." + `(defun ,(intern (concat "lsp-" (symbol-name func-name))) () + ,(format "Perform the %s code action, if available." code-action-kind) + (interactive) + (condition-case nil + (lsp-execute-code-action-by-kind ,code-action-kind) + (lsp-no-code-actions + (when (called-interactively-p 'any) + (lsp--info ,(format "%s action not available" code-action-kind))))))) + +(lsp-make-interactive-code-action organize-imports "source.organizeImports") + +(defun lsp--make-document-range-formatting-params (start end) + "Make DocumentRangeFormattingParams for selected region." + (lsp:set-document-range-formatting-params-range (lsp--make-document-formatting-params) + (lsp--region-to-range start end))) + +(defconst lsp--highlight-kind-face + '((1 . lsp-face-highlight-textual) + (2 . lsp-face-highlight-read) + (3 . lsp-face-highlight-write))) + +(defun lsp--remove-overlays (name) + (save-restriction + (widen) + (remove-overlays (point-min) (point-max) name t))) + +(defun lsp-document-highlight () + "Highlight all relevant references to the symbol under point." + (interactive) + (lsp--remove-overlays 'lsp-highlight) ;; clear any previous highlights + (setq lsp--have-document-highlights nil + lsp--symbol-bounds-of-last-highlight-invocation nil) + (let ((lsp-enable-symbol-highlighting t)) + (lsp--document-highlight))) + +(defun lsp--document-highlight-callback (highlights) + "Create a callback to process the reply of a +'textDocument/documentHighlight' message for the buffer BUF. +A reference is highlighted only if it is visible in a window." + (lsp--remove-overlays 'lsp-highlight) + + (let* ((wins-visible-pos (-map (lambda (win) + (cons (1- (line-number-at-pos (window-start win) t)) + (1+ (line-number-at-pos (window-end win) t)))) + (get-buffer-window-list nil nil 'visible)))) + (setq lsp--have-document-highlights t) + (-map + (-lambda ((&DocumentHighlight :range (&Range :start (start &as &Position :line start-line) + :end (end &as &Position :line end-line)) + :kind?)) + (-map + (-lambda ((start-window . end-window)) + ;; Make the overlay only if the reference is visible + (let ((start-point (lsp--position-to-point start)) + (end-point (lsp--position-to-point end))) + (when (and (> (1+ start-line) start-window) + (< (1+ end-line) end-window) + (not (and lsp-symbol-highlighting-skip-current + (<= start-point (point) end-point)))) + (-doto (make-overlay start-point end-point) + (overlay-put 'face (cdr (assq (or kind? 1) lsp--highlight-kind-face))) + (overlay-put 'lsp-highlight t))))) + wins-visible-pos)) + highlights))) + +(defcustom lsp-symbol-kinds + '((1 . "File") + (2 . "Module") + (3 . "Namespace") + (4 . "Package") + (5 . "Class") + (6 . "Method") + (7 . "Property") + (8 . "Field") + (9 . "Constructor") + (10 . "Enum") + (11 . "Interface") + (12 . "Function") + (13 . "Variable") + (14 . "Constant") + (15 . "String") + (16 . "Number") + (17 . "Boolean") + (18 . "Array") + (19 . "Object") + (20 . "Key") + (21 . "Null") + (22 . "Enum Member") + (23 . "Struct") + (24 . "Event") + (25 . "Operator") + (26 . "Type Parameter")) + "Alist mapping SymbolKinds to human-readable strings. +Various Symbol objects in the LSP protocol have an integral type, +specifying what they are. This alist maps such type integrals to +readable representations of them. See +`https://microsoft.github.io/language-server-protocol/specifications/specification-current/', +namespace SymbolKind." + :group 'lsp-mode + :type '(alist :key-type integer :value-type string)) +(defalias 'lsp--symbol-kind 'lsp-symbol-kinds) + +(lsp-defun lsp--symbol-information-to-xref + ((&SymbolInformation :kind :name + :location (&Location :uri :range (&Range :start + (&Position :line :character))))) + "Return a `xref-item' from SYMBOL information." + (xref-make (format "[%s] %s" (alist-get kind lsp-symbol-kinds) name) + (xref-make-file-location (lsp--uri-to-path uri) + line + character))) + +(defun lsp--get-document-symbols () + "Get document symbols. + +If the buffer has not been modified since symbols were last +retrieved, simply return the latest result. + +Else, if the request was initiated by Imenu updating its menu-bar +entry, perform it asynchronously; i.e., give Imenu the latest +result and then force a refresh when a new one is available. + +Else (e.g., due to interactive use of `imenu' or `xref'), +perform the request synchronously." + (if (= (buffer-chars-modified-tick) lsp--document-symbols-tick) + lsp--document-symbols + (let ((method "textDocument/documentSymbol") + (params `(:textDocument ,(lsp--text-document-identifier))) + (tick (buffer-chars-modified-tick))) + (if (not lsp--document-symbols-request-async) + (prog1 + (setq lsp--document-symbols (lsp-request method params)) + (setq lsp--document-symbols-tick tick)) + (lsp-request-async method params + (lambda (document-symbols) + (setq lsp--document-symbols document-symbols + lsp--document-symbols-tick tick) + (lsp--imenu-refresh)) + :mode 'alive) + lsp--document-symbols)))) + +(advice-add 'imenu-update-menubar :around + (lambda (oldfun &rest r) + (let ((lsp--document-symbols-request-async t)) + (apply oldfun r)))) + +(defun lsp--document-symbols->document-symbols-hierarchy (document-symbols current-position) + "Convert DOCUMENT-SYMBOLS to symbols hierarchy on CURRENT-POSITION." + (-let (((symbol &as &DocumentSymbol? :children?) + (seq-find (-lambda ((&DocumentSymbol :range)) + (lsp-point-in-range? current-position range)) + document-symbols))) + (if children? + (cons symbol (lsp--document-symbols->document-symbols-hierarchy children? current-position)) + (when symbol + (list symbol))))) + +(lsp-defun lsp--symbol-information->document-symbol ((&SymbolInformation :name :kind :location :container-name? :deprecated?)) + "Convert a SymbolInformation to a DocumentInformation" + (lsp-make-document-symbol :name name + :kind kind + :range (lsp:location-range location) + :children? nil + :deprecated? deprecated? + :selection-range (lsp:location-range location) + :detail? container-name?)) + +(defun lsp--symbols-informations->document-symbols-hierarchy (symbols-informations current-position) + "Convert SYMBOLS-INFORMATIONS to symbols hierarchy on CURRENT-POSITION." + (--> symbols-informations + (-keep (-lambda ((symbol &as &SymbolInformation :location (&Location :range))) + (when (lsp-point-in-range? current-position range) + (lsp--symbol-information->document-symbol symbol))) + it) + (sort it (-lambda ((&DocumentSymbol :range (&Range :start a-start-position :end a-end-position)) + (&DocumentSymbol :range (&Range :start b-start-position :end b-end-position))) + (and (lsp--position-compare b-start-position a-start-position) + (lsp--position-compare a-end-position b-end-position)))))) + +(defun lsp--symbols->document-symbols-hierarchy (symbols) + "Convert SYMBOLS to symbols-hierarchy." + (when-let ((first-symbol (lsp-seq-first symbols))) + (let ((cur-position (lsp-make-position :line (plist-get (lsp--cur-position) :line) + :character (plist-get (lsp--cur-position) :character)))) + (if (lsp-symbol-information? first-symbol) + (lsp--symbols-informations->document-symbols-hierarchy symbols cur-position) + (lsp--document-symbols->document-symbols-hierarchy symbols cur-position))))) + +(defun lsp--xref-backend () 'xref-lsp) + +(cl-defmethod xref-backend-identifier-at-point ((_backend (eql xref-lsp))) + (propertize (or (thing-at-point 'symbol) "") + 'identifier-at-point t)) + +(defun lsp--xref-elements-index (symbols path) + (-mapcat + (-lambda (sym) + (pcase-exhaustive sym + ((DocumentSymbol :name :children? :selection-range (Range :start)) + (cons (cons (concat path name) + (lsp--position-to-point start)) + (lsp--xref-elements-index children? (concat path name " / ")))) + ((SymbolInformation :name :location (Location :range (Range :start))) + (list (cons (concat path name) + (lsp--position-to-point start)))))) + symbols)) + +(defvar-local lsp--symbols-cache nil) + +(cl-defmethod xref-backend-identifier-completion-table ((_backend (eql xref-lsp))) + (if (lsp--find-workspaces-for "textDocument/documentSymbol") + (progn + (setq lsp--symbols-cache (lsp--xref-elements-index + (lsp--get-document-symbols) nil)) + lsp--symbols-cache) + (list (propertize (or (thing-at-point 'symbol) "") + 'identifier-at-point t)))) + +(cl-defmethod xref-backend-definitions ((_backend (eql xref-lsp)) identifier) + (save-excursion + (unless (get-text-property 0 'identifier-at-point identifier) + (goto-char (cl-rest (or (assoc identifier lsp--symbols-cache) + (user-error "Unable to find symbol %s in current document" identifier))))) + (lsp--locations-to-xref-items (lsp-request "textDocument/definition" + (lsp--text-document-position-params))))) + +(cl-defmethod xref-backend-references ((_backend (eql xref-lsp)) identifier) + (save-excursion + (unless (get-text-property 0 'identifier-at-point identifier) + (goto-char (cl-rest (or (assoc identifier lsp--symbols-cache) + (user-error "Unable to find symbol %s" identifier))))) + (lsp--locations-to-xref-items (lsp-request "textDocument/references" + (lsp--make-reference-params))))) + +(cl-defmethod xref-backend-apropos ((_backend (eql xref-lsp)) pattern) + (seq-map #'lsp--symbol-information-to-xref + (lsp-request "workspace/symbol" `(:query ,pattern)))) + +(defcustom lsp-rename-use-prepare t + "Whether `lsp-rename' should do a prepareRename first. +For some language servers, textDocument/prepareRename might be +too slow, in which case this variable may be set to nil. +`lsp-rename' will then use `thing-at-point' `symbol' to determine +the symbol to rename at point." + :group 'lsp-mode + :type 'boolean) + +(defun lsp--get-symbol-to-rename () + "Get a symbol to rename and placeholder at point. +Returns a cons ((START . END) . PLACEHOLDER?), and nil if +renaming is generally supported but cannot be done at point. +START and END are the bounds of the identifiers being renamed, +while PLACEHOLDER?, is either nil or a string suggested by the +language server as the initial input of a new-name prompt." + (unless (lsp-feature? "textDocument/rename") + (error "The connected server(s) doesn't support renaming")) + (if (and lsp-rename-use-prepare (lsp-feature? "textDocument/prepareRename")) + (when-let ((response + (lsp-request "textDocument/prepareRename" + (lsp--text-document-position-params)))) + (let* ((bounds (lsp--range-to-region + (if (lsp-range? response) + response + (lsp:prepare-rename-result-range response)))) + (placeholder + (and (not (lsp-range? response)) + (lsp:prepare-rename-result-placeholder response)))) + (cons bounds placeholder))) + (when-let ((bounds (bounds-of-thing-at-point 'symbol))) + (cons bounds nil)))) + +(defface lsp-face-rename '((t :underline t)) + "Face used to highlight the identifier being renamed. +Renaming can be done using `lsp-rename'." + :group 'lsp-mode) + +(defface lsp-rename-placeholder-face '((t :inherit font-lock-variable-name-face)) + "Face used to display the rename placeholder in. +When calling `lsp-rename' interactively, this will be the face of +the new name." + :group 'lsp-mode) + +(defvar lsp-rename-history '() + "History for `lsp--read-rename'.") + +(defun lsp--read-rename (at-point) + "Read a new name for a `lsp-rename' at `point' from the user. +AT-POINT shall be a structure as returned by +`lsp--get-symbol-to-rename'. + +Returns a string, which should be the new name for the identifier +at point. If renaming cannot be done at point (as determined from +AT-POINT), throw a `user-error'. + +This function is for use in `lsp-rename' only, and shall not be +relied upon." + (unless at-point + (user-error "`lsp-rename' is invalid here")) + (-let* ((((start . end) . placeholder?) at-point) + ;; Do the `buffer-substring' first to not include `lsp-face-rename' + (rename-me (buffer-substring start end)) + (placeholder (or placeholder? rename-me)) + (placeholder (propertize placeholder 'face 'lsp-rename-placeholder-face)) + + overlay) + ;; We need unwind protect, as the user might cancel here, causing the + ;; overlay to linger. + (unwind-protect + (progn + (setq overlay (make-overlay start end)) + (overlay-put overlay 'face 'lsp-face-rename) + + (read-string (format "Rename %s to: " rename-me) placeholder + 'lsp-rename-history)) + (and overlay (delete-overlay overlay))))) + +(defun lsp-rename (newname) + "Rename the symbol (and all references to it) under point to NEWNAME." + (interactive (list (lsp--read-rename (lsp--get-symbol-to-rename)))) + (when-let ((edits (lsp-request "textDocument/rename" + `( :textDocument ,(lsp--text-document-identifier) + :position ,(lsp--cur-position) + :newName ,newname)))) + (lsp--apply-workspace-edit edits 'rename))) + +(defun lsp-show-xrefs (xrefs display-action references?) + (unless (region-active-p) (push-mark nil t)) + (if (boundp 'xref-show-definitions-function) + (with-no-warnings + (xref-push-marker-stack) + (funcall (if references? xref-show-xrefs-function xref-show-definitions-function) + (-const xrefs) + `((window . ,(selected-window)) + (display-action . ,display-action)))) + (xref--show-xrefs xrefs display-action))) + +(cl-defmethod seq-empty-p ((ht hash-table)) + "Function `seq-empty-p' for hash-table." + (hash-table-empty-p ht)) + +(cl-defun lsp-find-locations (method &optional extra &key display-action references?) + "Send request named METHOD and get cross references of the symbol under point. +EXTRA is a plist of extra parameters. +REFERENCES? t when METHOD returns references." + (let ((loc (lsp-request method + (append (lsp--text-document-position-params) extra)))) + (if (seq-empty-p loc) + (lsp--error "Not found for: %s" (or (thing-at-point 'symbol t) "")) + (lsp-show-xrefs (lsp--locations-to-xref-items loc) display-action references?)))) + +(cl-defun lsp-find-declaration (&key display-action) + "Find declarations of the symbol under point." + (interactive) + (lsp-find-locations "textDocument/declaration" nil :display-action display-action)) + +(cl-defun lsp-find-definition (&key display-action) + "Find definitions of the symbol under point." + (interactive) + (lsp-find-locations "textDocument/definition" nil :display-action display-action)) + +(defun lsp-find-definition-mouse (click) + "Click to start `lsp-find-definition' at clicked point." + (interactive "e") + (let* ((ec (event-start click)) + (p1 (posn-point ec)) + (w1 (posn-window ec))) + (select-window w1) + (goto-char p1) + (lsp-find-definition))) + +(cl-defun lsp-find-implementation (&key display-action) + "Find implementations of the symbol under point." + (interactive) + (lsp-find-locations "textDocument/implementation" nil :display-action display-action)) + +(cl-defun lsp-find-references (&optional include-declaration &key display-action) + "Find references of the symbol under point." + (interactive "P") + (lsp-find-locations "textDocument/references" + (list :context `(:includeDeclaration ,(lsp-json-bool include-declaration))) + :display-action display-action + :references? t)) + +(cl-defun lsp-find-type-definition (&key display-action) + "Find type definitions of the symbol under point." + (interactive) + (lsp-find-locations "textDocument/typeDefinition" nil :display-action display-action)) + +(defalias 'lsp-find-custom #'lsp-find-locations) +(defalias 'lsp-goto-implementation #'lsp-find-implementation) +(defalias 'lsp-goto-type-definition #'lsp-find-type-definition) + +(with-eval-after-load 'evil + (evil-set-command-property 'lsp-find-definition :jump t) + (evil-set-command-property 'lsp-find-implementation :jump t) + (evil-set-command-property 'lsp-find-references :jump t) + (evil-set-command-property 'lsp-find-type-definition :jump t)) + +(defun lsp--find-workspaces-for (msg-or-method) + "Find all workspaces in the current project that can handle MSG." + (let ((method (if (stringp msg-or-method) + msg-or-method + (plist-get msg-or-method :method)))) + (-if-let (reqs (cdr (assoc method lsp-method-requirements))) + (-let (((&plist :capability :check-command) reqs)) + (--filter + (with-lsp-workspace it + (or + (when check-command (funcall check-command it)) + (when capability (lsp--capability capability)) + (lsp--registered-capability method) + (and (not capability) (not check-command)))) + (lsp-workspaces))) + (lsp-workspaces)))) + +(defun lsp-can-execute-command? (command-name) + "Returns non-nil if current language server(s) can execute COMMAND-NAME. +The command is executed via `workspace/executeCommand'" + (cl-position + command-name + (lsp:execute-command-options-commands + (lsp:server-capabilities-execute-command-provider? + (lsp--server-capabilities))) + :test #'equal)) + +(defalias 'lsp-feature? 'lsp--find-workspaces-for) + +(cl-defmethod lsp-execute-command (_server _command _arguments) + "Dispatch COMMAND execution." + (signal 'cl-no-applicable-method nil)) + +(defun lsp-workspace-command-execute (command &optional args) + "Execute workspace COMMAND with ARGS." + (condition-case-unless-debug err + (let ((params (if args + (list :command command :arguments args) + (list :command command)))) + (lsp-request "workspace/executeCommand" params)) + (error + (lsp--error "`workspace/executeCommand' with `%s' failed.\n\n%S" + command err)))) + +(defun lsp-send-execute-command (command &optional args) + "Create and send a 'workspace/executeCommand' message having command COMMAND and optional ARGS." + (lsp-workspace-command-execute command args)) + +(defalias 'lsp-point-to-position #'lsp--point-to-position) +(defalias 'lsp-text-document-identifier #'lsp--text-document-identifier) +(defalias 'lsp--send-execute-command #'lsp-send-execute-command) +(defalias 'lsp-on-open #'lsp--text-document-did-open) +(defalias 'lsp-on-save #'lsp--text-document-did-save) + +(defun lsp--set-configuration (settings) + "Set the SETTINGS for the lsp server." + (lsp-notify "workspace/didChangeConfiguration" `(:settings ,settings))) + +(defun lsp-current-buffer () + (or lsp--virtual-buffer + (current-buffer))) + +(defun lsp-buffer-live-p (buffer-id) + (if-let ((buffer-live (plist-get buffer-id :buffer-live?))) + (funcall buffer-live buffer-id) + (buffer-live-p buffer-id))) + +(defun lsp--on-set-visited-file-name (old-func &rest args) + "Advice around function `set-visited-file-name'. + +This advice sends textDocument/didClose for the old file and +textDocument/didOpen for the new file." + (when lsp--cur-workspace + (lsp--text-document-did-close t)) + (prog1 (apply old-func args) + (when lsp--cur-workspace + (lsp--text-document-did-open)))) + +(advice-add 'set-visited-file-name :around #'lsp--on-set-visited-file-name) + +(defvar lsp--flushing-delayed-changes nil) + +(defun lsp--send-no-wait (message proc) + "Send MESSAGE to PROC without waiting for further output." + + (unless lsp--flushing-delayed-changes + (let ((lsp--flushing-delayed-changes t)) + (lsp--flush-delayed-changes))) + + (condition-case err + (process-send-string proc message) + ('error (lsp--error "Sending to process failed with the following error: %s" + (error-message-string err))))) + +(define-error 'lsp-parse-error + "Error parsing message from language server" 'lsp-error) +(define-error 'lsp-unknown-message-type + "Unknown message type" '(lsp-error lsp-parse-error)) +(define-error 'lsp-unknown-json-rpc-version + "Unknown JSON-RPC protocol version" '(lsp-error lsp-parse-error)) +(define-error 'lsp-no-content-length + "Content-Length header missing in message" '(lsp-error lsp-parse-error)) +(define-error 'lsp-invalid-header-name + "Invalid header name" '(lsp-error lsp-parse-error)) + +;; id method +;; x x request +;; x . response +;; . x notification +(defun lsp--get-message-type (json-data) + "Get the message type from JSON-DATA." + (if (lsp:json-message-id? json-data) + (if (lsp:json-message-error? json-data) + 'response-error + (if (lsp:json-message-method? json-data) + 'request + 'response)) + 'notification)) + +(defconst lsp--default-notification-handlers + (ht ("window/showMessage" #'lsp--window-show-message) + ("window/logMessage" #'lsp--window-log-message) + ("textDocument/publishDiagnostics" #'lsp--on-diagnostics) + ("textDocument/diagnosticsEnd" #'ignore) + ("textDocument/diagnosticsBegin" #'ignore) + ("telemetry/event" #'ignore) + ("$/progress" (lambda (workspace params) + (funcall lsp-progress-function workspace params))))) + +(lsp-defun lsp--on-notification (workspace (&JSONNotification :params :method)) + "Call the appropriate handler for NOTIFICATION." + (-let ((client (lsp--workspace-client workspace))) + (when lsp-print-io + (lsp--log-entry-new (lsp--make-log-entry method nil params 'incoming-notif) + lsp--cur-workspace)) + (if-let ((handler (or (gethash method (lsp--client-notification-handlers client)) + (gethash method lsp--default-notification-handlers)))) + (funcall handler workspace params) + (when (and method (not (string-prefix-p "$" method))) + (lsp-warn "Unknown notification: %s" method))))) + +(lsp-defun lsp--build-workspace-configuration-response ((&ConfigurationParams :items)) + "Get section configuration. +PARAMS are the `workspace/configuration' request params" + (->> items + (-map (-lambda ((&ConfigurationItem :section?)) + (-let* ((path-parts (split-string section? "\\.")) + (path-without-last (s-join "." (-slice path-parts 0 -1))) + (path-parts-len (length path-parts))) + (cond + ((<= path-parts-len 1) + (ht-get (lsp-configuration-section section?) + (car-safe path-parts) + (ht-create))) + ((> path-parts-len 1) + (when-let ((section (lsp-configuration-section path-without-last)) + (keys path-parts)) + (while (and keys section) + (setf section (ht-get section (pop keys)))) + section)))))) + (apply #'vector))) + +(defun lsp--send-request-response (workspace recv-time request response) + "Send the RESPONSE for REQUEST in WORKSPACE and log if needed." + (-let* (((&JSONResponse :params :method :id) request) + (process (lsp--workspace-proc workspace)) + (response (lsp--make-response id response)) + (req-entry (and lsp-print-io + (lsp--make-log-entry method id params 'incoming-req))) + (resp-entry (and lsp-print-io + (lsp--make-log-entry method id response 'outgoing-resp + (/ (nth 2 (time-since recv-time)) 1000))))) + ;; Send response to the server. + (when lsp-print-io + (lsp--log-entry-new req-entry workspace) + (lsp--log-entry-new resp-entry workspace)) + (lsp--send-no-wait (lsp--make-message response) process))) + +(lsp-defun lsp--on-request (workspace (request &as &JSONRequest :params :method)) + "Call the appropriate handler for REQUEST, and send the return value to the server. +WORKSPACE is the active workspace." + (-let* ((recv-time (current-time)) + (client (lsp--workspace-client workspace)) + (buffers (lsp--workspace-buffers workspace)) + handler + (response (cond + ((setq handler (gethash method (lsp--client-request-handlers client) nil)) + (funcall handler workspace params)) + ((setq handler (gethash method (lsp--client-async-request-handlers client) nil)) + (funcall handler workspace params + (-partial #'lsp--send-request-response + workspace recv-time request)) + 'delay-response) + ((equal method "client/registerCapability") + (mapc #'lsp--server-register-capability + (lsp:registration-params-registrations params)) + (mapc (lambda (buf) + (when (lsp-buffer-live-p buf) + (lsp-with-current-buffer buf + (lsp-unconfig-buffer) + (lsp-configure-buffer)))) + buffers) + nil) + ((equal method "window/showMessageRequest") + (let ((choice (lsp--window-log-message-request params))) + `(:title ,choice))) + ((equal method "client/unregisterCapability") + (mapc #'lsp--server-unregister-capability + (lsp:unregistration-params-unregisterations params)) + (mapc (lambda (buf) + (when (lsp-buffer-live-p buf) + (lsp-with-current-buffer buf + (lsp-unconfig-buffer) + (lsp-configure-buffer)))) + buffers) + nil) + ((equal method "workspace/applyEdit") + (list :applied (condition-case err + (prog1 t + (lsp--apply-workspace-edit (lsp:apply-workspace-edit-params-edit params) 'server-requested)) + (error + (lsp--error "Failed to apply edits with message %s" + (error-message-string err)) + :json-false)))) + ((equal method "workspace/configuration") + (with-lsp-workspace workspace + (if-let ((buf (car buffers))) + (lsp-with-current-buffer buf + (lsp--build-workspace-configuration-response params)) + (lsp--with-workspace-temp-buffer (lsp--workspace-root workspace) + (lsp--build-workspace-configuration-response params))))) + ((equal method "workspace/workspaceFolders") + (let ((folders (or (-> workspace + (lsp--workspace-client) + (lsp--client-server-id) + (gethash (lsp-session-server-id->folders (lsp-session)))) + (lsp-session-folders (lsp-session))))) + (->> folders + (-distinct) + (-map (lambda (folder) + (list :uri (lsp--path-to-uri folder)))) + (apply #'vector)))) + ((equal method "window/workDoneProgress/create") + nil ;; no specific reply, no processing required + ) + ((equal method "workspace/semanticTokens/refresh") + (when (and lsp-semantic-tokens-enable + (fboundp 'lsp--semantic-tokens-on-refresh)) + (lsp--semantic-tokens-on-refresh)) + nil) + (t (lsp-warn "Unknown request method: %s" method) nil)))) + ;; Send response to the server. + (unless (eq response 'delay-response) + (lsp--send-request-response workspace recv-time request response)))) + +(lsp-defun lsp--error-string ((&JSONError :message :code)) + "Format ERR as a user friendly string." + (format "Error from the Language Server: %s (%s)" + message + (or (car (alist-get code lsp--errors)) "Unknown error"))) + +(defun lsp--get-body-length (headers) + (let ((content-length (cdr (assoc "Content-Length" headers)))) + (if content-length + (string-to-number content-length) + + ;; This usually means either the server or our parser is + ;; screwed up with a previous Content-Length + (error "No Content-Length header")))) + +(defun lsp--parse-header (s) + "Parse string S as a LSP (KEY . VAL) header." + (let ((pos (string-match "\:" s)) + key val) + (unless pos + (signal 'lsp-invalid-header-name (list s))) + (setq key (substring s 0 pos) + val (s-trim-left (substring s (+ 1 pos)))) + (when (equal key "Content-Length") + (cl-assert (cl-loop for c across val + when (or (> c ?9) (< c ?0)) return nil + finally return t) + nil (format "Invalid Content-Length value: %s" val))) + (cons key val))) + +(defmacro lsp--read-json (str) + "Read json string STR." + (if (progn + (require 'json) + (fboundp 'json-parse-string)) + `(json-parse-string ,str + :object-type (if lsp-use-plists + 'plist + 'hash-table) + :null-object nil + :false-object nil) + `(let ((json-array-type 'vector) + (json-object-type (if lsp-use-plists + 'plist + 'hash-table)) + (json-false nil)) + (json-read-from-string ,str)))) + +(defmacro lsp-json-read-buffer () + "Read json from the current buffer." + (if (progn + (require 'json) + (fboundp 'json-parse-string)) + `(json-parse-buffer :object-type (if lsp-use-plists + 'plist + 'hash-table) + :null-object nil + :false-object nil) + `(let ((json-array-type 'vector) + (json-object-type (if lsp-use-plists + 'plist + 'hash-table)) + (json-false nil)) + (json-read)))) + +(defun lsp--read-json-file (file-path) + "Read json file." + (-> file-path + (f-read-text) + (lsp--read-json))) + +(defun lsp--parser-on-message (json-data workspace) + "Called when the parser P read a complete MSG from the server." + (with-demoted-errors "Error processing message %S." + (with-lsp-workspace workspace + (let* ((client (lsp--workspace-client workspace)) + (id (--when-let (lsp:json-response-id json-data) + (if (stringp it) (string-to-number it) it))) + (data (lsp:json-response-result json-data))) + (pcase (lsp--get-message-type json-data) + ('response + (cl-assert id) + (-let [(callback _ method _ before-send) (gethash id (lsp--client-response-handlers client))] + (when lsp-print-io + (lsp--log-entry-new + (lsp--make-log-entry method id data 'incoming-resp + (/ (nth 2 (time-since before-send)) 1000)) + workspace)) + (when callback + (funcall callback (lsp:json-response-result json-data)) + (remhash id (lsp--client-response-handlers client))))) + ('response-error + (cl-assert id) + (-let [(_ callback method _ before-send) (gethash id (lsp--client-response-handlers client))] + (when lsp-print-io + (lsp--log-entry-new + (lsp--make-log-entry method id (lsp:json-response-error-error json-data) + 'incoming-resp (/ (nth 2 (time-since before-send)) 1000)) + workspace)) + (when callback + (funcall callback (lsp:json-response-error-error json-data)) + (remhash id (lsp--client-response-handlers client))))) + ('notification + (lsp--on-notification workspace json-data)) + ('request (lsp--on-request workspace json-data))))))) + +(defvar lsp-parsed-message nil + "This will store the string representation of the json message. + +In some cases like #1807 we lose information during json +deserialization.") + +(defun lsp--create-filter-function (workspace) + "Make filter for the workspace." + (let ((body-received 0) + leftovers body-length body chunk) + (lambda (_proc input) + (setf chunk (if (s-blank? leftovers) + input + (concat leftovers input))) + + (let (messages) + (while (not (s-blank? chunk)) + (if (not body-length) + ;; Read headers + (if-let ((body-sep-pos (string-match-p "\r\n\r\n" chunk))) + ;; We've got all the headers, handle them all at once: + (setf body-length (lsp--get-body-length + (mapcar #'lsp--parse-header + (split-string + (substring-no-properties chunk + (or (string-match-p "Content-Length" chunk) + (error "Unable to find Content-Length header.")) + body-sep-pos) + "\r\n"))) + body-received 0 + leftovers nil + chunk (substring-no-properties chunk (+ body-sep-pos 4))) + + ;; Haven't found the end of the headers yet. Save everything + ;; for when the next chunk arrives and await further input. + (setf leftovers chunk + chunk nil)) + (let* ((chunk-length (string-bytes chunk)) + (left-to-receive (- body-length body-received)) + (this-body (if (< left-to-receive chunk-length) + (prog1 (substring-no-properties chunk 0 left-to-receive) + (setf chunk (substring-no-properties chunk left-to-receive))) + (prog1 chunk + (setf chunk nil)))) + (body-bytes (string-bytes this-body))) + (push this-body body) + (setf body-received (+ body-received body-bytes)) + (when (>= chunk-length left-to-receive) + (condition-case err + (with-temp-buffer + (apply #'insert + (nreverse + (prog1 body + (setf leftovers nil + body-length nil + body-received nil + body nil)))) + (decode-coding-region (point-min) + (point-max) + 'utf-8) + (goto-char (point-min)) + (push (lsp-json-read-buffer) messages)) + + (error + (lsp-warn "Failed to parse the following chunk:\n'''\n%s\n'''\nwith message %s" + (concat leftovers input) + err))))))) + (mapc (lambda (msg) + (lsp--parser-on-message msg workspace)) + (nreverse messages)))))) + +(defvar-local lsp--line-col-to-point-hash-table nil + "Hash table with keys (line . col) and values that are either point positions +or markers.") + +(defcustom lsp-imenu-detailed-outline t + "Whether `lsp-imenu' should include signatures. +This will be ignored if the server doesn't provide the necessary +information, for example if it doesn't support DocumentSymbols." + :group 'lsp-imenu + :type 'boolean) + +(defface lsp-details-face '((t :height 0.8 :inherit shadow)) + "Used to display additional information troughout `lsp'. +Things like line numbers, signatures, ... are considered +additional information. Often, additional faces are defined that +inherit from this face by default, like `lsp-signature-face', and +they may be customized for finer control." + :group 'lsp-mode) + +(defface lsp-signature-face '((t :inherit lsp-details-face)) + "Used to display signatures in `imenu', ...." + :group 'lsp-mode) + +(lsp-defun lsp-render-symbol ((&DocumentSymbol :name :detail? :deprecated?) + show-detail?) + "Render INPUT0, an `&DocumentSymbol', to a string. +If SHOW-DETAIL? is set, make use of its `:detail?' field (often +the signature)." + (let ((detail (and show-detail? (s-present? detail?) + (propertize (concat " " (s-trim-left detail?)) + 'face 'lsp-signature-face))) + (name (if deprecated? + (propertize name 'face 'lsp-face-semhl-deprecated) name))) + (concat name detail))) + +(lsp-defun lsp-render-symbol-information ((&SymbolInformation :name :deprecated? :container-name?) + separator) + "Render a piece of SymbolInformation. +Handle :deprecated?. If SEPARATOR is non-nil, the +symbol's (optional) parent, SEPARATOR and the symbol itself are +concatenated." + (when (and separator container-name? (not (string-empty-p container-name?))) + (setq name (concat name separator container-name?))) + (if deprecated? (propertize name 'face 'lsp-face-semhl-deprecated) name)) + +(defun lsp--symbol-to-imenu-elem (sym) + "Convert SYM to imenu element. + +SYM is a SymbolInformation message. + +Return a cons cell (full-name . start-point)." + (let ((start-point (ht-get lsp--line-col-to-point-hash-table + (lsp--get-line-and-col sym)))) + (cons (lsp-render-symbol-information + sym (and lsp-imenu-show-container-name + lsp-imenu-container-name-separator)) + start-point))) + +(lsp-defun lsp--symbol-to-hierarchical-imenu-elem ((sym &as &DocumentSymbol :children?)) + "Convert SYM to hierarchical imenu elements. + +SYM is a DocumentSymbol message. + +Return cons cell (\"symbol-name (symbol-kind)\" . start-point) if +SYM doesn't have any children. Otherwise return a cons cell with +an alist + + (\"symbol-name\" . ((\"(symbol-kind)\" . start-point) + cons-cells-from-children))" + (let ((filtered-children (lsp--imenu-filter-symbols children?)) + (signature (lsp-render-symbol sym lsp-imenu-detailed-outline))) + (if (seq-empty-p filtered-children) + (cons signature + (ht-get lsp--line-col-to-point-hash-table + (lsp--get-line-and-col sym))) + (cons signature + (lsp--imenu-create-hierarchical-index filtered-children))))) + +(lsp-defun lsp--symbol-ignore ((&SymbolInformation :kind :location)) + "Determine if SYM is for the current document and is to be shown." + ;; It's a SymbolInformation or DocumentSymbol, which is always in the + ;; current buffer file. + (or (and lsp-imenu-index-symbol-kinds + (numberp kind) + (let ((clamped-kind (if (< 0 kind (length lsp/symbol-kind-lookup)) + kind + 0))) + (not (memql (aref lsp/symbol-kind-lookup clamped-kind) + lsp-imenu-index-symbol-kinds)))) + (and location + (not (eq (->> location + (lsp:location-uri) + (lsp--uri-to-path) + (find-buffer-visiting)) + (current-buffer)))))) + +(lsp-defun lsp--get-symbol-type ((&SymbolInformation :kind)) + "The string name of the kind of SYM." + (alist-get kind lsp-symbol-kinds "Other")) + +(defun lsp--get-line-and-col (sym) + "Obtain the line and column corresponding to SYM." + (-let* ((location (lsp:symbol-information-location sym)) + (name-range (or (and location (lsp:location-range location)) + (lsp:document-symbol-selection-range sym))) + ((&Range :start (&Position :line :character)) name-range)) + (cons line character))) + +(defun lsp--collect-lines-and-cols (symbols) + "Return a sorted list ((line . col) ...) of the locations of SYMBOLS." + (let ((stack (mapcar 'identity symbols)) + line-col-list) + (while stack + (let ((sym (pop stack))) + (push (lsp--get-line-and-col sym) line-col-list) + (unless (seq-empty-p (lsp:document-symbol-children? sym)) + (setf stack (nconc (lsp--imenu-filter-symbols (lsp:document-symbol-children? sym)) stack))))) + (-sort #'lsp--line-col-comparator line-col-list))) + +(defun lsp--convert-line-col-to-points-batch (line-col-list) + "Convert a sorted list of positions from line-column +representation to point representation." + (let ((line-col-to-point-map (ht-create)) + (inhibit-field-text-motion t) + (curr-line 0)) + (lsp-save-restriction-and-excursion + (goto-char (point-min)) + (cl-loop for (line . col) in line-col-list do + (forward-line (- line curr-line)) + (setq curr-line line) + (let ((line-end (line-end-position))) + (if (or (not col) (> col (- line-end (point)))) + (goto-char line-end) + (forward-char col))) + (ht-set! line-col-to-point-map (cons line col) (if imenu-use-markers + (point-marker) + (point))))) + line-col-to-point-map)) + +(cl-defun lsp--line-col-comparator ((l1 . c1) (l2 . c2)) + (or (< l1 l2) + (and (= l1 l2) + (cond ((and c1 c2) + (< c1 c2)) + (c1 t))))) + +(defun lsp-imenu-create-uncategorized-index (symbols) + "Create imenu index from document SYMBOLS. +This function, unlike `lsp-imenu-create-categorized-index', does +not categorize by type, but instead returns an `imenu' index +corresponding to the symbol hierarchy returned by the server +directly." + (let* ((lsp--line-col-to-point-hash-table (-> symbols + lsp--collect-lines-and-cols + lsp--convert-line-col-to-points-batch))) + (if (lsp--imenu-hierarchical-p symbols) + (lsp--imenu-create-hierarchical-index symbols) + (lsp--imenu-create-non-hierarchical-index symbols)))) + +(defcustom lsp-imenu-symbol-kinds + '((1 . "Files") + (2 . "Modules") + (3 . "Namespaces") + (4 . "Packages") + (5 . "Classes") + (6 . "Methods") + (7 . "Properties") + (8 . "Fields") + (9 . "Constructors") + (10 . "Enums") + (11 . "Interfaces") + (12 . "Functions") + (13 . "Variables") + (14 . "Constants") + (15 . "Strings") + (16 . "Numbers") + (17 . "Booleans") + (18 . "Arrays") + (19 . "Objects") + (20 . "Keys") + (21 . "Nulls") + (22 . "Enum Members") + (23 . "Structs") + (24 . "Events") + (25 . "Operators") + (26 . "Type Parameters")) + "`lsp-symbol-kinds', but only used by `imenu'. +A new variable is needed, as it is `imenu' convention to use +pluralized categories, which `lsp-symbol-kinds' doesn't. If the +non-pluralized names are preferred, this can be set to +`lsp-symbol-kinds'." + :type '(alist :key-type integer :value-type string)) + +(defun lsp--imenu-kind->name (kind) + (alist-get kind lsp-imenu-symbol-kinds "?")) + +(defun lsp-imenu-create-top-level-categorized-index (symbols) + "Create an `imenu' index categorizing SYMBOLS by type. +Only root symbols are categorized. + +See `lsp-symbol-kinds' to customize the category naming. SYMBOLS +shall be a list of DocumentSymbols or SymbolInformation." + (mapcan + (-lambda ((type . symbols)) + (let ((cat (lsp--imenu-kind->name type)) + (symbols (lsp-imenu-create-uncategorized-index symbols))) + ;; If there is no :kind (this is being defensive), or we couldn't look it + ;; up, just display the symbols inline, without categories. + (if cat (list (cons cat symbols)) symbols))) + (sort (seq-group-by #'lsp:document-symbol-kind symbols) + (-lambda ((kinda) (kindb)) (< kinda kindb))))) + +(lsp-defun lsp--symbol->imenu ((sym &as &DocumentSymbol :selection-range (&RangeToPoint :start))) + "Convert an `&DocumentSymbol' to an `imenu' entry." + (cons (lsp-render-symbol sym lsp-imenu-detailed-outline) start)) + +(defun lsp--imenu-create-categorized-index-1 (symbols) + "Returns an `imenu' index from SYMBOLS categorized by type. +The result looks like this: ((\"Variables\" . (...)))." + (->> + symbols + (mapcan + (-lambda ((sym &as &DocumentSymbol :kind :children?)) + (if (seq-empty-p children?) + (list (list kind (lsp--symbol->imenu sym))) + (let ((parent (lsp-render-symbol sym lsp-imenu-detailed-outline))) + (cons + (list kind (lsp--symbol->imenu sym)) + (mapcar (-lambda ((type . imenu-items)) + (list type (cons parent (mapcan #'cdr imenu-items)))) + (-group-by #'car (lsp--imenu-create-categorized-index-1 children?)))))))) + (-group-by #'car) + (mapcar + (-lambda ((kind . syms)) + (cons kind (mapcan #'cdr syms)))))) + +(defun lsp--imenu-create-categorized-index (symbols) + (let ((syms (lsp--imenu-create-categorized-index-1 symbols))) + (dolist (sym syms) + (setcar sym (lsp--imenu-kind->name (car sym)))) + syms)) + +(lsp-defun lsp--symbol-information->imenu ((sym &as &SymbolInformation :location (&Location :range (&RangeToPoint :start)))) + (cons (lsp-render-symbol-information sym nil) start)) + +(defun lsp--imenu-create-categorized-index-flat (symbols) + "Create a kind-categorized index for SymbolInformation." + (mapcar (-lambda ((kind . syms)) + (cons (lsp--imenu-kind->name kind) + (mapcan (-lambda ((parent . children)) + (let ((children (mapcar #'lsp--symbol-information->imenu children))) + (if parent (list (cons parent children)) children))) + (-group-by #'lsp:symbol-information-container-name? syms)))) + (seq-group-by #'lsp:symbol-information-kind symbols))) + +(defun lsp-imenu-create-categorized-index (symbols) + (if (lsp--imenu-hierarchical-p symbols) + (lsp--imenu-create-categorized-index symbols) + (lsp--imenu-create-categorized-index-flat symbols))) + +(defcustom lsp-imenu-index-function #'lsp-imenu-create-uncategorized-index + "Function that should create an `imenu' index. +It will be called with a list of SymbolInformation or +DocumentSymbols, whose first level is already filtered. It shall +then return an appropriate `imenu' index (see +`imenu-create-index-function'). + +Note that this interface is not stable, and subject to change any +time." + :group 'lsp-imenu + :type '(radio + (const :tag "Categorize by type" + lsp-imenu-create-categorized-index) + (const :tag "Categorize root symbols by type" + lsp-imenu-create-top-level-categorized-index) + (const :tag "Uncategorized, inline entries" + lsp-imenu-create-uncategorized-index) + (function :tag "Custom function"))) + +(defun lsp--imenu-create-index () + "Create an `imenu' index based on the language server. +Respects `lsp-imenu-index-function'." + (let ((symbols (lsp--imenu-filter-symbols (lsp--get-document-symbols)))) + (funcall lsp-imenu-index-function symbols))) + +(defun lsp--imenu-filter-symbols (symbols) + "Filter out unsupported symbols from SYMBOLS." + (seq-remove #'lsp--symbol-ignore symbols)) + +(defun lsp--imenu-hierarchical-p (symbols) + "Determine whether any element in SYMBOLS has children." + (seq-some #'lsp-document-symbol? symbols)) + +(defun lsp--imenu-create-non-hierarchical-index (symbols) + "Create imenu index for non-hierarchical SYMBOLS. + +SYMBOLS are a list of DocumentSymbol messages. + +Return a nested alist keyed by symbol names. e.g. + + ((\"SomeClass\" (\"(Class)\" . 10) + (\"someField (Field)\" . 20) + (\"someFunction (Function)\" . 25) + (\"SomeSubClass\" (\"(Class)\" . 30) + (\"someSubField (Field)\" . 35)) + (\"someFunction (Function)\" . 40))" + (seq-map (lambda (nested-alist) + (cons (car nested-alist) + (seq-map #'lsp--symbol-to-imenu-elem (cdr nested-alist)))) + (seq-group-by #'lsp--get-symbol-type symbols))) + +(defun lsp--imenu-create-hierarchical-index (symbols) + "Create imenu index for hierarchical SYMBOLS. + +SYMBOLS are a list of DocumentSymbol messages. + +Return a nested alist keyed by symbol names. e.g. + + ((\"SomeClass\" (\"(Class)\" . 10) + (\"someField (Field)\" . 20) + (\"someFunction (Function)\" . 25) + (\"SomeSubClass\" (\"(Class)\" . 30) + (\"someSubField (Field)\" . 35)) + (\"someFunction (Function)\" . 40))" + (seq-map #'lsp--symbol-to-hierarchical-imenu-elem + (seq-sort #'lsp--imenu-symbol-lessp symbols))) + +(defun lsp--imenu-symbol-lessp (sym1 sym2) + (let* ((compare-results (mapcar (lambda (method) + (funcall (alist-get method lsp--imenu-compare-function-alist) + sym1 sym2)) + lsp-imenu-sort-methods)) + (result (seq-find (lambda (result) + (not (= result 0))) + compare-results + 0))) + (and (numberp result) (< result 0)))) + +(lsp-defun lsp--imenu-compare-kind ((&SymbolInformation :kind left) + (&SymbolInformation :kind right)) + "Compare SYM1 and SYM2 by kind." + (- left right)) + +(defun lsp--imenu-compare-line-col (sym1 sym2) + (if (lsp--line-col-comparator + (lsp--get-line-and-col sym1) + (lsp--get-line-and-col sym2)) + -1 + 1)) + +(lsp-defun lsp--imenu-compare-name ((&SymbolInformation :name name1) + (&SymbolInformation :name name2)) + "Compare SYM1 and SYM2 by name." + (let ((result (compare-strings name1 0 (length name1) name2 0 (length name2)))) + (if (numberp result) result 0))) + +(defun lsp--imenu-refresh () + "Force Imenu to refresh itself." + (imenu--menubar-select imenu--rescan-item)) + +(defun lsp-enable-imenu () + "Use lsp-imenu for the current buffer." + (imenu--cleanup) + (setq-local imenu-create-index-function #'lsp--imenu-create-index) + (setq-local imenu-menubar-modified-tick -1) + (setq-local imenu--index-alist nil) + (when menu-bar-mode + (lsp--imenu-refresh))) + +(defun lsp-resolve-final-function (command) + "Resolve final function COMMAND." + (-let [command (if (functionp command) (funcall command) command)] + (cl-etypecase command + (list + (cl-assert (seq-every-p (apply-partially #'stringp) command) nil + "Invalid command list") + command) + (string (list command))))) + +(defun lsp-server-present? (final-command) + "Check whether FINAL-COMMAND is present." + ;; executable-find only gained support for remote checks after 27 release + (or (and (cond + ((not (file-remote-p default-directory)) + (executable-find (cl-first final-command))) + ((version<= "27.0" emacs-version) + (with-no-warnings (executable-find (cl-first final-command) (file-remote-p default-directory)))) + (t)) + (prog1 t + (lsp-log "Command \"%s\" is present on the path." (s-join " " final-command)))) + (ignore (lsp-log "Command \"%s\" is not present on the path." (s-join " " final-command))))) + +(defun lsp--value-to-string (value) + "Convert VALUE to a string that can be set as value in an environment variable." + (cond + ((stringp value) value) + ((booleanp value) (if value + "1" + "0")) + ((and (sequencep value) + (seq-every-p #'stringp value)) (string-join value ":")) + (t (user-error "Only strings, booleans, and sequences of strings are supported as environment variables")))) + +(defun lsp--compute-process-environment (environment-fn) + "Append a list of KEY=VALUE from the alist ENVIRONMENT to `process-environment'. +Ignore non-boolean keys whose value is nil." + (let ((environment (if environment-fn + (funcall environment-fn) + nil))) + (-flatten (cons (cl-loop for (key . value) in environment + if (or (eval value) + (eq (get value 'custom-type) 'boolean)) + collect (concat key "=" (lsp--value-to-string + (eval value)))) + process-environment)))) + +(defun lsp-stdio-connection (command &optional test-command) + "Returns a connection property list using COMMAND. +COMMAND can be: A string, denoting the command to launch the +language server. A list of strings, denoting an executable with +its command line arguments. A function, that either returns a +string or a list of strings. In all cases, the launched language +server should send and receive messages on standard I/O. +TEST-COMMAND is a function with no arguments which returns +whether the command is present or not. When not specified +`lsp-mode' will check whether the first element of the list +returned by COMMAND is available via `executable-find'" + (cl-check-type command (or string + function + (and list + (satisfies (lambda (l) + (seq-every-p (lambda (el) + (stringp el)) + l)))))) + (list :connect (lambda (filter sentinel name environment-fn) + (let ((final-command (lsp-resolve-final-function command)) + (process-name (generate-new-buffer-name name)) + (process-environment + (lsp--compute-process-environment environment-fn))) + (let* ((stderr-buf (format "*%s::stderr*" process-name)) + (proc (make-process + :name process-name + :connection-type 'pipe + :buffer (format "*%s*" process-name) + :coding 'no-conversion + :command final-command + :filter filter + :sentinel sentinel + :stderr stderr-buf + :noquery t))) + (set-process-query-on-exit-flag proc nil) + (set-process-query-on-exit-flag (get-buffer-process stderr-buf) nil) + (with-current-buffer (get-buffer stderr-buf) + ;; Make the *NAME::stderr* buffer buffer-read-only, q to bury, etc. + (special-mode)) + (cons proc proc)))) + :test? (or + test-command + (lambda () (-> command lsp-resolve-final-function lsp-server-present?))))) + +(defun lsp--open-network-stream (host port name) + "Open network stream to HOST:PORT. + NAME will be passed to `open-network-stream'. + RETRY-COUNT is the number of the retries. + SLEEP-INTERVAL is the sleep interval between each retry." + (let* ((retries 0) + (sleep-interval 0.01) + (number-of-retries (/ lsp-tcp-connection-timeout sleep-interval)) + connection) + (while (and (not connection) (< retries number-of-retries)) + (condition-case err + (setq connection (open-network-stream name nil host port + :type 'plain + :coding 'no-conversion)) + (file-error + (let ((inhibit-message t)) + (lsp--warn "Failed to connect to %s:%s with error message %s" + host + port + (error-message-string err)) + (sleep-for sleep-interval) + (cl-incf retries))))) + (or connection (error "Port %s was never taken. Consider increasing `lsp-tcp-connection-timeout'." port)))) + +(defun lsp--find-available-port (host starting-port) + "Find available port on HOST starting from STARTING-PORT." + (let ((success nil) + (port starting-port)) + (while (and (not success)) + (condition-case _err + (progn + (delete-process (open-network-stream "*connection-test*" nil host port :type 'plain)) + (cl-incf port)) + (file-error (setq success t)))) + port)) + +(defun lsp-tcp-connection (command-fn) + "Returns a connection property list similar to `lsp-stdio-connection'. +COMMAND-FN can only be a function that takes a single argument, a +port number. It should return a command for launches a language server +process listening for TCP connections on the provided port." + (cl-check-type command-fn function) + (list + :connect (lambda (filter sentinel name environment-fn) + (let* ((host "localhost") + (port (lsp--find-available-port host (cl-incf lsp--tcp-port))) + (command (funcall command-fn port)) + (final-command (if (consp command) command (list command))) + (_ (unless (executable-find (cl-first final-command)) + (user-error (format "Couldn't find executable %s" (cl-first final-command))))) + (process-environment + (lsp--compute-process-environment environment-fn)) + (proc (make-process :name name :connection-type 'pipe :coding 'no-conversion + :command final-command :sentinel sentinel :stderr (format "*%s::stderr*" name) :noquery t)) + (tcp-proc (lsp--open-network-stream host port (concat name "::tcp")))) + + ;; TODO: Same :noquery issue (see above) + (set-process-query-on-exit-flag proc nil) + (set-process-query-on-exit-flag tcp-proc nil) + (set-process-filter tcp-proc filter) + (cons tcp-proc proc))) + :test? (lambda () (executable-find (cl-first (funcall command-fn 0)))))) + +(defalias 'lsp-tcp-server 'lsp-tcp-server-command) + +(defun lsp-tcp-server-command (command-fn) + "Create tcp server connection. +In this mode Emacs is TCP server and the language server connects +to it. COMMAND is function with one parameter(the port) and it +should return the command to start the LS server." + (cl-check-type command-fn function) + (list + :connect (lambda (filter sentinel name environment-fn) + (let* (tcp-client-connection + (tcp-server (make-network-process :name (format "*tcp-server-%s*" name) + :buffer (format "*tcp-server-%s*" name) + :family 'ipv4 + :service lsp--tcp-server-port + :sentinel (lambda (proc _string) + (lsp-log "Language server %s is connected." name) + (setf tcp-client-connection proc)) + :server 't)) + (port (process-contact tcp-server :service)) + (final-command (funcall command-fn port)) + (process-environment + (lsp--compute-process-environment environment-fn)) + (cmd-proc (make-process :name name + :connection-type 'pipe + :coding 'no-conversion + :command final-command + :stderr (format "*tcp-server-%s*::stderr" name) + :noquery t))) + (let ((retries 0)) + ;; wait for the client to connect (we sit-for 500 ms, so have to double lsp--tcp-server-wait-seconds) + (while (and (not tcp-client-connection) (< retries (* 2 lsp--tcp-server-wait-seconds))) + (lsp--info "Waiting for connection for %s, retries: %s" name retries) + (sit-for 0.500) + (cl-incf retries))) + + (unless tcp-client-connection + (condition-case nil (delete-process tcp-server) (error)) + (condition-case nil (delete-process cmd-proc) (error)) + (error "Failed to create connection to %s on port %s" name port)) + (lsp--info "Successfully connected to %s" name) + + (set-process-query-on-exit-flag cmd-proc nil) + (set-process-query-on-exit-flag tcp-client-connection nil) + (set-process-query-on-exit-flag tcp-server nil) + + (set-process-filter tcp-client-connection filter) + (set-process-sentinel tcp-client-connection sentinel) + (cons tcp-client-connection cmd-proc))) + :test? (lambda () (executable-find (cl-first (funcall command-fn 0)))))) + +(defun lsp-tramp-connection (local-command &optional generate-error-file-fn) + "Create LSP stdio connection named name. +LOCAL-COMMAND is either list of strings, string or function which +returns the command to execute." + (list :connect (lambda (filter sentinel name environment-fn) + (let* ((final-command (lsp-resolve-final-function local-command)) + ;; wrap with stty to disable converting \r to \n + (process-name (generate-new-buffer-name name)) + (wrapped-command (s-join + " " + (append '("stty" "raw" ";") + final-command + (list + (concat "2>" + (or (when generate-error-file-fn + (funcall generate-error-file-fn name)) + (format "/tmp/%s-%s-stderr" name + (cl-incf lsp--stderr-index)))))))) + (process-environment + (lsp--compute-process-environment environment-fn))) + (let ((proc (start-file-process-shell-command process-name + (format "*%s*" process-name) + wrapped-command))) + (set-process-sentinel proc sentinel) + (set-process-filter proc filter) + (set-process-query-on-exit-flag proc nil) + (set-process-coding-system proc 'binary 'binary) + (cons proc proc)))) + :test? (lambda () (-> local-command lsp-resolve-final-function lsp-server-present?)))) + +(defun lsp--auto-configure () + "Autoconfigure `company', `flycheck', `lsp-ui', etc if they are installed." + (when (functionp 'lsp-ui-mode) + (lsp-ui-mode)) + + (when lsp-headerline-breadcrumb-enable + (add-hook 'lsp-configure-hook 'lsp-headerline-breadcrumb-mode)) + (when lsp-modeline-code-actions-enable + (add-hook 'lsp-configure-hook 'lsp-modeline-code-actions-mode)) + (when lsp-modeline-diagnostics-enable + (add-hook 'lsp-configure-hook 'lsp-modeline-diagnostics-mode)) + (when lsp-modeline-workspace-status-enable + (add-hook 'lsp-configure-hook 'lsp-modeline-workspace-status-mode)) + (when lsp-lens-enable + (add-hook 'lsp-configure-hook 'lsp-lens--enable)) + (when lsp-semantic-tokens-enable + (add-hook 'lsp-configure-hook 'lsp-semantic-tokens--enable)) + + ;; yas-snippet config + (setq-local yas-inhibit-overlay-modification-protection t)) + +(defvar-local lsp--buffer-deferred nil + "Whether buffer was loaded via `lsp-deferred'.") + +(defun lsp--restart-if-needed (workspace) + "Handler restart for WORKSPACE." + (when (or (eq lsp-restart 'auto-restart) + (eq (lsp--workspace-shutdown-action workspace) 'restart) + (and (eq lsp-restart 'interactive) + (let ((query (format + "Server %s exited with status %s(check corresponding stderr buffer for details). Do you want to restart it?" + (lsp--workspace-print workspace) + (process-status (lsp--workspace-proc workspace))))) + (y-or-n-p query)))) + (--each (lsp--workspace-buffers workspace) + (when (lsp-buffer-live-p it) + (lsp-with-current-buffer it + (if lsp--buffer-deferred + (lsp-deferred) + (lsp--info "Restarting LSP in buffer %s" (buffer-name)) + (lsp))))))) + +(defun lsp--update-key (table key fn) + "Apply FN on value corresponding to KEY in TABLE." + (let ((existing-value (gethash key table))) + (if-let ((new-value (funcall fn existing-value))) + (puthash key new-value table) + (remhash key table)))) + +(defun lsp--process-sentinel (workspace process exit-str) + "Create the sentinel for WORKSPACE." + (unless (process-live-p process) + (let* ((status (process-status process)) + (folder->workspaces (lsp-session-folder->servers (lsp-session))) + (stderr (-> workspace lsp--workspace-proc process-name get-buffer))) + + (lsp--warn "%s has exited (%s)" + (process-name (lsp--workspace-proc workspace)) + (string-trim-right exit-str)) + + (with-lsp-workspace workspace + ;; Clean workspace related data in each of the buffers + ;; in the workspace. + (--each (lsp--workspace-buffers workspace) + (when (lsp-buffer-live-p it) + (lsp-with-current-buffer it + (setq lsp--buffer-workspaces (delete workspace lsp--buffer-workspaces)) + (lsp--uninitialize-workspace) + (lsp--spinner-stop) + (lsp--remove-overlays 'lsp-highlight)))) + + ;; Cleanup session from references to the closed workspace. + (--each (hash-table-keys folder->workspaces) + (lsp--update-key folder->workspaces it (apply-partially 'delete workspace))) + + ;; Kill standard error buffer only if the process exited normally. + ;; Leave it intact otherwise for debugging purposes. + (when (and (eq status 'exit) (zerop (process-exit-status process)) (buffer-live-p stderr)) + (kill-buffer stderr))) + + (run-hook-with-args 'lsp-after-uninitialized-functions workspace) + + (if (eq (lsp--workspace-shutdown-action workspace) 'shutdown) + (lsp--info "Workspace %s shutdown." (lsp--workspace-print workspace)) + (lsp--restart-if-needed workspace)) + (lsp--cleanup-hanging-watches)))) + +(defun lsp-workspace-folders (workspace) + "Return all folders associated with WORKSPACE." + (let (result) + (->> (lsp-session) + (lsp-session-folder->servers) + (maphash (lambda (folder workspaces) + (when (-contains? workspaces workspace) + (push folder result))))) + result)) + +(defun lsp--start-workspace (session client-template root &optional initialization-options) + "Create new workspace for CLIENT-TEMPLATE with project root ROOT. +INITIALIZATION-OPTIONS are passed to initialize function. +SESSION is the active session." + (lsp--spinner-start) + (-let* ((default-directory root) + (client (copy-lsp--client client-template)) + (workspace (make-lsp--workspace + :root root + :client client + :status 'starting + :buffers (list (lsp-current-buffer)) + :host-root (file-remote-p root))) + ((&lsp-cln 'server-id 'environment-fn 'new-connection 'custom-capabilities + 'multi-root 'initialized-fn) client) + ((proc . cmd-proc) (funcall + (or (plist-get new-connection :connect) + (user-error "Client %s is configured incorrectly" client)) + (lsp--create-filter-function workspace) + (apply-partially #'lsp--process-sentinel workspace) + (format "%s" server-id) + environment-fn)) + (workspace-folders (gethash server-id (lsp-session-server-id->folders session)))) + (setf (lsp--workspace-proc workspace) proc + (lsp--workspace-cmd-proc workspace) cmd-proc) + + ;; update (lsp-session-folder->servers) depending on whether we are starting + ;; multi/single folder workspace + (mapc (lambda (project-root) + (->> session + (lsp-session-folder->servers) + (gethash project-root) + (cl-pushnew workspace))) + (or workspace-folders (list root))) + + (with-lsp-workspace workspace + (run-hooks 'lsp-before-initialize-hook) + (lsp-request-async + "initialize" + (append + (list :processId nil + :rootPath (lsp-file-local-name (expand-file-name root)) + :clientInfo (list :name "emacs" + :version (emacs-version)) + :rootUri (lsp--path-to-uri root) + :capabilities (lsp--client-capabilities custom-capabilities) + :initializationOptions initialization-options + :workDoneToken "1") + (when lsp-server-trace + (list :trace lsp-server-trace)) + (when multi-root + (->> workspace-folders + (-distinct) + (-map (lambda (folder) + (list :uri (lsp--path-to-uri folder) + :name (f-filename folder)))) + (apply 'vector) + (list :workspaceFolders)))) + (lambda (response) + (unless response + (lsp--spinner-stop) + (signal 'lsp-empty-response-error (list "initialize"))) + + (let* ((capabilities (lsp:initialize-result-capabilities response)) + (json-object-type 'hash-table) + (text-document-sync (-some-> lsp-parsed-message + (json-read-from-string) + (ht-get "result") + (ht-get "capabilities") + (ht-get "textDocumentSync"))) + (save (when (ht? text-document-sync) + (ht-get text-document-sync "save")))) + ;; see #1807 + (when (and (ht? save) (ht-empty? save)) + (-> capabilities + (lsp:server-capabilities-text-document-sync?) + (lsp:set-text-document-sync-options-save? save))) + + (setf (lsp--workspace-server-capabilities workspace) capabilities + (lsp--workspace-status workspace) 'initialized) + + (with-lsp-workspace workspace + (lsp-notify "initialized" lsp--empty-ht)) + + (when initialized-fn (funcall initialized-fn workspace)) + + (cl-callf2 -filter #'lsp-buffer-live-p (lsp--workspace-buffers workspace)) + (->> workspace + (lsp--workspace-buffers) + (mapc (lambda (buffer) + (lsp-with-current-buffer buffer + (lsp--open-in-workspace workspace))))) + + (with-lsp-workspace workspace + (run-hooks 'lsp-after-initialize-hook)) + (lsp--info "%s initialized successfully in folders: %s" + (lsp--workspace-print workspace) + (lsp-workspace-folders workspace)))) + :mode 'detached)) + workspace)) + +(defun lsp--load-default-session () + "Load default session." + (setq lsp--session (or (condition-case err + (lsp--read-from-file lsp-session-file) + (error (lsp--error "Failed to parse the session %s, starting with clean one." + (error-message-string err)) + nil)) + (make-lsp-session)))) + +(defun lsp-session () + "Get the session associated with the current buffer." + (or lsp--session (setq lsp--session (lsp--load-default-session)))) + +(defun lsp--client-disabled-p (buffer-major-mode client) + (seq-some + (lambda (entry) + (pcase entry + ((pred symbolp) (eq entry client)) + (`(,mode . ,client-or-list) + (and (eq mode buffer-major-mode) + (if (listp client-or-list) + (memq client client-or-list) + (eq client client-or-list)))))) + lsp-disabled-clients)) + + +;; download server + +(defcustom lsp-server-install-dir (expand-file-name + (locate-user-emacs-file (f-join ".cache" "lsp"))) + "Directory in which the servers will be installed." + :risky t + :type 'directory + :package-version '(lsp-mode . "6.3") + :group 'lsp-mode) + +(defcustom lsp-verify-signature t + "Whether to check GPG signatures of downloaded files." + :type 'boolean + :package-version '(lsp-mode . "7.1") + :group 'lsp-mode) + +(defvar lsp--dependencies (ht)) + +(defun lsp-dependency (name &rest definitions) + "Used to specify a language server DEPENDENCY, the server +executable or other required file path. Typically, the +DEPENDENCY is found by locating it on the system path using +`executable-find'. + +You can explicitly call lsp-dependency in your environment to +specify the absolute path to the DEPENDENCY. For example, the +typescript-language-server requires both the server and the +typescript compiler. If you've installed them in a team shared +read-only location, you can instruct lsp-mode to use them via + + (eval-after-load 'lsp-mode + '(progn + (require 'lsp-javascript) + (lsp-dependency 'typescript-language-server `(:system ,tls-exe)) + (lsp-dependency 'typescript `(:system ,ts-js)))) + +where tls-exe is the absolute path to the typescript-language-server +executable and ts-js is the absolute path to the typescript compiler +JavaScript file, tsserver.js (the *.js is required for Windows)." + (ht-set lsp--dependencies name definitions)) + +(defun lsp--server-binary-present? (client) + (unless (equal (lsp--client-server-id client) 'lsp-pwsh) + (condition-case () + (-some-> client lsp--client-new-connection (plist-get :test?) funcall) + (error nil) + (args-out-of-range nil)))) + +(define-minor-mode lsp-installation-buffer-mode + "Mode used in *lsp-installation* buffers. +It can be used to set-up keybindings, etc. Disabling this mode +detaches the installation buffer from commands like +`lsp-select-installation-buffer'." + :init-value nil + :lighter nil) + +(defface lsp-installation-finished-buffer-face '((t :foreground "orange")) + "Face used for finished installation buffers. +Used in `lsp-select-installation-buffer'." + :group 'lsp-mode) + +(defface lsp-installation-buffer-face '((t :foreground "green")) + "Face used for installation buffers still in progress. +Used in `lsp-select-installation-buffer'." + :group 'lsp-mode) + +(defun lsp--installation-buffer? (buf) + "Check whether BUF is an `lsp-async-start-process' buffer." + (buffer-local-value 'lsp-installation-buffer-mode buf)) + +(defun lsp-select-installation-buffer (&optional show-finished) + "Interactively choose an installation buffer. +If SHOW-FINISHED is set, leftover (finished) installation buffers +are still shown." + (interactive "P") + (let ((bufs (--filter (and (lsp--installation-buffer? it) + (or show-finished (get-buffer-process it))) + (buffer-list)))) + (pcase bufs + (`nil (user-error "No installation buffers")) + (`(,buf) (pop-to-buffer buf)) + (bufs (pop-to-buffer (completing-read "Select installation buffer: " + (--map (propertize (buffer-name it) 'face + (if (get-buffer-process it) + 'lsp-installation-buffer-face + 'lsp-installation-finished-buffer-face)) + bufs))))))) + +(defun lsp-cleanup-installation-buffers () + "Delete finished *lsp-installation* buffers." + (interactive) + (dolist (buf (buffer-list)) + (when (and (lsp--installation-buffer? buf) (not (get-buffer-process buf))) + (kill-buffer buf)))) + +(defun lsp--download-status () + (-some--> #'lsp--client-download-in-progress? + (lsp--filter-clients it) + (-map (-compose #'symbol-name #'lsp--client-server-id) it) + (format "%s" it) + (propertize it 'face 'success) + (format " Installing following servers: %s" it) + (propertize it + 'local-map (make-mode-line-mouse-map + 'mouse-1 #'lsp-select-installation-buffer) + 'mouse-face 'highlight))) + +(defun lsp--install-server-internal (client &optional update?) + (unless (lsp--client-download-server-fn client) + (user-error "There is no automatic installation for `%s', you have to install it manually following lsp-mode's documentation." + (lsp--client-server-id client))) + + (setf (lsp--client-download-in-progress? client) t) + (add-to-list 'global-mode-string '(t (:eval (lsp--download-status)))) + (cl-flet ((done + (success? &optional error-message) + ;; run with idle timer to make sure the lsp command is executed in + ;; the main thread, see #2739. + (run-with-timer + 0.0 + nil + (lambda () + (-let [(&lsp-cln 'server-id 'buffers) client] + (setf (lsp--client-download-in-progress? client) nil + (lsp--client-buffers client) nil) + (if success? + (lsp--info "Server %s downloaded, auto-starting in %s buffers." server-id + (length buffers)) + (lsp--error "Server %s install process failed with the following error message: %s. +Check `*lsp-install*' and `*lsp-log*' buffer." + server-id + error-message)) + (seq-do + (lambda (buffer) + (when (lsp-buffer-live-p buffer) + (lsp-with-current-buffer buffer + (cl-callf2 -remove-item '(t (:eval (lsp--download-status))) + global-mode-string) + (when success? (lsp))))) + buffers) + (unless (lsp--filter-clients #'lsp--client-download-in-progress?) + (cl-callf2 -remove-item '(t (:eval (lsp--download-status))) + global-mode-string))))))) + (lsp--info "Download %s started." (lsp--client-server-id client)) + (condition-case err + (funcall + (lsp--client-download-server-fn client) + client + (lambda () (done t)) + (lambda (msg) (done nil msg)) + update?) + (error + (done nil (error-message-string err)))))) + +(defun lsp--require-packages () + "Load `lsp-client-packages' if needed." + (when (and lsp-auto-configure (not lsp--client-packages-required)) + (seq-do (lambda (package) + ;; loading client is slow and `lsp' can be called repeatedly + (unless (featurep package) + (require package nil t))) + lsp-client-packages) + (setq lsp--client-packages-required t))) + +;;;###autoload +(defun lsp-install-server (update? &optional server-id) + "Interactively install server. +When prefix UPDATE? is t force installation even if the server is present." + (interactive "P") + (lsp--require-packages) + (lsp--install-server-internal + (or (gethash server-id lsp-clients) + (lsp--completing-read + "Select server to install: " + (or (->> lsp-clients + (ht-values) + (-filter (-andfn + (-orfn (-not #'lsp--server-binary-present?) + (-const update?)) + (-not #'lsp--client-download-in-progress?) + #'lsp--client-download-server-fn))) + (user-error "There are no servers with automatic installation")) + (-compose #'symbol-name #'lsp--client-server-id) + nil + t)) + update?)) + +;;;###autoload +(defun lsp-ensure-server (server-id) + "Ensure server SERVER-ID" + (lsp--require-packages) + (if-let ((client (gethash server-id lsp-clients))) + (unless (lsp--server-binary-present? client) + (lsp--info "Server `%s' is not preset, installing..." server-id) + (lsp-install-server nil server-id)) + (warn "Unable to find server registration with id %s" server-id))) + +(defun lsp-async-start-process (callback error-callback &rest command) + "Start async process COMMAND with CALLBACK and ERROR-CALLBACK." + (let ((name (cl-first command))) + (with-current-buffer (compilation-start (mapconcat #'shell-quote-argument command " ") t + (lambda (&rest _) + (generate-new-buffer-name (format "*lsp-install: %s*" name)))) + (lsp-installation-buffer-mode +1) + (add-hook + 'compilation-finish-functions + (lambda (_buf status) + (if (string= "finished\n" status) + (condition-case err + (funcall callback) + (error + (funcall error-callback (error-message-string err)))) + (funcall error-callback (s-trim-right status)))) + nil t)))) + +(defun lsp-resolve-value (value) + "Resolve VALUE's value. +If it is function - call it. +If it is symbol - return it's value +Otherwise returns value itself." + (cond + ((functionp value) (funcall value)) + ((symbolp value) (symbol-value value)) + (value))) + +(defvar lsp-deps-providers + (list :npm (list :path #'lsp--npm-dependency-path + :install #'lsp--npm-dependency-install) + :system (list :path #'lsp--system-path) + :download (list :path #'lsp-download-path + :install #'lsp-download-install))) + +(defun lsp--system-path (path) + "If PATH is absolute and exists return it as is. Otherwise, +return the absolute path to the executable defined by PATH or +nil." + ;; For node.js 'sub-packages' PATH may point to a *.js file. Consider the + ;; typescript-language-server. When lsp invokes the server, lsp needs to + ;; supply the path to the typescript compiler, tsserver.js, as an argument. To + ;; make code platform independent, one must pass the absolute path to the + ;; tsserver.js file (Windows requires a *.js file - see help on the JavaScript + ;; child process spawn command that is invoked by the + ;; typescript-language-server). This is why we check for existence and not + ;; that the path is executable. + (let ((path (lsp-resolve-value path))) + (if (and (f-absolute? path) + (f-exists? path)) + path + (executable-find path)))) + +(defun lsp-package-path (dependency) + "Path to the DEPENDENCY each of the registered providers." + (let (path) + (-first (-lambda ((provider . rest)) + (setq path (-some-> lsp-deps-providers + (plist-get provider) + (plist-get :path) + (apply rest)))) + (gethash dependency lsp--dependencies)) + path)) + +(defun lsp-package-ensure (dependency callback error-callback) + "Asynchronously ensure a package." + (or (-first (-lambda ((provider . rest)) + (-some-> lsp-deps-providers + (plist-get provider) + (plist-get :install) + (apply (cl-list* callback error-callback rest)))) + (gethash dependency lsp--dependencies)) + (funcall error-callback (format "Unable to find a way to install %s" dependency)))) + + +;; npm handling + +;; https://docs.npmjs.com/files/folders#executables +(cl-defun lsp--npm-dependency-path (&key package path &allow-other-keys) + "Return npm dependency PATH for PACKAGE." + (let ((path (executable-find + (f-join lsp-server-install-dir "npm" package + (cond ((eq system-type 'windows-nt) "") + (t "bin")) + path)))) + (unless (and path (f-exists? path)) + (error "The package %s is not installed. Unable to find %s" package path)) + path)) + +(cl-defun lsp--npm-dependency-install (callback error-callback &key package &allow-other-keys) + (if-let ((npm-binary (executable-find "npm"))) + (progn + ;; Explicitly `make-directory' to work around NPM bug in + ;; versions 7.0.0 through 7.4.1. See + ;; https://github.com/emacs-lsp/lsp-mode/issues/2364 for + ;; discussion. + (make-directory (f-join lsp-server-install-dir "npm" package "lib") 'parents) + (lsp-async-start-process callback + error-callback + npm-binary + "-g" + "--prefix" + (f-join lsp-server-install-dir "npm" package) + "install" + package)) + (lsp-log "Unable to install %s via `npm' because it is not present" package) + nil)) + + +;; Download URL handling +(cl-defun lsp-download-install (callback error-callback &key url asc-url pgp-key store-path decompress &allow-other-keys) + (let* ((url (lsp-resolve-value url)) + (store-path (lsp-resolve-value store-path)) + ;; (decompress (lsp-resolve-value decompress)) + (download-path + (pcase decompress + (:gzip (concat store-path ".gz")) + (:zip (concat store-path ".zip")) + (`nil store-path) + (_ (error ":decompress must be `:gzip', `:zip' or `nil'"))))) + (make-thread + (lambda () + (condition-case err + (progn + (when (f-exists? download-path) + (f-delete download-path)) + (when (f-exists? store-path) + (f-delete store-path)) + (lsp--info "Starting to download %s to %s..." url download-path) + (mkdir (f-parent download-path) t) + (url-copy-file url download-path) + (lsp--info "Finished downloading %s..." download-path) + (when (and lsp-verify-signature asc-url pgp-key) + (if (executable-find epg-gpg-program) + (let ((asc-download-path (concat download-path ".asc")) + (context (epg-make-context)) + (fingerprint) + (signature)) + (when (f-exists? asc-download-path) + (f-delete asc-download-path)) + (lsp--info "Starting to download %s to %s..." asc-url asc-download-path) + (url-copy-file asc-url asc-download-path) + (lsp--info "Finished downloading %s..." asc-download-path) + (epg-import-keys-from-string context pgp-key) + (setq fingerprint (epg-import-status-fingerprint + (car + (epg-import-result-imports + (epg-context-result-for context 'import))))) + (lsp--info "Verifying signature %s..." asc-download-path) + (epg-verify-file context asc-download-path download-path) + (setq signature (car (epg-context-result-for context 'verify))) + (unless (and + (eq (epg-signature-status signature) 'good) + (equal (epg-signature-fingerprint signature) fingerprint)) + (error "Failed to verify GPG signature: %s" (epg-signature-to-string signature)))) + (lsp--warn "GPG is not installed, skipping the signature check."))) + (when decompress + (lsp--info "Decompressing %s..." download-path) + (pcase decompress + (:gzip + (lsp-gunzip download-path)) + (:zip (lsp-unzip download-path (f-parent store-path)))) + (lsp--info "Decompressed %s..." store-path)) + (funcall callback)) + (error (funcall error-callback err))))))) + +(cl-defun lsp-download-path (&key store-path binary-path set-executable? &allow-other-keys) + "Download URL and store it into STORE-PATH. + +SET-EXECUTABLE? when non-nil change the executable flags of +STORE-PATH to make it executable. BINARY-PATH can be specified +when the binary to start does not match the name of the +archieve(e. g. when the archieve has multiple files)" + (let ((store-path (or (lsp-resolve-value binary-path) + (lsp-resolve-value store-path)))) + (cond + ((executable-find store-path) store-path) + ((and set-executable? (f-exists? store-path)) + (set-file-modes store-path #o0700) + store-path) + ((f-exists? store-path) store-path)))) + +;; unzip + +(defconst lsp-ext-pwsh-script "powershell -noprofile -noninteractive \ +-nologo -ex bypass Expand-Archive -path '%s' -dest '%s'" + "Powershell script to unzip file.") + +(defconst lsp-ext-unzip-script "bash -c 'mkdir -p %2$s && unzip -qq -o %1$s -d %2$s'" + "Unzip script to unzip file.") + +(defcustom lsp-unzip-script (cond ((executable-find "powershell") lsp-ext-pwsh-script) + ((executable-find "unzip") lsp-ext-unzip-script) + (t nil)) + "The script to unzip." + :group 'lsp-mode + :type 'string + :package-version '(lsp-mode . "7.1")) + +(defun lsp-unzip (zip-file dest) + "Unzip ZIP-FILE to DEST." + (unless lsp-unzip-script + (error "Unable to find `unzip' or `powershell' on the path, please customize `lsp-unzip-script'")) + (shell-command (format lsp-unzip-script zip-file dest))) + +;; gunzip + +(defconst lsp-ext-gunzip-script "gzip -d %1$s" + "Script to decompress a gzippped file with gzip.") + +(defcustom lsp-gunzip-script (cond ((executable-find "gzip") lsp-ext-gunzip-script) + (t nil)) + "The script to decompress a gzipped file. +Should be a format string with one argument for the file to be decompressed +in place." + :group 'lsp-mode + :type 'string + :package-version '(lsp-mode . "7.1")) + +(defun lsp-gunzip (gz-file) + "Decompress GZ-FILE in place." + (unless lsp-gunzip-script + (error "Unable to find `gzip' on the path, please either customize `lsp-gunzip-script' or manually decompress %s" gz-file)) + (shell-command (format lsp-gunzip-script gz-file))) + +;; VSCode marketplace + +(defcustom lsp-vscode-ext-url + "https://marketplace.visualstudio.com/_apis/public/gallery/publishers/%s/vsextensions/%s/%s/vspackage" + "Vscode extension template url." + :group 'lsp-mode + :type 'string + :package-version '(lsp-mode . "7.1")) + +(defun lsp-vscode-extension-url (publisher name &optional version) + "Return the URL to vscode extension. +PUBLISHER is the extension publisher. +NAME is the name of the extension. +VERSION is the version of the extension, defaults to `latest'" + (format lsp-vscode-ext-url publisher name (or version "latest"))) + + + +;; Queueing prompts + +(defvar lsp--question-queue nil + "List of questions yet to be asked by `lsp-ask-question'.") + +(defun lsp-ask-question (question options callback) + "Prompt the user to answer the QUESTION with one of the OPTIONS from the +minibuffer. Once the user selects an option, the CALLBACK function will be +called, passing the selected option to it. + +If the user is currently being shown a question, the question will be stored in +`lsp--question-queue', and will be asked once the user has answered the current +question." + (add-to-list 'lsp--question-queue `(("question" . ,question) + ("options" . ,options) + ("callback" . ,callback)) t) + (when (eq (length lsp--question-queue) 1) + (lsp--process-question-queue))) + +(defun lsp--process-question-queue () + "Take the first question from `lsp--question-queue', process it, then process +the next question until the queue is empty." + (-let* (((&alist "question" "options" "callback") (car lsp--question-queue)) + (answer (completing-read question options nil t))) + (pop lsp--question-queue) + (funcall callback answer) + (when lsp--question-queue + (lsp--process-question-queue)))) + +(defun lsp--matching-clients? (client) + (and + ;; both file and client remote or both local + (eq (---truthy? (file-remote-p (buffer-file-name))) + (---truthy? (lsp--client-remote? client))) + + ;; activation function or major-mode match. + (if-let ((activation-fn (lsp--client-activation-fn client))) + (funcall activation-fn (buffer-file-name) major-mode) + (-contains? (lsp--client-major-modes client) major-mode)) + + ;; check whether it is enabled if `lsp-enabled-clients' is not null + (or (null lsp-enabled-clients) + (or (member (lsp--client-server-id client) lsp-enabled-clients) + (ignore (lsp--info "Client %s is not in lsp-enabled-clients" + (lsp--client-server-id client))))) + + ;; check whether it is not disabled. + (not (lsp--client-disabled-p major-mode (lsp--client-server-id client))))) + +(defun lsp--filter-clients (pred) + (->> lsp-clients hash-table-values (-filter pred))) + +(defun lsp--find-clients () + "Find clients which can handle BUFFER-MAJOR-MODE. +SESSION is the currently active session. The function will also +pick only remote enabled clients in case the FILE-NAME is on +remote machine and vice versa." + (-when-let (matching-clients (lsp--filter-clients (-andfn #'lsp--matching-clients? + #'lsp--server-binary-present?))) + (lsp-log "Found the following clients for %s: %s" + (buffer-file-name) + (s-join ", " + (-map (lambda (client) + (format "(server-id %s, priority %s)" + (lsp--client-server-id client) + (lsp--client-priority client))) + matching-clients))) + (-let* (((add-on-clients main-clients) (-separate #'lsp--client-add-on? matching-clients)) + (selected-clients (if-let ((main-client (and main-clients + (--max-by (> (lsp--client-priority it) + (lsp--client-priority other)) + main-clients)))) + (cons main-client add-on-clients) + add-on-clients))) + (lsp-log "The following clients were selected based on priority: %s" + (s-join ", " + (-map (lambda (client) + (format "(server-id %s, priority %s)" + (lsp--client-server-id client) + (lsp--client-priority client))) + selected-clients))) + selected-clients))) + +(defun lsp-register-client (client) + "Registers LSP client CLIENT." + (cl-assert (symbolp (lsp--client-server-id client)) t) + (cl-assert (or + (functionp (lsp--client-activation-fn client)) + (and (listp (lsp--client-major-modes client)) + (seq-every-p (apply-partially #'symbolp) + (lsp--client-major-modes client)))) + nil "Invalid activation-fn and/or major-modes.") + (let ((client-id (lsp--client-server-id client))) + (puthash client-id client lsp-clients) + (setplist (intern (format "lsp-%s-after-open-hook" client-id)) + `( standard-value (nil) custom-type hook + custom-package-version (lsp-mode . "7.0.1") + variable-documentation ,(format "Hooks to run after `%s' server is run." client-id) + custom-requests nil)))) + +(defun lsp--create-initialization-options (_session client) + "Create initialization-options from SESSION and CLIENT. +Add workspace folders depending on server being multiroot and +session workspace folder configuration for the server." + (let* ((initialization-options-or-fn (lsp--client-initialization-options client))) + (if (functionp initialization-options-or-fn) + (funcall initialization-options-or-fn) + initialization-options-or-fn))) + +(defvar lsp-client-settings nil + "For internal use, any external users please use + `lsp-register-custom-settings' function instead") + +(defun lsp--compare-setting-path (a b) + (equal (car a) (car b))) + +(defun lsp-register-custom-settings (props) + "Register PROPS. +PROPS is list of triple (path value boolean?) where PATH is the path to the +property; VALUE can be a literal value, symbol to be evaluated, or either a +function or lambda function to be called without arguments; BOOLEAN? is an +optional flag that should be non-nil for boolean settings, when it is nil the +property will be ignored if the VALUE is nil. + +Example: `(lsp-register-custom-settings '((\"foo.bar.buzz.enabled\" t t)))' +\(note the double parentheses)" + (let ((-compare-fn #'lsp--compare-setting-path)) + (setq lsp-client-settings (-uniq (append props lsp-client-settings))))) + +(defun lsp-region-text (region) + "Get the text for REGION in current buffer." + (-let (((start . end) (lsp--range-to-region region))) + (buffer-substring-no-properties start end))) + +(defun lsp-ht-set (tbl paths value) + "Set nested hash table value. +TBL - a hash table, PATHS is the path to the nested VALUE." + (pcase paths + (`(,path) (ht-set! tbl path value)) + (`(,path . ,rst) (let ((nested-tbl (or (gethash path tbl) + (let ((temp-tbl (ht))) + (ht-set! tbl path temp-tbl) + temp-tbl)))) + (lsp-ht-set nested-tbl rst value))))) + +(defun lsp-configuration-section (section) + "Get settings for SECTION." + (let ((ret (ht-create))) + (mapc (-lambda ((path variable boolean?)) + (when (s-matches? (concat (regexp-quote section) "\\..*") path) + (let* ((symbol-value (-> variable + lsp-resolve-value + lsp-resolve-value)) + (value (if (and boolean? (not symbol-value)) + :json-false + symbol-value))) + (when (or boolean? value) + (lsp-ht-set ret (s-split "\\." path) value))))) + lsp-client-settings) + ret)) + +(defun lsp--start-connection (session client project-root) + "Initiates connection created from CLIENT for PROJECT-ROOT. +SESSION is the active session." + (when (lsp--client-multi-root client) + (cl-pushnew project-root (gethash (lsp--client-server-id client) + (lsp-session-server-id->folders session)))) + (run-hook-with-args 'lsp-workspace-folders-changed-functions (list project-root) nil) + + (unwind-protect + (lsp--start-workspace session client project-root (lsp--create-initialization-options session client)) + (lsp--spinner-stop))) + +;; lsp-log-io-mode + +(defvar lsp-log-io-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "M-n") #'lsp-log-io-next) + (define-key map (kbd "M-p") #'lsp-log-io-prev) + (define-key map (kbd "k") #'lsp--erase-log-buffer) + (define-key map (kbd "K") #'lsp--erase-session-log-buffers) + map) + "Keymap for lsp log buffer mode.") + +(define-derived-mode lsp-log-io-mode special-mode "LspLogIo" + "Special mode for viewing IO logs.") + +(defun lsp-workspace-show-log (workspace) + "Display the log buffer of WORKSPACE." + (interactive + (list (if lsp-print-io + (if (eq (length (lsp-workspaces)) 1) + (cl-first (lsp-workspaces)) + (lsp--completing-read "Workspace: " (lsp-workspaces) + #'lsp--workspace-print nil t)) + (user-error "IO logging is disabled")))) + (pop-to-buffer (lsp--get-log-buffer-create workspace))) + +(defalias 'lsp-switch-to-io-log-buffer 'lsp-workspace-show-log) + +(defun lsp--get-log-buffer-create (workspace) + "Return the lsp log buffer of WORKSPACE, creating a new one if needed." + (let ((server-id (-> workspace lsp--workspace-client lsp--client-server-id symbol-name)) + (pid (format "%s" (process-id (lsp--workspace-cmd-proc workspace))))) + (get-buffer-create (format "*lsp-log: %s:%s*" server-id pid)))) + +(defun lsp--erase-log-buffer (&optional all) + "Delete contents of current lsp log buffer. +When ALL is t, erase all log buffers of the running session." + (interactive) + (let* ((workspaces (lsp--session-workspaces (lsp-session))) + (current-log-buffer (current-buffer))) + (dolist (w workspaces) + (let ((b (lsp--get-log-buffer-create w))) + (when (or all (eq b current-log-buffer)) + (with-current-buffer b + (let ((inhibit-read-only t)) + (erase-buffer)))))))) + +(defun lsp--erase-session-log-buffers () + "Erase log buffers of the running session." + (interactive) + (lsp--erase-log-buffer t)) + +(defun lsp-log-io-next (arg) + "Move to next log entry." + (interactive "P") + (ewoc-goto-next lsp--log-io-ewoc (or arg 1))) + +(defun lsp-log-io-prev (arg) + "Move to previous log entry." + (interactive "P") + (ewoc-goto-prev lsp--log-io-ewoc (or arg 1))) + +(defun lsp--workspace-print (workspace) + "Visual representation WORKSPACE." + (let* ((proc (lsp--workspace-cmd-proc workspace)) + (status (lsp--workspace-status workspace)) + (server-id (-> workspace lsp--workspace-client lsp--client-server-id symbol-name)) + (pid (process-id proc))) + + (if (eq 'initialized status) + (format "%s:%s" server-id pid) + (format "%s:%s/%s" server-id pid status)))) + +(defun lsp--map-tree-widget (m) + "Build `tree-widget' from a hash-table M." + (when (hash-table-p m) + (let (nodes) + (maphash (lambda (k v) + (push `(tree-widget + :tag ,(if (hash-table-p v) + (format "%s:" k) + (format "%s: %s" k + (propertize (format "%s" v) + 'face + 'font-lock-string-face))) + :open t + ,@(lsp--map-tree-widget v)) + nodes)) + m) + nodes))) + +(defun lsp-buffer-name (buffer-id) + (if-let ((buffer-name (plist-get buffer-id :buffer-name))) + (funcall buffer-name buffer-id) + (buffer-name buffer-id))) + +(defun lsp--render-workspace (workspace) + "Tree node representation of WORKSPACE." + `(tree-widget :tag ,(lsp--workspace-print workspace) + :open t + (tree-widget :tag ,(propertize "Buffers" 'face 'font-lock-function-name-face) + :open t + ,@(->> workspace + (lsp--workspace-buffers) + (--map `(tree-widget + :tag ,(when (lsp-buffer-live-p it) + (let ((buffer-name (lsp-buffer-name it))) + (if (lsp-with-current-buffer it buffer-read-only) + (propertize buffer-name 'face 'font-lock-constant-face) + buffer-name))))))) + (tree-widget :tag ,(propertize "Capabilities" 'face 'font-lock-function-name-face) + ,@(-> workspace lsp--workspace-server-capabilities lsp--map-tree-widget)))) + +(define-derived-mode lsp-browser-mode special-mode "LspBrowser" + "Define mode for displaying lsp sessions." + (setq-local display-buffer-base-action '(nil . ((inhibit-same-window . t))))) + +(defun lsp-describe-session () + "Describes current `lsp-session'." + (interactive) + (let ((session (lsp-session)) + (buf (get-buffer-create "*lsp session*"))) + (with-current-buffer buf + (lsp-browser-mode) + (let ((inhibit-read-only t)) + (erase-buffer) + (--each (lsp-session-folders session) + (widget-create + `(tree-widget + :tag ,(propertize it 'face 'font-lock-keyword-face) + :open t + ,@(->> session + (lsp-session-folder->servers) + (gethash it) + (-map 'lsp--render-workspace))))))) + (pop-to-buffer buf))) + +(defun lsp--session-workspaces (session) + "Get all workspaces that are part of the SESSION." + (-> session lsp-session-folder->servers hash-table-values -flatten -uniq)) + +(defun lsp--find-multiroot-workspace (session client project-root) + "Look for a multiroot connection in SESSION created from CLIENT for PROJECT-ROOT and BUFFER-MAJOR-MODE." + (when (lsp--client-multi-root client) + (-when-let (multi-root-workspace (->> session + (lsp--session-workspaces) + (--first (eq (-> it lsp--workspace-client lsp--client-server-id) + (lsp--client-server-id client))))) + (with-lsp-workspace multi-root-workspace + (lsp-notify "workspace/didChangeWorkspaceFolders" + (lsp-make-did-change-workspace-folders-params + :event (lsp-make-workspace-folders-change-event + :added (vector (lsp-make-workspace-folder + :uri (lsp--path-to-uri project-root) + :name (f-filename project-root))) + :removed [])))) + + (->> session (lsp-session-folder->servers) (gethash project-root) (cl-pushnew multi-root-workspace)) + (->> session (lsp-session-server-id->folders) (gethash (lsp--client-server-id client)) (cl-pushnew project-root)) + + (lsp--persist-session session) + + (lsp--info "Opened folder %s in workspace %s" project-root (lsp--workspace-print multi-root-workspace)) + (lsp--open-in-workspace multi-root-workspace) + + multi-root-workspace))) + +(defun lsp--ensure-lsp-servers (session clients project-root ignore-multi-folder) + "Ensure that SESSION contain server CLIENTS created for PROJECT-ROOT. +IGNORE-MULTI-FOLDER to ignore multi folder server." + (-map (lambda (client) + (or + (lsp--find-workspace session client project-root) + (unless ignore-multi-folder + (lsp--find-multiroot-workspace session client project-root)) + (lsp--start-connection session client project-root))) + clients)) + +(defun lsp--spinner-stop () + "Stop the spinner in case all of the workspaces are started." + (when (--all? (eq (lsp--workspace-status it) 'initialized) + lsp--buffer-workspaces) + (spinner-stop))) + +(defun lsp--open-in-workspace (workspace) + "Open in existing WORKSPACE." + (if (eq 'initialized (lsp--workspace-status workspace)) + ;; when workspace is initialized just call document did open. + (progn + (with-lsp-workspace workspace + (when-let ((before-document-open-fn (-> workspace + lsp--workspace-client + lsp--client-before-file-open-fn))) + (funcall before-document-open-fn workspace)) + (lsp--text-document-did-open)) + (lsp--spinner-stop)) + ;; when it is not initialized + (lsp--spinner-start) + (cl-pushnew (lsp-current-buffer) (lsp--workspace-buffers workspace)))) + +(defun lsp--find-workspace (session client project-root) + "Find server connection created with CLIENT in SESSION for PROJECT-ROOT." + (when-let ((workspace (->> session + (lsp-session-folder->servers) + (gethash project-root) + (--first (eql (-> it lsp--workspace-client lsp--client-server-id) + (lsp--client-server-id client)))))) + (lsp--open-in-workspace workspace) + workspace)) + +(defun lsp--find-root-interactively (session) + "Find project interactively. +Returns nil if the project should not be added to the current SESSION." + (condition-case nil + (let* ((project-root-suggestion (or (lsp--suggest-project-root) default-directory)) + (action (read-key (format + "%s is not part of any project. Select action: + +%s==>Import project root %s. +%s==>Import project by selecting root directory interactively. +%s==>Do not ask again for the current project by adding %s to lsp-session-folders-blacklist. +%s==>Do not ask again for the current project by selecting ignore path interactively. +%s==>Do nothing: ask again when opening other files from the current project." + (propertize (buffer-name) 'face 'bold) + (propertize "i" 'face 'success) + (propertize project-root-suggestion 'face 'bold) + (propertize "I" 'face 'success) + (propertize "d" 'face 'warning) + (propertize project-root-suggestion 'face 'bold) + (propertize "D" 'face 'warning) + (propertize "n" 'face 'warning))))) + (cl-case action + (?i project-root-suggestion) + (?\r project-root-suggestion) + (?I (read-directory-name "Select workspace folder to add: " + (or project-root-suggestion default-directory) + nil + t)) + (?d (push project-root-suggestion (lsp-session-folders-blacklist session)) + (lsp--persist-session session) + nil) + (?D (push (read-directory-name "Select folder to blacklist: " + (or project-root-suggestion default-directory) + nil + t) + (lsp-session-folders-blacklist session)) + (lsp--persist-session session) + nil) + (t nil))) + ('quit))) + +(declare-function tramp-file-name-host "ext:tramp" (file) t) +(declare-function tramp-dissect-file-name "ext:tramp" (file &optional nodefault)) + +(defun lsp--files-same-host (f1 f2) + "Predicate on whether or not two files are on the same host." + (or (not (or (file-remote-p f1) (file-remote-p f2))) + (and (file-remote-p f1) + (file-remote-p f2) + (progn (require 'tramp) + (equal (tramp-file-name-host (tramp-dissect-file-name f1)) + (tramp-file-name-host (tramp-dissect-file-name f2))))))) + +(defun lsp-find-session-folder (session file-name) + "Look in the current SESSION for folder containing FILE-NAME." + (let ((file-name-canonical (lsp-f-canonical file-name))) + (->> session + (lsp-session-folders) + (--filter (and (lsp--files-same-host it file-name-canonical) + (or (lsp-f-same? it file-name-canonical) + (and (f-dir? it) + (lsp-f-ancestor-of? it file-name-canonical))))) + (--max-by (> (length it) + (length other)))))) + +(defun lsp-find-workspace (server-id &optional file-name) + "Find workspace for SERVER-ID for FILE-NAME." + (-when-let* ((session (lsp-session)) + (folder->servers (lsp-session-folder->servers session)) + (workspaces (if file-name + (gethash (lsp-find-session-folder session file-name) folder->servers) + (lsp--session-workspaces session)))) + + (--first (eq (lsp--client-server-id (lsp--workspace-client it)) server-id) workspaces))) + +(defun lsp--calculate-root (session file-name) + "Calculate project root for FILE-NAME in SESSION." + (and + (->> session + (lsp-session-folders-blacklist) + (--first (and (lsp--files-same-host it file-name) + (lsp-f-ancestor-of? it file-name) + (prog1 t + (lsp--info "File %s is in blacklisted directory %s" file-name it)))) + not) + (or + (when lsp-auto-guess-root + (lsp--suggest-project-root)) + (lsp-find-session-folder session file-name) + (unless lsp-auto-guess-root + (lsp--find-root-interactively session))))) + +(defun lsp--try-open-in-library-workspace () + "Try opening current file as library file in any of the active workspace. +The library folders are defined by each client for each of the active workspace." + (when-let ((workspace (->> (lsp-session) + (lsp--session-workspaces) + ;; Sort the last active workspaces first as they are more likely to be + ;; the correct ones, especially when jumping to a definition. + (-sort (lambda (a _b) + (-contains? lsp--last-active-workspaces a))) + (--first + (and (-> it lsp--workspace-client lsp--matching-clients?) + (when-let ((library-folders-fn + (-> it lsp--workspace-client lsp--client-library-folders-fn))) + (-first (lambda (library-folder) + (lsp-f-ancestor-of? library-folder (buffer-file-name))) + (funcall library-folders-fn it)))))))) + (lsp--open-in-workspace workspace) + (view-mode t) + (lsp--info "Opening read-only library file %s." (buffer-file-name)) + (list workspace))) + +(defun lsp--persist-session (session) + "Persist SESSION to `lsp-session-file'." + (lsp--persist lsp-session-file (make-lsp-session + :folders (lsp-session-folders session) + :folders-blacklist (lsp-session-folders-blacklist session) + :server-id->folders (lsp-session-server-id->folders session)))) + +(defun lsp--try-project-root-workspaces (ask-for-client ignore-multi-folder) + "Try create opening file as a project file. +When IGNORE-MULTI-FOLDER is t the lsp mode will start new +language server even if there is language server which can handle +current language. When IGNORE-MULTI-FOLDER is nil current file +will be opened in multi folder language server if there is +such." + (-let ((session (lsp-session))) + (-if-let (clients (if ask-for-client + (list (lsp--completing-read "Select server to start: " + (ht-values lsp-clients) + (-compose 'symbol-name 'lsp--client-server-id) nil t)) + (lsp--find-clients))) + (-if-let (project-root (-some-> session + (lsp--calculate-root (buffer-file-name)) + (lsp-f-canonical))) + (progn + ;; update project roots if needed and persist the lsp session + (unless (-contains? (lsp-session-folders session) project-root) + (cl-pushnew project-root (lsp-session-folders session)) + (lsp--persist-session session)) + (lsp--ensure-lsp-servers session clients project-root ignore-multi-folder)) + (lsp--warn "%s not in project or it is blacklisted." (buffer-name)) + nil) + (lsp--warn "No LSP server for %s(check *lsp-log*)." major-mode) + nil))) + +(defun lsp-shutdown-workspace () + "Shutdown language server." + (interactive) + (--when-let (pcase (lsp-workspaces) + (`nil (user-error "There are no active servers in the current buffer")) + (`(,workspace) (when (y-or-n-p (format "Are you sure you want to stop the server %s?" + (lsp--workspace-print workspace))) + workspace)) + (workspaces (lsp--completing-read "Select server: " + workspaces + 'lsp--workspace-print nil t))) + (lsp-workspace-shutdown it))) + +(make-obsolete 'lsp-shutdown-workspace 'lsp-workspace-shutdown "lsp-mode 6.1") + +(defcustom lsp-auto-select-workspace t + "Shutdown or restart a single workspace. +If set and the current buffer has only a single workspace +associated with it, `lsp-shutdown-workspace' and +`lsp-restart-workspace' will act on it without asking." + :type 'boolean + :group 'lsp-mode) + +(defun lsp--read-workspace () + "Ask the user to select a workspace. +Errors if there are none." + (pcase (lsp-workspaces) + (`nil (error "No workspaces associated with the current buffer")) + ((and `(,workspace) (guard lsp-auto-select-workspace)) workspace) + (workspaces (lsp--completing-read "Select workspace: " workspaces + #'lsp--workspace-print nil t)))) + +(defun lsp-workspace-shutdown (workspace) + "Shut the workspace WORKSPACE and the language server associated with it" + (interactive (list (lsp--read-workspace))) + (lsp--warn "Stopping %s" (lsp--workspace-print workspace)) + (with-lsp-workspace workspace (lsp--shutdown-workspace))) + +(defun lsp-disconnect () + "Disconnect the buffer from the language server." + (interactive) + (lsp--text-document-did-close t) + (lsp-managed-mode -1) + (lsp-mode -1) + (setq lsp--buffer-workspaces nil) + (lsp--info "Disconnected")) + +(defun lsp-restart-workspace () + (interactive) + (--when-let (pcase (lsp-workspaces) + (`nil (user-error "There are no active servers in the current buffer")) + (`(,workspace) workspace) + (workspaces (lsp--completing-read "Select server: " + workspaces + 'lsp--workspace-print nil t))) + (lsp-workspace-restart it))) + +(make-obsolete 'lsp-restart-workspace 'lsp-workspace-restart "lsp-mode 6.1") + +(defun lsp-workspace-restart (workspace) + "Restart the workspace WORKSPACE and the language server associated with it" + (interactive (list (lsp--read-workspace))) + (lsp--warn "Restarting %s" (lsp--workspace-print workspace)) + (with-lsp-workspace workspace (lsp--shutdown-workspace t))) + +;;;###autoload +(defun lsp (&optional arg) + "Entry point for the server startup. +When ARG is t the lsp mode will start new language server even if +there is language server which can handle current language. When +ARG is nil current file will be opened in multi folder language +server if there is such. When `lsp' is called with prefix +argument ask the user to select which language server to start." + (interactive "P") + + (lsp--require-packages) + + (when (buffer-file-name) + (let (clients + (matching-clients (lsp--filter-clients + (-andfn #'lsp--matching-clients? + #'lsp--server-binary-present?)))) + (cond + (matching-clients + (when (setq lsp--buffer-workspaces + (or (and + ;; Don't open as library file if file is part of a project. + (not (lsp-find-session-folder (lsp-session) (buffer-file-name))) + (lsp--try-open-in-library-workspace)) + (lsp--try-project-root-workspaces (equal arg '(4)) + (and arg (not (equal arg 1)))))) + (lsp-mode 1) + (when lsp-auto-configure (lsp--auto-configure)) + (setq lsp-buffer-uri (lsp--buffer-uri)) + (lsp--info "Connected to %s." + (apply 'concat (--map (format "[%s]" (lsp--workspace-print it)) + lsp--buffer-workspaces))))) + ;; look for servers which are currently being downloaded. + ((setq clients (lsp--filter-clients (-andfn #'lsp--matching-clients? + #'lsp--client-download-in-progress?))) + (lsp--info "There are language server(%s) installation in progress. +The server(s) will be started in the buffer when it has finished." + (-map #'lsp--client-server-id clients)) + (seq-do (lambda (client) + (cl-pushnew (current-buffer) (lsp--client-buffers client))) + clients)) + ;; look for servers to install + ((setq clients (lsp--filter-clients (-andfn #'lsp--matching-clients? + #'lsp--client-download-server-fn + (-not #'lsp--client-download-in-progress?)))) + (let ((client (lsp--completing-read + (concat "Unable to find installed server supporting this file. " + "The following servers could be installed automatically: ") + clients + (-compose #'symbol-name #'lsp--client-server-id) + nil + t))) + (cl-pushnew (current-buffer) (lsp--client-buffers client)) + (lsp--install-server-internal client))) + ;; no clients present + ((setq clients (unless matching-clients + (lsp--filter-clients (-andfn #'lsp--matching-clients? + (-not #'lsp--server-binary-present?))))) + (lsp--warn "The following servers support current file but do not have automatic installation configuration: %s +You may find the installation instructions at https://emacs-lsp.github.io/lsp-mode/page/languages. +\(If you have already installed the server check *lsp-log*)." + (mapconcat (lambda (client) + (symbol-name (lsp--client-server-id client))) + clients + " "))) + ;; no matches + ((-> #'lsp--matching-clients? lsp--filter-clients not) + (lsp--error "There are no language servers supporting current mode `%s' registered with `lsp-mode'. +This issue might be caused by: +1. The language you are trying to use does not have built-in support in `lsp-mode'. You must install the required support manually. Examples of this are `lsp-java' or `lsp-metals'. +2. The language server that you expect to run is not configured to run for major mode `%s'. You may check that by checking the `:major-modes' that are passed to `lsp-register-client'. +3. `lsp-mode' doesn't have any integration for the language behind `%s'. Refer to https://emacs-lsp.github.io/lsp-mode/page/languages and https://langserver.org/ . +4. You are over `tramp'. In this case follow https://emacs-lsp.github.io/lsp-mode/page/remote/. +5. You have disabled the `lsp-mode' clients for that file. (Check `lsp-enabled-clients' and `lsp-disabled-clients')." + major-mode major-mode major-mode)))))) + +(defun lsp--init-if-visible () + "Run `lsp' for the current buffer if the buffer is visible. +Returns `t' if `lsp' was run for the buffer." + (when (or (buffer-modified-p) (get-buffer-window nil t)) + (remove-hook 'window-configuration-change-hook #'lsp--init-if-visible t) + (lsp) + t)) + +;;;###autoload +(defun lsp-deferred () + "Entry point that defers server startup until buffer is visible. +`lsp-deferred' will wait until the buffer is visible before invoking `lsp'. +This avoids overloading the server with many files when starting Emacs." + ;; Workspace may not be initialized yet. Use a buffer local variable to + ;; remember that we deferred loading of this buffer. + (setq lsp--buffer-deferred t) + (let ((buffer (current-buffer))) + ;; Avoid false positives as desktop-mode restores buffers by deferring + ;; visibility check until the stack clears. + (run-with-timer 0 nil (lambda () + (when (buffer-live-p buffer) + (with-current-buffer buffer + (unless (lsp--init-if-visible) + (add-hook 'window-configuration-change-hook #'lsp--init-if-visible nil t)))))))) + + + +(defvar lsp-file-truename-cache (ht)) + +(defmacro lsp-with-cached-filetrue-name (&rest body) + "Executes BODY caching the `file-truename' calls." + `(let ((old-fn (symbol-function 'file-truename))) + (unwind-protect + (progn + (fset 'file-truename + (lambda (file-name &optional counter prev-dirs) + (or (gethash file-name lsp-file-truename-cache) + (puthash file-name (apply old-fn (list file-name counter prev-dirs)) + lsp-file-truename-cache)))) + ,@body) + (fset 'file-truename old-fn)))) + + +(defun lsp-virtual-buffer-call (key &rest args) + (when lsp--virtual-buffer + (when-let ((fn (plist-get lsp--virtual-buffer key))) + (apply fn args)))) + +(defun lsp-translate-column (column) + "Translate COLUMN taking into account virtual buffers." + (or (lsp-virtual-buffer-call :real->virtual-char column) + column)) + +(defun lsp-translate-line (line) + "Translate LINE taking into account virtual buffers." + (or (lsp-virtual-buffer-call :real->virtual-line line) + line)) + + +;; lsp internal validation. + +(defmacro lsp--doctor (&rest checks) + `(-let [buf (current-buffer)] + (with-current-buffer (get-buffer-create "*lsp-performance*") + (with-help-window (current-buffer) + ,@(-map (-lambda ((msg form)) + `(insert (format "%s: %s\n" ,msg + (let ((res (with-current-buffer buf + ,form))) + (cond + ((eq res :optional) (propertize "NOT AVAILABLE (OPTIONAL)" 'face 'warning)) + (res (propertize "OK" 'face 'success)) + (t (propertize "ERROR" 'face 'error))))))) + (-partition 2 checks)))))) + +(define-obsolete-function-alias 'lsp-diagnose + 'lsp-doctor "lsp-mode 7.1") + +(defun lsp-doctor () + "Validate performance settings." + (interactive) + (lsp--doctor + "Checking for Native JSON support" (functionp 'json-serialize) + "Check emacs supports `read-process-output-max'" (boundp 'read-process-output-max) + "Check `read-process-output-max' default has been changed from 4k" + (and (boundp 'read-process-output-max) + (> read-process-output-max 4096)) + "Byte compiled against Native JSON (recompile lsp-mode if failing when Native JSON available)" + (condition-case _err + (progn (lsp--make-message (list "a" "b")) + nil) + (error t)) + "`gc-cons-threshold' increased?" (> gc-cons-threshold 800000) + "Using gccemacs with emacs lisp native compilation (https://akrl.sdf.org/gccemacs.html)" + (or (and (fboundp 'native-comp-available-p) + (native-comp-available-p)) + :optional))) + +(declare-function package-version-join "ext:package") +(declare-function package-desc-version "ext:package") +(declare-function package--alist "ext:package") + +(defun lsp-version () + "Return string describing current version of `lsp-mode'." + (interactive) + (unless (featurep 'package) + (require 'package)) + (let ((ver (format "lsp-mode %s, Emacs %s, %s" + (package-version-join + (package-desc-version + (car (alist-get 'lsp-mode (package--alist))))) + emacs-version + system-type))) + (if (called-interactively-p 'interactive) + (lsp--info "%s" ver) + ver))) + + + +;; org-mode/virtual-buffer + +(declare-function org-babel-get-src-block-info "ext:ob-core") +(declare-function org-do-remove-indentation "ext:org-macs") +(declare-function org-src-get-lang-mode "ext:org-src") +(declare-function org-element-context "ext:org-element") + +(defun lsp--virtual-buffer-update-position () + (-if-let (virtual-buffer (-first (-lambda ((&plist :in-range)) + (funcall in-range)) + lsp--virtual-buffer-connections)) + (unless (equal virtual-buffer lsp--virtual-buffer) + (lsp-org)) + (when lsp-managed-mode + (lsp-managed-mode -1) + (lsp-mode -1) + (setq lsp--buffer-workspaces nil) + (setq lsp--virtual-buffer nil) + (setq lsp-buffer-uri nil) + + ;; force refresh of diagnostics + (run-hooks 'lsp-after-diagnostics-hook)))) + +(defun lsp-virtual-buffer-on-change (start end length) + "Adjust on change event to be executed against the proper language server." + (let ((max-point (max end + (or (plist-get lsp--before-change-vals :end) 0) + (+ start length)))) + (when-let ((virtual-buffer (-first (lambda (vb) + (let ((lsp--virtual-buffer vb)) + (and (lsp-virtual-buffer-call :in-range start) + (lsp-virtual-buffer-call :in-range max-point)))) + lsp--virtual-buffer-connections))) + (lsp-with-current-buffer virtual-buffer + (lsp-on-change start end length + (lambda (&rest _) + (list :range (lsp--range (list :character 0 :line 0) + lsp--virtual-buffer-point-max) + :text (lsp--buffer-content)))))))) + +(defun lsp-virtual-buffer-before-change (start _end) + (when-let ((virtual-buffer (-first (lambda (vb) + (lsp-with-current-buffer vb + (lsp-virtual-buffer-call :in-range start))) + lsp--virtual-buffer-connections))) + (lsp-with-current-buffer virtual-buffer + (setq lsp--virtual-buffer-point-max + (lsp--point-to-position (lsp-virtual-buffer-call :last-point)))))) + +(defun lsp-patch-on-change-event () + (remove-hook 'after-change-functions #'lsp-on-change t) + (add-hook 'after-change-functions #'lsp-virtual-buffer-on-change nil t) + (add-hook 'before-change-functions #'lsp-virtual-buffer-before-change nil t)) + +(defun lsp-kill-virtual-buffers () + (mapc #'lsp-virtual-buffer-disconnect lsp--virtual-buffer-connections)) + +(defun lsp--move-point-in-indentation (point indentation) + (save-excursion + (goto-char point) + (if (<= point (+ (point-at-bol) indentation)) + (point-at-bol) + point))) + +(declare-function flycheck-checker-supports-major-mode-p "ext:flycheck") +(declare-function flycheck-add-mode "ext:flycheck") +(declare-function lsp-diagnostics-lsp-checker-if-needed "lsp-diagnostics") + +(defalias 'lsp-client-download-server-fn 'lsp--client-download-server-fn) + +(defun lsp-flycheck-add-mode (mode) + "Register flycheck support for MODE." + (lsp-diagnostics-lsp-checker-if-needed) + (unless (flycheck-checker-supports-major-mode-p 'lsp mode) + (flycheck-add-mode 'lsp mode))) + +(defun lsp-org () + (interactive) + (-if-let ((virtual-buffer &as &plist :workspaces) (-first (-lambda ((&plist :in-range)) + (funcall in-range)) + lsp--virtual-buffer-connections)) + (unless (equal lsp--virtual-buffer virtual-buffer) + (setq lsp--buffer-workspaces workspaces) + (setq lsp--virtual-buffer virtual-buffer) + (setq lsp-buffer-uri nil) + (lsp-mode 1) + (lsp-managed-mode 1) + (lsp-patch-on-change-event)) + + (save-excursion + (-let* (virtual-buffer + (wcb (lambda (f) + (with-current-buffer (plist-get virtual-buffer :buffer) + (-let* (((&plist :major-mode :buffer-file-name + :goto-buffer :workspaces) virtual-buffer) + (lsp--virtual-buffer virtual-buffer) + (lsp--buffer-workspaces workspaces)) + (save-excursion + (funcall goto-buffer) + (funcall f)))))) + ((&plist :begin :end :post-blank :language) (cl-second (org-element-context))) + ((&alist :tangle file-name) (cl-third (org-babel-get-src-block-info 'light))) + + (file-name (if file-name + (f-expand file-name) + (user-error "You should specify file name in the src block header."))) + (begin-marker (progn + (goto-char begin) + (forward-line) + (set-marker (make-marker) (point)))) + (end-marker (progn + (goto-char end) + (forward-line (1- (- post-blank))) + (set-marker (make-marker) (1+ (point))))) + (buf (current-buffer)) + (src-block (buffer-substring-no-properties begin-marker + (1- end-marker))) + (indentation (with-temp-buffer + (insert src-block) + + (goto-char (point-min)) + (let ((indentation (current-indentation))) + (plist-put lsp--virtual-buffer :indentation indentation) + (org-do-remove-indentation) + (goto-char (point-min)) + (- indentation (current-indentation)))))) + (add-hook 'post-command-hook #'lsp--virtual-buffer-update-position nil t) + + (when (fboundp 'flycheck-add-mode) + (lsp-flycheck-add-mode 'org-mode)) + + (setq lsp--virtual-buffer + (list + :in-range (lambda (&optional point) + (<= begin-marker (or point (point)) (1- end-marker))) + :goto-buffer (lambda () (goto-char begin-marker)) + :buffer-string + (lambda () + (let ((src-block (buffer-substring-no-properties + begin-marker + (1- end-marker)))) + (with-temp-buffer + (insert src-block) + + (goto-char (point-min)) + (while (not (eobp)) + (delete-region (point) (if (> (+ (point) indentation) (point-at-eol)) + (point-at-eol) + (+ (point) indentation))) + (forward-line)) + (buffer-substring-no-properties (point-min) + (point-max))))) + :buffer buf + :begin begin-marker + :end end-marker + :indentation indentation + :last-point (lambda () (1- end-marker)) + :cur-position (lambda () + (lsp-save-restriction-and-excursion + (list :line (- (lsp--cur-line) + (lsp--cur-line begin-marker)) + :character (let ((character (- (point) + (line-beginning-position) + indentation))) + (if (< character 0) + 0 + character))))) + :line/character->point (-lambda (line character) + (-let [inhibit-field-text-motion t] + (+ indentation + (lsp-save-restriction-and-excursion + (goto-char begin-marker) + (forward-line line) + (-let [line-end (line-end-position)] + (if (> character (- line-end (point))) + line-end + (forward-char character) + (point))))))) + :major-mode (org-src-get-lang-mode language) + :buffer-file-name file-name + :buffer-uri (lsp--path-to-uri file-name) + :with-current-buffer wcb + :buffer-live? (lambda (_) (buffer-live-p buf)) + :buffer-name (lambda (_) + (propertize (format "%s(%s:%s)%s" + (buffer-name buf) + begin-marker + end-marker + language) + 'face 'italic)) + :real->virtual-line (lambda (line) + (+ line (line-number-at-pos begin-marker) -1)) + :real->virtual-char (lambda (char) (+ char indentation)) + :cleanup (lambda () + (set-marker begin-marker nil) + (set-marker end-marker nil)))) + (setf virtual-buffer lsp--virtual-buffer) + (puthash file-name virtual-buffer lsp--virtual-buffer-mappings) + (push virtual-buffer lsp--virtual-buffer-connections) + + ;; TODO: tangle only connected sections + (add-hook 'after-save-hook 'org-babel-tangle nil t) + (add-hook 'lsp-after-open-hook #'lsp-patch-on-change-event nil t) + (add-hook 'kill-buffer-hook #'lsp-kill-virtual-buffers nil t) + + (setq lsp--buffer-workspaces + (lsp-with-current-buffer virtual-buffer + (lsp) + (plist-put virtual-buffer :workspaces (lsp-workspaces)) + (lsp-workspaces))))))) + +(defun lsp-virtual-buffer-disconnect (virtual-buffer) + (interactive (list (or + lsp--virtual-buffer + (when lsp--virtual-buffer-connections + (lsp--completing-read "Select virtual buffer to disconnect: " + lsp--virtual-buffer-connections + (-lambda ((&plist :buffer-file-name)) + buffer-file-name)))))) + (-if-let ((&plist :buffer-file-name file-name :cleanup) virtual-buffer) + (progn + (lsp-with-current-buffer virtual-buffer + (lsp--text-document-did-close)) + (setq lsp--virtual-buffer-connections (-remove-item virtual-buffer lsp--virtual-buffer-connections)) + (when (eq virtual-buffer lsp--virtual-buffer) + (setf lsp--virtual-buffer nil)) + (when cleanup (funcall cleanup)) + (remhash file-name lsp--virtual-buffer-mappings) + + (lsp--virtual-buffer-update-position) + (lsp--info "Disconnected from buffer %s" file-name)) + (lsp--error "Nothing to disconnect from?"))) + + + +(provide 'lsp-mode) +;;; lsp-mode.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-modeline.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-modeline.el new file mode 100644 index 0000000..09ea7d4 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-modeline.el @@ -0,0 +1,354 @@ +;;; lsp-modeline.el --- LSP modeline features -*- lexical-binding: t; -*- +;; +;; Copyright (C) 2020 emacs-lsp maintainers +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. +;; +;;; Commentary: +;; +;; LSP modeline +;; +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-modeline nil + "LSP support for modeline" + :prefix "lsp-modeline-" + :group 'lsp-mode + :tag "LSP Modeline") + +(defcustom lsp-modeline-code-actions-kind-regex "$\\|quickfix.*\\|refactor.*" + "Regex for the code actions kinds to show in the modeline." + :type 'string + :group 'lsp-modeline) + +(defcustom lsp-modeline-code-actions-segments '(count icon) + "Define what should display on the modeline when code actions are available." + :type '(repeat (choice + (const :tag "Show the lightbulb icon" icon) + (const :tag "Show the name of the preferred code action" name) + (const :tag "Show the count of how many code actions available" count))) + :group 'lsp-modeline + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-modeline-code-action-fallback-icon "💡" + "Define what should display on the modeline when code actions are available." + :type 'string + :group 'lsp-modeline + :package-version '(lsp-mode . "7.1")) + +(defface lsp-modeline-code-actions-face + '((t :inherit homoglyph)) + "Face used to code action text on modeline." + :group 'lsp-modeline) + +(defface lsp-modeline-code-actions-preferred-face + '((t :foreground "yellow")) + "Face used to code action text on modeline." + :group 'lsp-modeline) + +;;;###autoload +(define-obsolete-variable-alias 'lsp-diagnostics-modeline-scope + 'lsp-modeline-diagnostics-scope "lsp-mode 7.0.1") + +(defcustom lsp-modeline-diagnostics-scope :workspace + "The modeline diagnostics scope." + :group 'lsp-modeline + :type '(choice (const :tag "File" :file) + (const :tag "Project" :workspace) + (const :tag "All Projects" :global)) + :package-version '(lsp-mode . "6.3")) + +(declare-function all-the-icons-octicon "ext:all-the-icons" t t) +(declare-function lsp-treemacs-errors-list "ext:lsp-treemacs" t) + + +;; code actions + +(defvar-local lsp-modeline--code-actions-string nil + "Holds the current code action string on modeline.") + +(defun lsp-modeline--code-action-face (preferred-code-action) + "Return the face checking if there is any PREFERRED-CODE-ACTION." + (if preferred-code-action + 'lsp-modeline-code-actions-preferred-face + 'lsp-modeline-code-actions-face)) + +(defun lsp-modeline--code-actions-icon (face) + "Build the icon for modeline code actions using FACE." + (if (require 'all-the-icons nil t) + (all-the-icons-octicon "light-bulb" + :face face + :v-adjust -0.0575) + (propertize lsp-modeline-code-action-fallback-icon 'face face))) + +(defun lsp-modeline--code-action-name (actions preferred-code-action-title) + "Return the code action name from ACTIONS and PREFERRED-CODE-ACTION-TITLE." + (or preferred-code-action-title + (->> actions + lsp-seq-first + lsp-modeline--code-action->string))) + +(defun lsp-modeline--code-action->string (action) + "Convert code ACTION to friendly string." + (->> action + lsp:code-action-title + (replace-regexp-in-string "[\n\t ]+" " "))) + +(defun lsp-modeline--build-code-actions-segments (actions) + "Build the code ACTIONS string from the defined segments." + (let* ((preferred-code-action (-some->> actions + (-first #'lsp:code-action-is-preferred?) + lsp-modeline--code-action->string)) + (face (lsp-modeline--code-action-face preferred-code-action))) + (mapconcat + (lambda (segment) + (pcase segment + ('icon (lsp-modeline--code-actions-icon face)) + ('name (propertize (lsp-modeline--code-action-name actions preferred-code-action) + 'face face)) + ('count (propertize (number-to-string (seq-length actions)) + 'face face)))) + lsp-modeline-code-actions-segments " "))) + +(defun lsp-modeline--build-code-actions-string (actions) + "Build the string to be presented on modeline for code ACTIONS." + (-let* ((single-action? (= (length actions) 1)) + (keybinding (concat "(" + (-some->> #'lsp-execute-code-action + where-is-internal + (-find (lambda (o) + (not (member (aref o 0) '(menu-bar normal-state))))) + key-description) + ")")) + (built-string (lsp-modeline--build-code-actions-segments actions)) + (preferred-code-action (-some->> actions + (-first #'lsp:code-action-is-preferred?) + lsp-modeline--code-action->string))) + (add-text-properties 0 (length built-string) + (list 'help-echo + (concat (format "Apply code actions %s\nmouse-1: " keybinding) + (if single-action? + (lsp-modeline--code-action-name actions preferred-code-action) + "select from multiple code actions")) + 'mouse-face 'mode-line-highlight + 'local-map (make-mode-line-mouse-map + 'mouse-1 (lambda () + (interactive) + (if single-action? + (lsp-execute-code-action (lsp-seq-first actions)) + (lsp-execute-code-action (lsp--select-action actions)))))) + built-string) + (unless (string= "" built-string) + (concat built-string " ")))) + +(defun lsp--modeline-update-code-actions (actions) + "Update modeline with new code ACTIONS." + (when lsp-modeline-code-actions-kind-regex + (setq actions (seq-filter (-lambda ((&CodeAction :kind?)) + (or (not kind?) + (s-match lsp-modeline-code-actions-kind-regex kind?))) + actions))) + (setq lsp-modeline--code-actions-string + (if (seq-empty-p actions) "" + (lsp-modeline--build-code-actions-string actions))) + (force-mode-line-update)) + +(defun lsp-modeline--check-code-actions (&rest _) + "Request code actions to update modeline for given BUFFER." + (when (lsp-feature? "textDocument/codeAction") + (lsp-request-async + "textDocument/codeAction" + (lsp--text-document-code-action-params) + #'lsp--modeline-update-code-actions + :mode 'unchanged + :cancel-token :lsp-modeline-code-actions))) + +(defun lsp-modeline--enable-code-actions () + "Enable code actions on modeline mode." + (when (and lsp-modeline-code-actions-enable + (lsp-feature? "textDocument/codeAction")) + (lsp-modeline-code-actions-mode 1))) + +(defun lsp-modeline--disable-code-actions () + "Disable code actions on modeline mode." + (lsp-modeline-code-actions-mode -1)) + +;;;###autoload +(define-minor-mode lsp-modeline-code-actions-mode + "Toggle code actions on modeline." + :group 'lsp-modeline + :global nil + :lighter "" + (cond + (lsp-modeline-code-actions-mode + (add-to-list 'global-mode-string '(t (:eval lsp-modeline--code-actions-string))) + + (add-hook 'lsp-on-idle-hook 'lsp-modeline--check-code-actions nil t) + (add-hook 'lsp-configure-hook #'lsp-modeline--enable-code-actions nil t) + (add-hook 'lsp-unconfigure-hook #'lsp-modeline--disable-code-actions nil t)) + (t + (remove-hook 'lsp-on-idle-hook 'lsp-modeline--check-code-actions t) + (remove-hook 'lsp-configure-hook #'lsp-modeline--enable-code-actions t) + (remove-hook 'lsp-unconfigure-hook #'lsp-modeline--disable-code-actions t) + (setq global-mode-string (remove '(t (:eval lsp-modeline--code-actions-string)) global-mode-string))))) + + +;; diagnostics + +(defvar-local lsp-modeline--diagnostics-string nil + "Value of current buffer diagnostics statistics.") + +(defvar lsp-modeline--diagnostics-wks->strings nil + "Plist of workspaces to their modeline strings. +The `:global' workspace is global one.") + +(defun lsp-modeline-diagnostics-statistics () + "Calculate diagnostics statistics based on `lsp-modeline-diagnostics-scope'." + (let ((diagnostics (cond + ((equal :file lsp-modeline-diagnostics-scope) + (list (lsp--get-buffer-diagnostics))) + (t (->> (eq :workspace lsp-modeline-diagnostics-scope) + (lsp-diagnostics) + (ht-values))))) + (stats (make-vector lsp/diagnostic-severity-max 0)) + strs + (i 0)) + (mapc (lambda (buf-diags) + (mapc (lambda (diag) + (-let [(&Diagnostic? :severity?) diag] + (when severity? + (cl-incf (aref stats severity?))))) + buf-diags)) + diagnostics) + (while (< i lsp/diagnostic-severity-max) + (when (> (aref stats i) 0) + (setq strs + (nconc strs + `(,(propertize + (format "%s" (aref stats i)) + 'face + (cond + ((= i lsp/diagnostic-severity-error) 'error) + ((= i lsp/diagnostic-severity-warning) 'warning) + ((= i lsp/diagnostic-severity-information) 'success) + ((= i lsp/diagnostic-severity-hint) 'success))))))) + (cl-incf i)) + (-> (s-join "/" strs) + (propertize 'mouse-face 'mode-line-highlight + 'help-echo "mouse-1: Show diagnostics" + 'local-map (when (require 'lsp-treemacs nil t) + (make-mode-line-mouse-map + 'mouse-1 #'lsp-treemacs-errors-list)))))) + +(defun lsp-modeline--diagnostics-reset-modeline-cache () + "Reset the modeline diagnostics cache." + (plist-put lsp-modeline--diagnostics-wks->strings (car (lsp-workspaces)) nil) + (plist-put lsp-modeline--diagnostics-wks->strings :global nil) + (setq lsp-modeline--diagnostics-string nil)) + +(defun lsp-modeline--diagnostics-update-modeline () + "Update diagnostics modeline string." + (cl-labels ((calc-modeline () + (let ((str (lsp-modeline-diagnostics-statistics))) + (if (string-empty-p str) "" + (concat str " "))))) + (setq lsp-modeline--diagnostics-string + (cl-case lsp-modeline-diagnostics-scope + (:file (or lsp-modeline--diagnostics-string + (calc-modeline))) + (:workspace + (let ((wk (car (lsp-workspaces)))) + (or (plist-get lsp-modeline--diagnostics-wks->strings wk) + (let ((ml (calc-modeline))) + (setq lsp-modeline--diagnostics-wks->strings + (plist-put lsp-modeline--diagnostics-wks->strings wk ml)) + ml)))) + (:global + (or (plist-get lsp-modeline--diagnostics-wks->strings :global) + (let ((ml (calc-modeline))) + (setq lsp-modeline--diagnostics-wks->strings + (plist-put lsp-modeline--diagnostics-wks->strings :global ml)) + ml))))))) + +(defun lsp-modeline--enable-diagnostics () + "Enable diagnostics on modeline mode." + (when (and lsp-modeline-diagnostics-enable + (lsp-feature? "textDocument/publishDiagnostics")) + (lsp-modeline-diagnostics-mode 1))) + +(defun lsp-modeline--disable-diagnostics () + "Disable diagnostics on modeline mode." + (lsp-modeline-diagnostics-mode -1)) + +;;;###autoload +(define-obsolete-function-alias 'lsp-diagnostics-modeline-mode + 'lsp-modeline-diagnostics-mode "lsp-mode 7.0.1") + +;;;###autoload +(define-minor-mode lsp-modeline-diagnostics-mode + "Toggle diagnostics modeline." + :group 'lsp-modeline + :global nil + :lighter "" + (cond + (lsp-modeline-diagnostics-mode + (add-hook 'lsp-configure-hook #'lsp-modeline--enable-diagnostics nil t) + (add-hook 'lsp-unconfigure-hook #'lsp-modeline--disable-diagnostics nil t) + (add-to-list 'global-mode-string '(t (:eval (lsp-modeline--diagnostics-update-modeline)))) + (add-hook 'lsp-diagnostics-updated-hook 'lsp-modeline--diagnostics-reset-modeline-cache)) + (t + (remove-hook 'lsp-configure-hook #'lsp-modeline--enable-diagnostics t) + (remove-hook 'lsp-unconfigure-hook #'lsp-modeline--disable-diagnostics t) + (remove-hook 'lsp-diagnostics-updated-hook 'lsp-modeline--diagnostics-reset-modeline-cache) + (setq global-mode-string (remove '(t (:eval (lsp-modeline--diagnostics-update-modeline))) global-mode-string))))) + + +;; workspace status + +(defun lsp-modeline--workspace-status-string () + "Build the workspace status string." + '(t (:eval (-keep #'lsp--workspace-status-string (lsp-workspaces))))) + +(defun lsp-modeline--enable-workspace-status () + "Enable workspace status on modeline." + (let ((status (lsp-modeline--workspace-status-string))) + (setq-local global-mode-string (if (-contains? global-mode-string status) + global-mode-string + (cons status global-mode-string))))) + +(defun lsp-modeline--disable-workspace-status () + "Disable workspace status on modeline." + (let ((status (lsp-modeline--workspace-status-string))) + (setq-local global-mode-string (remove status global-mode-string)))) + +;;;###autoload +(define-minor-mode lsp-modeline-workspace-status-mode + "Toggle workspace status on modeline." + :group 'lsp-modeline + :global nil + :lighter "" + (cond + (lsp-modeline-workspace-status-mode + (add-hook 'lsp-configure-hook #'lsp-modeline--enable-workspace-status nil t) + (add-hook 'lsp-unconfigure-hook #'lsp-modeline--disable-workspace-status nil t)) + (t + (remove-hook 'lsp-configure-hook #'lsp-modeline--enable-workspace-status t) + (remove-hook 'lsp-unconfigure-hook #'lsp-modeline--disable-workspace-status t)))) + +(lsp-consistency-check lsp-modeline) + +(provide 'lsp-modeline) +;;; lsp-modeline.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-nim.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-nim.el new file mode 100644 index 0000000..5418137 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-nim.el @@ -0,0 +1,45 @@ +;;; lsp-nim.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, nim + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the Nim Programming Language. + +;;; Code: + +(require 'lsp-mode) + +;; Nim +(defgroup lsp-nimlsp nil + "LSP support for Nim, using nimlsp." + :group 'lsp-mode + :link '(url-link "https://github.com/PMunch/nimlsp")) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection "nimlsp") + :major-modes '(nim-mode) + :priority -1 + :server-id 'nimls)) + + +(lsp-consistency-check lsp-nim) + +(provide 'lsp-nim) +;;; lsp-nim.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-nix.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-nix.el new file mode 100644 index 0000000..2e1c0b5 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-nix.el @@ -0,0 +1,48 @@ +;;; lsp-nix.el --- lsp-mode nix integration -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 lsp-mode maintainers + +;; Author: Seong Yong-ju <sei40kr@gmail.com> +;; Keywords: languages + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Client for the rnix language server. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-nix nil + "LSP support for Nix, using rnix-lsp." + :group 'lsp-mode + :link '(url-link "https://github.com/nix-community/rnix-lsp")) + +(defcustom lsp-nix-server-path "rnix-lsp" + "Executable path for the server." + :group 'lsp-nix + :type 'string + :package-version '(lsp-mode . "7.1")) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection (lambda () lsp-nix-server-path)) + :major-modes '(nix-mode) + :server-id 'rnix-lsp)) + +(lsp-consistency-check lsp-nix) + +(provide 'lsp-nix) +;;; lsp-nix.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-ocaml.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-ocaml.el new file mode 100644 index 0000000..b1e1003 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-ocaml.el @@ -0,0 +1,84 @@ +;;; lsp-ocaml.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, ocaml + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the Ocaml Programming Language. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-ocaml nil + "LSP support for OCaml, using ocaml-language-server." + :group 'lsp-mode + :link '(url-link "https://github.com/freebroccolo/ocaml-language-server")) + +(define-obsolete-variable-alias + 'lsp-ocaml-ocaml-lang-server-command + 'lsp-ocaml-lang-server-command + "lsp-mode 6.1") + +(defcustom lsp-ocaml-lang-server-command + '("ocaml-language-server" "--stdio") + "Command to start ocaml-language-server." + :group 'lsp-ocaml + :type '(choice + (string :tag "Single string value") + (repeat :tag "List of string values" + string))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (lambda () lsp-ocaml-lang-server-command)) + :major-modes '(reason-mode caml-mode tuareg-mode) + :priority -1 + :server-id 'ocaml-ls)) + +(defgroup lsp-ocaml-lsp-server nil + "LSP support for OCaml, using ocaml-lsp-server." + :group 'lsp-mode + :link '(url-link "https://github.com/ocaml/ocaml-lsp")) + +(define-obsolete-variable-alias 'lsp-merlin 'lsp-ocaml-lsp-server "lsp-mode 6.1") +(define-obsolete-variable-alias 'lsp-merlin-command 'lsp-ocaml-lsp-server-command "lsp-mode 6.1") + +(defcustom lsp-ocaml-lsp-server-command + '("ocamllsp") + "Command to start ocaml-language-server." + :group 'lsp-ocaml + :type '(choice + (string :tag "Single string value") + (repeat :tag "List of string values" + string))) + +(lsp-register-client + (make-lsp-client + :new-connection + (lsp-stdio-connection (lambda () lsp-ocaml-lsp-server-command)) + :major-modes '(reason-mode caml-mode tuareg-mode) + :priority 0 + :server-id 'ocaml-lsp-server)) + + +(lsp-consistency-check lsp-ocaml) + +(provide 'lsp-ocaml) +;;; lsp-ocaml.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-perl.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-perl.el new file mode 100644 index 0000000..07ef6d0 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-perl.el @@ -0,0 +1,117 @@ +;;; lsp-perl.el --- lsp-perl config -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 lsp-mode developers + +;; Author: Hiroki Noda <kubo39@gmail.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; lsp-perl client + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-perl nil + "LSP support for Perl" + :group 'lsp-mode + :link '(url-link "https://github.com/richterger/Perl-LanguageServer") + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-perl-language-server-path "perl" + "Path to perl interpreter." + :type 'string + :group 'lsp-perl + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-perl-language-server-port 13603 + "Choose listen port." + :type 'integer + :group 'lsp-perl + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-perl-language-server-client-version "2.1.0" + "Choose client version." + :type 'string + :group 'lsp-perl + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-perl-perl-cmd nil + "Path to perl interpreter used in Perl Language Server. +Defaults to `perl' if nil." + :type 'string + :group 'lsp-perl + :package-version '(lsp-mode . "7.0.1")) +(defcustom lsp-perl-perl-inc nil + "A vector of paths to add to perl library path." + :type 'lsp-string-vector + :group 'lsp-perl + :package-version '(lsp-mode . "7.0.1")) +(defcustom lsp-perl-file-filter nil + "A vector of directories filtering perl file. +Defaults to `[\".pm\" \".pl\"]' if nil." + :type 'lsp-string-vector + :group 'lsp-perl + :package-version '(lsp-mode . "7.0.1")) +(defcustom lsp-perl-ignore-dirs nil + "A vector of directories to ignore. +Defaults to `[\".vscode\" \".git\" \".svn\"]' if nil." + :type 'lsp-string-vector + :group 'lsp-perl + :package-version '(lsp-mode . "7.0.1")) + +(defcustom lsp-perl-show-local-vars nil + "If true, show also local variables in symbol view. +Defaults to false if nil" + :type 'boolean + :group 'lsp-perl + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-perl-log-level nil + "Log level 0-2. +Defaults to 0." + :type 'integer + :group 'lsp-perl + :package-version '(lsp-mode . "7.1")) + +(lsp-register-custom-settings + '(("perl.perlCmd" lsp-perl-perl-cmd) + ("perl.perlInc" lsp-perl-perl-inc) + ("perl.fileFilter" lsp-perl-file-filter) + ("perl.ignoreDirs" lsp-perl-ignore-dirs) + ("perl.showLocalVars" lsp-perl-show-local-vars t) + ("perl.logLevel" lsp-perl-log-level))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (lambda () + (list lsp-perl-language-server-path + "-MPerl::LanguageServer" "-e" "Perl::LanguageServer::run" "--" + (format "--port %d --version %s" + lsp-perl-language-server-port lsp-perl-language-server-client-version)))) + :major-modes '(perl-mode cperl-mode) + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration + (lsp-configuration-section "perl")))) + :priority -1 + :server-id 'perl-language-server)) + +(lsp-consistency-check lsp-perl) + +(provide 'lsp-perl) +;;; lsp-perl.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-php.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-php.el new file mode 100644 index 0000000..975a527 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-php.el @@ -0,0 +1,433 @@ +;;; lsp-php.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, php + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the PHP Programming Language. + +;;; Code: + +(require 'lsp-mode) +(require 'lsp-protocol) + +;; PHP Language Server +(defgroup lsp-php nil + "LSP support for PHP, using php-language-server." + :link '(url-link "https://github.com/felixfbecker/php-language-server") + :group 'lsp-mode) + +(defun lsp-php-get-composer-dir () + "Get composer home directory if possible." + (if (executable-find "composer") + (replace-regexp-in-string "\n$" "" (shell-command-to-string "composer config --global home")) + "~/.composer")) + +(defcustom lsp-php-composer-dir nil + "Home directory of composer." + :group 'lsp-php + :type 'string) + +(defcustom lsp-clients-php-server-command nil + "Install directory for php-language-server." + :group 'lsp-php + :type '(repeat string)) + +(defun lsp-php--create-connection () + "Create lsp connection." + (lsp-stdio-connection + (lambda () + (unless lsp-php-composer-dir + (setq lsp-php-composer-dir (lsp-php-get-composer-dir))) + (unless lsp-clients-php-server-command + (setq lsp-clients-php-server-command + `("php", + (expand-file-name + (f-join lsp-php-composer-dir "vendor/felixfbecker/language-server/bin/php-language-server.php"))))) + lsp-clients-php-server-command) + (lambda () + (if (and (cdr lsp-clients-php-server-command) + (eq (string-match-p "php[0-9.]*\\'" (car lsp-clients-php-server-command)) 0)) + ;; Start with the php command and the list has more elems. Test the existence of the PHP script. + (let ((php-file (nth 1 lsp-clients-php-server-command))) + (or (file-exists-p php-file) + (progn + (lsp-log "%s is not present." php-file) + nil))) + t)))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-php--create-connection) + :activation-fn (lsp-activate-on "php") + :priority -3 + :server-id 'php-ls)) + +;;; Intelephense +(defgroup lsp-intelephense nil + "LSP support for PHP, using Intelephense." + :group 'lsp-mode + :link '(url-link "https://github.com/bmewburn/vscode-intelephense") + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-intelephense-files-max-size 1000000 + "Maximum file size in bytes." + :type 'number + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-intelephense-files-associations + ["*.php" "*.phtml"] + "Configure glob patterns to make files available for language +server features." + :type '(repeat string) + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-intelephense-files-exclude + ["**/.git/**" "**/.svn/**" "**/.hg/**" "**/CVS/**" "**/.DS_Store/**" + "**/node_modules/**" "**/bower_components/**" "**/vendor/**/{Test,test,Tests,tests}/**"] + "Configure glob patterns to exclude certain files and folders +from all language server features." + :type '(repeat string) + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-intelephense-stubs + ["apache" "bcmath" "bz2" "calendar" + "com_dotnet" "Core" "ctype" "curl" "date" "dba" "dom" "enchant" + "exif" "fileinfo" "filter" "fpm" "ftp" "gd" "hash" "iconv" "imap" "interbase" + "intl" "json" "ldap" "libxml" "mbstring" "mcrypt" "meta" "mssql" "mysqli" + "oci8" "odbc" "openssl" "pcntl" "pcre" "PDO" "pdo_ibm" "pdo_mysql" + "pdo_pgsql" "pdo_sqlite" "pgsql" "Phar" "posix" "pspell" "readline" "recode" + "Reflection" "regex" "session" "shmop" "SimpleXML" "snmp" "soap" "sockets" + "sodium" "SPL" "sqlite3" "standard" "superglobals" "sybase" "sysvmsg" + "sysvsem" "sysvshm" "tidy" "tokenizer" "wddx" "xml" "xmlreader" "xmlrpc" + "xmlwriter" "Zend OPcache" "zip" "zlib"] + "Configure stub files for built in symbols and common +extensions. The default setting includes PHP core and all +bundled extensions." + :type '(repeat string) + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-intelephense-completion-insert-use-declaration t + "Use declarations will be automatically inserted for namespaced +classes, traits, interfaces, functions, and constants." + :type 'boolean + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-intelephense-completion-fully-qualify-global-constants-and-functions nil + "Global namespace constants and functions will be fully +qualified (prefixed with a backslash)." + :type 'boolean + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-intelephense-completion-trigger-parameter-hints t + "Method and function completions will include parentheses and +trigger parameter hints." + :type 'boolean + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-intelephense-completion-max-items 100 + "The maximum number of completion items returned per request." + :type 'number + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-intelephense-format-enable t + "Enables formatting." + :type 'boolean + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-intelephense-licence-key nil + "Enter your intelephense licence key here to access premium +features." + :type 'string + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-intelephense-telemetry-enabled nil + "Anonymous usage and crash data will be sent to Azure +Application Insights." + :type 'boolean + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-intelephense-rename-exclude + ["**/vendor/**"] + "Glob patterns to exclude files and folders from having symbols +renamed. Rename operation will fail if references and/or +definitions are found in excluded files/folders." + :type '(repeat string) + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-intelephense-trace-server "off" + "Traces the communication between VSCode and the intelephense +language server." + :type '(choice (:tag "off" "messages" "verbose")) + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-intelephense-storage-path + (expand-file-name (locate-user-emacs-file "lsp-cache")) + "Optional absolute path to storage dir." + :type 'directory + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-intelephense-clear-cache nil + "Optional flag to clear server state." + :type 'boolean + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-intelephense-multi-root t + "Flag to control if the server supports multi-root projects." + :type 'boolean + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.3")) + +(lsp-register-custom-settings + '(("intelephense.trace.server" lsp-intelephense-trace-server) + ("intelephense.rename.exclude" lsp-intelephense-rename-exclude) + ("intelephense.telemetry.enabled" lsp-intelephense-telemetry-enabled t) + ("intelephense.format.enable" lsp-intelephense-format-enable t) + ("intelephense.completion.maxItems" lsp-intelephense-completion-max-items) + ("intelephense.completion.triggerParameterHints" lsp-intelephense-completion-trigger-parameter-hints t) + ("intelephense.completion.fullyQualifyGlobalConstantsAndFunctions" lsp-intelephense-completion-fully-qualify-global-constants-and-functions t) + ("intelephense.completion.insertUseDeclaration" lsp-intelephense-completion-insert-use-declaration t) + ("intelephense.stubs" lsp-intelephense-stubs) + ("intelephense.files.exclude" lsp-intelephense-files-exclude) + ("intelephense.files.associations" lsp-intelephense-files-associations) + ("intelephense.files.maxSize" lsp-intelephense-files-max-size))) + +(define-obsolete-variable-alias + 'lsp-clients-php-iph-server-command + 'lsp-intelephense-server-command + "lsp-mode 6.1") + +(defcustom lsp-intelephense-server-command + `("intelephense" "--stdio") + "Command to start Intelephense." + :type '(repeat string) + :group 'lsp-intelephense + :package-version '(lsp-mode . "6.1")) + +(lsp-dependency 'intelephense + '(:system "intelephense") + '(:npm :package "intelephense" + :path "intelephense")) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (lambda () + `(,(or (executable-find + (cl-first lsp-intelephense-server-command)) + (lsp-package-path 'intelephense)) + ,@(cl-rest lsp-intelephense-server-command)))) + :activation-fn (lsp-activate-on "php") + :priority -1 + :notification-handlers (ht ("indexingStarted" #'ignore) + ("indexingEnded" #'ignore)) + :initialization-options (lambda () + (list :storagePath lsp-intelephense-storage-path + :licenceKey lsp-intelephense-licence-key + :clearCache lsp-intelephense-clear-cache)) + :multi-root lsp-intelephense-multi-root + :completion-in-comments? t + :server-id 'iph + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'intelephense + callback error-callback)))) + + +;;; Serenata +(defgroup lsp-serenata nil + "LSP support for the PHP programming language, using serenata." + :group 'lsp-mode + :link '(url-link "https://gitlab.com/Serenata/Serenata") + :package-version '(lsp-mode . "7.0")) + +(defcustom lsp-serenata-server-path + "serenata.phar" + "Path to the Serenata Language Server phar file. +It can be downloaded from https://gitlab.com/Serenata/Serenata/-/releases." + :group 'lsp-serenata + :type 'file) + +(defcustom lsp-serenata-uris + [] + "A list of folders to index for your project. +This does not have to include the root of the project itself, in +case you have need of an exotic configuration where the root of +the project is at some location but your actual PHP code is +somewhere else. Note that if you are running Serenata in a +container, you will have to ensure that these URI's are mapped +inside it. Avoid using file paths containing spaces. This is +currently broken due to apparent PHP quirks. By default, the +value is taken from the lsp workspace location." + :group 'lsp-serenata + :type 'lsp-string-vector) + +(defcustom lsp-serenata-php-version + 7.3 + "Allows you to specify the PHP version your project is written in. +At the moment this directive is still ignored, but it will +influence functionality such as refactoring in the future, where +older PHP versions may not support scalar type hints, which may +then be omitted from places such as getters and setters." + :group 'lsp-serenata + :type 'number) + +(defcustom lsp-serenata-file-extensions + ["php"] + "List of file extensions (without dot) to process. +Files that do not match this whitelist will be ignored during +indexing. Usually you'll want to set this to at least include +php, as it is the most common PHP extension. phpt is not +included by default as it is often used to contain test code that +is not directly part of the code. Note that for existing +projects, removing extensions will not not automatically prune +files having them from the index if they are already present. +Adding new ones will cause the files having them to be picked up +on the next project initialization." + :group 'lsp-serenata + :type 'lsp-string-vector) + +(defcustom lsp-serenata-index-database-uri (lsp--path-to-uri (f-join user-emacs-directory "index.sqlite")) + "The location to store the index database. +Note that, as the index database uses SQLite and WAL mode, +additional files (usually two) may be generated and used in the +same folder. Note also that Serenata relies on the Doctrine DBAL +library as well as the SQLite backends in PHP, which may not +support non-file URI's, which may prevent you from using these." + :group 'lsp-serenata + :type 'file) + +(defcustom lsp-serenata-exclude-path-expressions ["/.+Test.php$/"] + "One or more expressions of paths to ignore. +This uses Symfony's Finder in the background, so this means you +can configure anything here that can also be passed to the name +function, which includes plain strings, globs, as well as regular +expressions. Note that for existing projects, modifying these +will not not automatically prune them from the index if they are +already present." + :group 'lsp-serenata + :type 'lsp-string-vector) + +(defun lsp-serenata-server-start-fun (port) + "Define serenata start function, it requires a PORT." + `(,lsp-serenata-server-path + "-u" ,(number-to-string port))) + +(defun lsp-serenata-init-options () + "Init options for lsp-serenata." + `( :configuration ( :uris ,lsp-serenata-uris + :indexDatabaseUri ,lsp-serenata-index-database-uri + :phpVersion ,lsp-serenata-php-version + :excludedPathExpressions ,lsp-serenata-exclude-path-expressions + :fileExtensions ,lsp-serenata-file-extensions))) + + +(lsp-interface (serenata:didProgressIndexing (:sequenceOfIndexedItem :totalItemsToIndex :progressPercentage :folderUri :fileUri :info) nil )) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-tcp-connection 'lsp-serenata-server-start-fun) + :activation-fn (lsp-activate-on "php") + :priority -2 + :notification-handlers (ht ("serenata/didProgressIndexing" + (lambda (_server data) + (lsp-log "%s" (lsp:serenata-did-progress-indexing-info data))))) + + :initialization-options #'lsp-serenata-init-options + :initialized-fn (lambda (workspace) + (when (equal (length lsp-serenata-uris) 0) + (let* ((lsp-root (lsp--path-to-uri (lsp-workspace-root)))) + (setq lsp-serenata-uris (vector lsp-root)))) + (with-lsp-workspace workspace + (lsp--set-configuration + (lsp-configuration-section "serenata")))) + :server-id 'serenata)) + +;;; phpactor + +(defgroup lsp-phpactor nil + "LSP support for Phpactor." + :link '(url-link "https://github.com/phpactor/phpactor") + :group 'lsp-mode) + +(defcustom lsp-phpactor-path nil + "Path to the `phpactor' command." + :group 'lsp-phpactor + :type "string") + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection + (lambda () + (unless lsp-php-composer-dir + (setq lsp-php-composer-dir (lsp-php-get-composer-dir))) + (unless lsp-phpactor-path + (setq lsp-phpactor-path (f-join lsp-php-composer-dir "vendor/phpactor/phpactor/bin/phpactor"))) + (list lsp-phpactor-path "language-server"))) + :activation-fn (lsp-activate-on "php") + ;; `phpactor' is not really that feature-complete: it doesn't support + ;; `textDocument/showOccurence' and sometimes errors (e.g. find references on + ;; a global free-standing function). + :priority -4 + ;; Even though `phpactor' itself supports no options, this needs to be + ;; serialized as an empty object (otherwise the LS won't even start, due to a + ;; type error). + :initialization-options (ht) + :server-id 'phpactor)) + +(defcustom lsp-phpactor-extension-alist '(("Phpstan" . "phpactor/language-server-phpstan-extension") + ("Behat" . "phpactor/behat-extension") + ("PHPUnit" . "phpactor/phpunit-extension")) + "Alist mapping extension names to `composer' packages. +These extensions can be installed using +`lsp-phpactor-install-extension'." + :type '(alist :key-type "string" :value-type "string") + :group 'lsp-phpactor) + +(defun lsp-phpactor-install-extension (extension) + "Install a `phpactor' EXTENSION. +See `lsp-phpactor-extension-alist' and +https://phpactor.readthedocs.io/en/develop/extensions.html." + (interactive (list (completing-read "Select extension: " + lsp-phpactor-extension-alist))) + (compilation-start + (format "%s extension:install %s" + (shell-quote-argument (expand-file-name lsp-phpactor-path)) + (shell-quote-argument + (cdr (assoc extension lsp-phpactor-extension-alist)))) + nil + (lambda (_mode) + (format "*Phpactor install %s*" extension)))) + +(lsp-consistency-check lsp-php) + +(provide 'lsp-php) +;;; lsp-php.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-prolog.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-prolog.el new file mode 100644 index 0000000..084f0ee --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-prolog.el @@ -0,0 +1,55 @@ +;;; lsp-prolog.el --- Prolog Client settings -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 James Cash + +;; Author: James Cash <james.nvc@gmail.com> +;; Keywords: languages,tools + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; lsp-prolog client + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-prolog nil + "LSP support for Prolog." + :link '(url-link "https://github.com/jamesnvc/lsp_server") + :group 'lsp-mode + :tag "Lsp Prolog") + +(defcustom lsp-prolog-server-command '("swipl" + "-g" "use_module(library(lsp_server))." + "-g" "lsp_server:main" + "-t" "halt" + "--" "stdio") + "The prolog-lsp server command." + :group 'lsp-prolog + :risky t + :type 'list) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection (lambda () lsp-prolog-server-command)) + :major-modes '(prolog-mode) + :multi-root t + :server-id 'prolog-lsp)) + +(lsp-consistency-check lsp-prolog) + +(provide 'lsp-prolog) +;;; lsp-prolog.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-protocol.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-protocol.el new file mode 100644 index 0000000..50bcf3d --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-protocol.el @@ -0,0 +1,752 @@ +;;; lsp-protocol.el --- Language Sever Protocol Bindings -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Ivan Yonchovski + +;; Author: Ivan Yonchovski <yyoncho@gmail.com> +;; Keywords: convenience + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Autogenerated bindings from lsp4j using +;; https://github.com/victools/jsonschema-generator+scrips to generate +;; scripts/generated.protocol.schema.json and then +;; scripts/lsp-generate-bindings.el + +;;; Code: + +(require 'cl-lib) +(require 'dash) +(require 'ht) +(require 's) + +(eval-and-compile + (defun lsp-keyword->symbol (keyword) + "Convert a KEYWORD to symbol." + (intern (substring (symbol-name keyword) 1))) + + (defun lsp-keyword->string (keyword) + "Convert a KEYWORD to string." + (substring (symbol-name keyword) 1)) + + (defvar lsp-use-plists nil)) + +(defmacro lsp-interface (&rest interfaces) + "Generate LSP bindings from INTERFACES triplet. + +Example usage with `dash`. + +\(-let [(&ApplyWorkspaceEditResponse + :failure-reason?) (ht (\"failureReason\" \"...\"))] + failure-reason?) + +\(fn (INTERFACE-NAME-1 REQUIRED-FIELDS-1 OPTIONAL-FIELDS-1) (INTERFACE-NAME-2 REQUIRED-FIELDS-2 OPTIONAL-FIELDS-2) ...)" + (with-case-table ascii-case-table + (->> interfaces + (-map (-lambda ((interface required optional)) + (let ((params (nconc + (-map (lambda (param-name) + (cons + (intern (concat ":" (s-dashed-words (symbol-name param-name)) "?")) + param-name)) + optional) + (-map (lambda (param-name) + (cons (intern (concat ":" (s-dashed-words (symbol-name param-name)))) + param-name)) + required)))) + (cl-list* + `(defun ,(intern (format "dash-expand:&%s" interface)) (key source) + (unless (or (member key ',(-map #'cl-first params)) + (s-starts-with? ":_" (symbol-name key))) + (error "Unknown key: %s. Available keys: %s" key ',(-map #'cl-first params))) + ,(if lsp-use-plists + ``(plist-get ,source + ,(if (s-starts-with? ":_" (symbol-name key)) + key + (cl-rest (assoc key ',params)))) + ``(gethash ,(if (s-starts-with? ":_" (symbol-name key)) + (substring (symbol-name key) 1) + (substring (symbol-name + (cl-rest (assoc key ',params))) + 1)) + ,source))) + `(defun ,(intern (format "dash-expand:&%s?" interface)) (key source) + (unless (member key ',(-map #'cl-first params)) + (error "Unknown key: %s. Available keys: %s" key ',(-map #'cl-first params))) + ,(if lsp-use-plists + ``(plist-get ,source + ,(if (s-starts-with? ":_" (symbol-name key)) + key + (cl-rest (assoc key ',params)))) + ``(when (ht? ,source) + (gethash ,(substring (symbol-name + (cl-rest (assoc key ',params))) + 1) + ,source)))) + + `(defun ,(intern (format "lsp-%s?" (s-dashed-words (symbol-name interface)))) (object) + (cond + ((ht? object) + (-all? (let ((keys (ht-keys object))) + (lambda (prop) + (member prop keys))) + ',(-map (lambda (field-name) + (substring (symbol-name field-name) 1)) + required))) + ((listp object) (-all? (lambda (prop) + (plist-member object prop)) + ',required)))) + `(cl-defun ,(intern (format "lsp-make-%s" (s-dashed-words (symbol-name interface)))) + (&rest plist &key ,@(-map (-lambda ((key)) + (intern (substring (symbol-name key) 1))) params) + &allow-other-keys) + (ignore ,@(-map (-lambda ((key)) + (intern (substring (symbol-name key) 1))) params)) + ,(format "Constructs %s from `plist.' +Allowed params: %s" interface (reverse (-map #'cl-first params))) + ,(if lsp-use-plists + `(-mapcat (-lambda ((key value)) + (list (or (cl-rest (assoc key ',params)) key) value)) + (-partition 2 plist)) + `(let (($$result (ht))) + (mapc (-lambda ((key value)) + (puthash (lsp-keyword->string (or (cl-rest (assoc key ',params)) + key)) + value + $$result)) + (-partition 2 plist)) + $$result))) + `(pcase-defmacro ,interface (&rest property-bindings) + ,(if lsp-use-plists + ``(and + (pred listp) + ;; Check if all the types required by the + ;; interface exist in the expr-val. + ,@(-map + (lambda (key) + `(pred + (lambda (plist) + (plist-member plist ,key)))) + ',required) + ;; Recursively generate the bindings. + ,@(let ((current-list property-bindings) + (output-bindings nil)) + ;; Invariant: while current-list is + ;; non-nil, the car of current-list is + ;; always of the form :key, while the + ;; cadr of current-list is either a) + ;; nil, b) of the form :key-next or c) + ;; a pcase pattern that can + ;; recursively match an expression. + (while current-list + (-let* (((curr-binding-as-keyword next-entry . _) current-list) + (curr-binding-as-camelcased-symbol + (or (alist-get curr-binding-as-keyword ',params) + (error "Unknown key: %s. Available keys: %s" + (symbol-name curr-binding-as-keyword) + ',(-map #'cl-first params)))) + (bound-name (lsp-keyword->symbol curr-binding-as-keyword)) + (next-entry-is-key-or-nil + (and (symbolp next-entry) + (or (null next-entry) + (s-starts-with? ":" (symbol-name next-entry)))))) + (cond + ;; If the next-entry is either a + ;; plist-key or nil, then bind to + ;; bound-name the value corresponding + ;; to the camelcased symbol. Pop + ;; current-list once. + (next-entry-is-key-or-nil + (push `(app (lambda (plist) + (plist-get plist ,curr-binding-as-camelcased-symbol)) + ,bound-name) + output-bindings) + (setf current-list (cdr current-list))) + ;; Otherwise, next-entry is a pcase + ;; pattern we recursively match to the + ;; expression. This can in general + ;; create additional bindings that we + ;; persist in the top level of + ;; bindings. We pop current-list + ;; twice. + (t + (push `(app (lambda (plist) + (plist-get plist ,curr-binding-as-camelcased-symbol)) + ,next-entry) + output-bindings) + (setf current-list (cddr current-list)))))) + output-bindings)) + ``(and + (pred ht?) + ,@(-map + (lambda (key) + `(pred + (lambda (hash-table) + (ht-contains? hash-table ,(lsp-keyword->string key))))) + ',required) + ,@(let ((current-list property-bindings) + (output-bindings nil)) + (while current-list + (-let* (((curr-binding-as-keyword next-entry . _) current-list) + (curr-binding-as-camelcased-string + (lsp-keyword->string (or (alist-get curr-binding-as-keyword ',params) + (error "Unknown key: %s. Available keys: %s" + (symbol-name curr-binding-as-keyword) + ',(-map #'cl-first params))))) + (bound-name (lsp-keyword->symbol curr-binding-as-keyword)) + (next-entry-is-key-or-nil + (and (symbolp next-entry) + (or (null next-entry) + (s-starts-with? ":" (symbol-name next-entry)))))) + (cond + (next-entry-is-key-or-nil + (push `(app (lambda (hash-table) + (ht-get hash-table ,curr-binding-as-camelcased-string)) + ,bound-name) + output-bindings) + (setf current-list (cdr current-list))) + (t + (push `(app (lambda (hash-table) + (ht-get hash-table ,curr-binding-as-camelcased-string)) + ,next-entry) + output-bindings) + (setf current-list (cddr current-list)))))) + output-bindings)))) + (-mapcat (-lambda ((label . name)) + (list + `(defun ,(intern (format "lsp:%s-%s" + (s-dashed-words (symbol-name interface)) + (substring (symbol-name label) 1))) + (object) + ,(if lsp-use-plists + `(plist-get object ,name) + `(when (ht? object) (gethash ,(lsp-keyword->string name) object)))) + `(defun ,(intern (format "lsp:set-%s-%s" + (s-dashed-words (symbol-name interface)) + (substring (symbol-name label) 1))) + (object value) + ,@(if lsp-use-plists + `((plist-put object ,name value)) + `((puthash ,(lsp-keyword->string name) value object) + object))))) + params))))) + (apply #'append) + (cl-list* 'progn)))) + +(if lsp-use-plists + (progn + (defun lsp-get (from key) + (plist-get from key)) + (defun lsp-put (where key value) + (plist-put where key value)) + (defun lsp-map (fn value) + (-map (-lambda ((k v)) + (funcall fn (lsp-keyword->string k) v)) + (-partition 2 value ))) + (defalias 'lsp-merge 'append) + (defalias 'lsp-empty? 'null) + (defalias 'lsp-copy 'copy-sequence) + (defun lsp-member? (from key) + (when (listp from) + (plist-member from key)))) + (defun lsp-get (from key) + (when from + (gethash (lsp-keyword->string key) from))) + (defun lsp-put (where key value) + (prog1 where + (puthash (lsp-keyword->string key) value where))) + (defun lsp-map (fn value) + (when value + (maphash fn value))) + (defalias 'lsp-merge 'ht-merge) + (defalias 'lsp-empty? 'ht-empty?) + (defalias 'lsp-copy 'ht-copy) + (defun lsp-member? (from key) + (when (hash-table-p from) + (not (eq (gethash (lsp-keyword->string key) from :__lsp_default) + :__lsp_default))))) + +(defmacro lsp-defun (name match-form &rest body) + "Define a function named NAME. +The function destructures its input as MATCH-FORM then executes BODY. + +Note that you have to enclose the MATCH-FORM in a pair of parens, +such that: + + (-defun (x) body) + (-defun (x y ...) body) + +has the usual semantics of `defun'. Furthermore, these get +translated into a normal `defun', so there is no performance +penalty. + +See `-let' for a description of the destructuring mechanism." + (declare (doc-string 3) (indent defun) + (debug (&define name sexp + [&optional stringp] + [&optional ("declare" &rest sexp)] + [&optional ("interactive" interactive)] + def-body))) + (cond + ((nlistp match-form) + (signal 'wrong-type-argument (list #'listp match-form))) + ;; no destructuring, so just return regular defun to make things faster + ((-all? #'symbolp match-form) + `(defun ,name ,match-form ,@body)) + (t + (-let* ((inputs (--map-indexed (list it (make-symbol (format "input%d" it-index))) match-form)) + ((body docs) (cond + ;; only docs + ((and (stringp (car body)) + (not (cdr body))) + (list body (car body))) + ;; docs + body + ((stringp (car body)) + (list (cdr body) (car body))) + ;; no docs + (t (list body)))) + ((body interactive-form) (cond + ;; interactive form + ((and (listp (car body)) + (eq (caar body) 'interactive)) + (list (cdr body) (car body))) + ;; no interactive form + (t (list body))))) + ;; TODO: because inputs to the defun are evaluated only once, + ;; -let* need not to create the extra bindings to ensure that. + ;; We should find a way to optimize that. Not critical however. + `(defun ,name ,(-map #'cadr inputs) + ,@(when docs (list docs)) + ,@(when interactive-form (list interactive-form)) + (-let* ,inputs ,@body)))))) + + + + +;; manually defined interfaces +(defconst lsp/markup-kind-plain-text "plaintext") +(defconst lsp/markup-kind-markdown "markdown") + +(lsp-interface (JSONResponse (:params :id :method :result) nil) + (JSONResponseError (:error) nil) + (JSONMessage nil (:params :id :method :result :error)) + (JSONResult nil (:params :id :method)) + (JSONNotification (:params :method) nil) + (JSONRequest (:params :method) nil) + (JSONError (:message :code) (:data)) + (ProgressParams (:token :value) nil) + (Edit (:kind) nil) + (WorkDoneProgress (:kind) nil) + (WorkDoneProgressBegin (:kind :title) (:cancellable :message :percentage)) + (WorkDoneProgressReport (:kind) (:cancellable :message :percentage)) + (WorkDoneProgressEnd (:kind) (:message)) + (WorkDoneProgressOptions nil (:workDoneProgress)) + (SemanticTokensOptions (:legend) (:rangeProvider :documentProvider)) + (SemanticTokensLegend (:tokenTypes :tokenModifiers)) + (SemanticTokensResult (:resultId) (:data)) + (SemanticTokensPartialResult nil (:data)) + (SemanticTokensEdit (:start :deleteCount) (:data)) + (SemanticTokensDelta (:resultId) (:edits)) + (SemanticTokensDeltaPartialResult nil (:edits))) + +(lsp-interface (v1:ProgressParams (:id :title) (:message :percentage :done))) + +(defun dash-expand:&RangeToPoint (key source) + "Convert the position KEY from SOURCE into a point." + `(lsp--position-to-point + (lsp-get ,source ,key))) + +(lsp-interface (eslint:StatusParams (:state) nil) + (eslint:OpenESLintDocParams (:url) nil) + (eslint:ConfirmExecutionParams (:scope :file :libraryPath) nil)) + +(lsp-interface (haxe:ProcessStartNotification (:title) nil)) + +(lsp-interface (pwsh:ScriptRegion (:StartLineNumber :EndLineNumber :StartColumnNumber :EndColumnNumber :Text) nil)) + +(lsp-interface (omnisharp:ErrorMessage (:Text :FileName :Line :Column)) + (omnisharp:ProjectInformationRequest (:FileName)) + (omnisharp:MsBuildProject (:IsUnitProject :IsExe :Platform :Configuration :IntermediateOutputPath :OutputPath :TargetFrameworks :SourceFiles :TargetFramework :TargetPath :AssemblyName :Path :ProjectGuid)) + (omnisharp:ProjectInformation (:ScriptProject :MsBuildProject)) + (omnisharp:CodeStructureRequest (:FileName)) + (omnisharp:CodeStructureResponse (:Elements)) + (omnisharp:CodeElement (:Kind :Name :DisplayName :Children :Ranges :Properties)) + (omnisharp:CodeElementProperties () (:static :accessibility :testMethodName :testFramework)) + (omnisharp:Range (:Start :End)) + (omnisharp:RangeList () (:attributes :full :name)) + (omnisharp:Point (:Line :Column)) + (omnisharp:RunTestsInClassRequest (:MethodNames :RunSettings :TestFrameworkname :TargetFrameworkVersion :NoBuild :Line :Column :Buffer :FileName)) + (omnisharp:RunTestResponse (:Results :Pass :Failure :ContextHadNoTests)) + (omnisharp:TestMessageEvent (:MessageLevel :Message)) + (omnisharp:DotNetTestResult (:MethodName :Outcome :ErrorMessage :ErrorStackTrace :StandardOutput :StandardError))) + +(lsp-interface (rls:Cmd (:args :binary :env :cwd) nil)) + +(defconst lsp/rust-analyzer-inlay-hint-kind-type-hint "TypeHint") +(defconst lsp/rust-analyzer-inlay-hint-kind-param-hint "ParameterHint") +(defconst lsp/rust-analyzer-inlay-hint-kind-chaining-hint "ChainingHint") +(lsp-interface (rust-analyzer:AnalyzerStatusParams (:textDocument)) + (rust-analyzer:SyntaxTreeParams (:textDocument) (:range)) + (rust-analyzer:ExpandMacroParams (:textDocument :position) nil) + (rust-analyzer:ExpandedMacro (:name :expansion) nil) + (rust-analyzer:MatchingBraceParams (:textDocument :positions) nil) + (rust-analyzer:OpenCargoTomlParams (:textDocument) nil) + (rust-analyzer:ResovedCodeActionParams (:id :codeActionParams) nil) + (rust-analyzer:JoinLinesParams (:textDocument :ranges) nil) + (rust-analyzer:RunnablesParams (:textDocument) (:position)) + (rust-analyzer:Runnable (:label :kind :args) (:location)) + (rust-analyzer:RunnableArgs (:cargoArgs :executableArgs) (:workspaceRoot)) + (rust-analyzer:RelatedTestsParams (:textDocument :position) nil) + (rust-analyzer:RelatedTests (:runnable) nil) + (rust-analyzer:InlayHint (:range :label :kind) nil) + (rust-analyzer:InlayHintsParams (:textDocument) nil) + (rust-analyzer:SsrParams (:query :parseOnly) nil) + (rust-analyzer:CommandLink (:title :command) (:arguments :tooltip)) + (rust-analyzer:CommandLinkGroup (:commands) (:title))) + + +;; begin autogenerated code + +(defvar lsp/completion-item-kind-lookup + [nil Text Method Function Constructor Field Variable Class Interface Module Property Unit Value Enum Keyword Snippet Color File Reference Folder EnumMember Constant Struct Event Operator TypeParameter]) +(defconst lsp/completion-item-kind-text 1) +(defconst lsp/completion-item-kind-method 2) +(defconst lsp/completion-item-kind-function 3) +(defconst lsp/completion-item-kind-constructor 4) +(defconst lsp/completion-item-kind-field 5) +(defconst lsp/completion-item-kind-variable 6) +(defconst lsp/completion-item-kind-class 7) +(defconst lsp/completion-item-kind-interface 8) +(defconst lsp/completion-item-kind-module 9) +(defconst lsp/completion-item-kind-property 10) +(defconst lsp/completion-item-kind-unit 11) +(defconst lsp/completion-item-kind-value 12) +(defconst lsp/completion-item-kind-enum 13) +(defconst lsp/completion-item-kind-keyword 14) +(defconst lsp/completion-item-kind-snippet 15) +(defconst lsp/completion-item-kind-color 16) +(defconst lsp/completion-item-kind-file 17) +(defconst lsp/completion-item-kind-reference 18) +(defconst lsp/completion-item-kind-folder 19) +(defconst lsp/completion-item-kind-enum-member 20) +(defconst lsp/completion-item-kind-constant 21) +(defconst lsp/completion-item-kind-struct 22) +(defconst lsp/completion-item-kind-event 23) +(defconst lsp/completion-item-kind-operator 24) +(defconst lsp/completion-item-kind-type-parameter 25) +(defvar lsp/completion-trigger-kind-lookup + [nil Invoked TriggerCharacter TriggerForIncompleteCompletions]) +(defconst lsp/completion-trigger-kind-invoked 1) +(defconst lsp/completion-trigger-kind-trigger-character 2) +(defconst lsp/completion-trigger-kind-trigger-for-incomplete-completions 3) +(defvar lsp/diagnostic-severity-lookup + [nil Error Warning Information Hint Max]) +(defconst lsp/diagnostic-severity-error 1) +(defconst lsp/diagnostic-severity-warning 2) +(defconst lsp/diagnostic-severity-information 3) +(defconst lsp/diagnostic-severity-hint 4) +(defconst lsp/diagnostic-severity-max 5) +(defvar lsp/diagnostic-tag-lookup + [nil Unnecessary Deprecated]) +(defconst lsp/diagnostic-tag-unnecessary 1) +(defconst lsp/diagnostic-tag-deprecated 2) +(defvar lsp/document-highlight-kind-lookup + [nil Text Read Write]) +(defconst lsp/document-highlight-kind-text 1) +(defconst lsp/document-highlight-kind-read 2) +(defconst lsp/document-highlight-kind-write 3) +(defvar lsp/file-change-type-lookup + [nil Created Changed Deleted]) +(defconst lsp/file-change-type-created 1) +(defconst lsp/file-change-type-changed 2) +(defconst lsp/file-change-type-deleted 3) +(defvar lsp/insert-text-format-lookup + [nil PlainText Snippet]) +(defconst lsp/insert-text-format-plain-text 1) +(defconst lsp/insert-text-format-snippet 2) +(defvar lsp/insert-text-mode-lookup + [nil AsIs AdjustIndentation]) +(defconst lsp/insert-text-mode-as-it 1) +(defconst lsp/insert-text-mode-adjust-indentation 2) +(defvar lsp/message-type-lookup + [nil Error Warning Info Log]) +(defconst lsp/message-type-error 1) +(defconst lsp/message-type-warning 2) +(defconst lsp/message-type-info 3) +(defconst lsp/message-type-log 4) +(defvar lsp/signature-help-trigger-kind-lookup + [nil Invoked TriggerCharacter ContentChange]) +(defconst lsp/signature-help-trigger-kind-invoked 1) +(defconst lsp/signature-help-trigger-kind-trigger-character 2) +(defconst lsp/signature-help-trigger-kind-content-change 3) +(defvar lsp/symbol-kind-lookup + [nil File Module Namespace Package Class Method Property Field Constructor Enum Interface Function Variable Constant String Number Boolean Array Object Key Null EnumMember Struct Event Operator TypeParameter]) +(defconst lsp/symbol-kind-file 1) +(defconst lsp/symbol-kind-module 2) +(defconst lsp/symbol-kind-namespace 3) +(defconst lsp/symbol-kind-package 4) +(defconst lsp/symbol-kind-class 5) +(defconst lsp/symbol-kind-method 6) +(defconst lsp/symbol-kind-property 7) +(defconst lsp/symbol-kind-field 8) +(defconst lsp/symbol-kind-constructor 9) +(defconst lsp/symbol-kind-enum 10) +(defconst lsp/symbol-kind-interface 11) +(defconst lsp/symbol-kind-function 12) +(defconst lsp/symbol-kind-variable 13) +(defconst lsp/symbol-kind-constant 14) +(defconst lsp/symbol-kind-string 15) +(defconst lsp/symbol-kind-number 16) +(defconst lsp/symbol-kind-boolean 17) +(defconst lsp/symbol-kind-array 18) +(defconst lsp/symbol-kind-object 19) +(defconst lsp/symbol-kind-key 20) +(defconst lsp/symbol-kind-null 21) +(defconst lsp/symbol-kind-enum-member 22) +(defconst lsp/symbol-kind-struct 23) +(defconst lsp/symbol-kind-event 24) +(defconst lsp/symbol-kind-operator 25) +(defconst lsp/symbol-kind-type-parameter 26) +(defvar lsp/text-document-save-reason-lookup + [nil Manual AfterDelay FocusOut]) +(defconst lsp/text-document-save-reason-manual 1) +(defconst lsp/text-document-save-reason-after-delay 2) +(defconst lsp/text-document-save-reason-focus-out 3) +(defvar lsp/text-document-sync-kind-lookup + [None Full Incremental]) +(defconst lsp/text-document-sync-kind-none 0) +(defconst lsp/text-document-sync-kind-full 1) +(defconst lsp/text-document-sync-kind-incremental 2) +(defvar lsp/type-hierarchy-direction-lookup + [nil Children Parents Both]) +(defconst lsp/type-hierarchy-direction-children 1) +(defconst lsp/type-hierarchy-direction-parents 2) +(defconst lsp/type-hierarchy-direction-both 3) +(defvar lsp/call-hierarchy-direction-lookup + [nil CallsFrom CallsTo]) +(defconst lsp/call-hierarchy-direction-calls-from 1) +(defconst lsp/call-hierarchy-direction-calls-to 2) +(defvar lsp/response-error-code-lookup + [nil ParseError InvalidRequest MethodNotFound InvalidParams InternalError serverErrorStart serverErrorEnd]) +(defconst lsp/response-error-code-parse-error 1) +(defconst lsp/response-error-code-invalid-request 2) +(defconst lsp/response-error-code-method-not-found 3) +(defconst lsp/response-error-code-invalid-params 4) +(defconst lsp/response-error-code-internal-error 5) +(defconst lsp/response-error-code-server-error-start 6) +(defconst lsp/response-error-code-server-error-end 7) + +(lsp-interface + (CallHierarchyCapabilities nil (:dynamicRegistration)) + (CallHierarchyItem (:kind :name :range :selectionRange :uri) (:detail :tags)) + (ClientCapabilities nil (:experimental :textDocument :workspace)) + (ClientInfo (:name) (:version)) + (CodeActionCapabilities nil (:codeActionLiteralSupport :dynamicRegistration :isPreferredSupport :dataSupport :resolveSupport)) + (CodeActionContext (:diagnostics) (:only)) + (CodeActionKindCapabilities (:valueSet) nil) + (CodeActionLiteralSupportCapabilities nil (:codeActionKind)) + (CodeActionOptions nil (:codeActionKinds :resolveProvider)) + (CodeLensCapabilities nil (:dynamicRegistration)) + (CodeLensOptions (:resolveProvider) nil) + (Color (:red :green :blue :alpha) nil) + (ColorProviderCapabilities nil (:dynamicRegistration)) + (ColorProviderOptions nil (:documentSelector :id)) + (ColoringInformation (:range :styles) nil) + (Command (:title :command) (:arguments)) + (CompletionCapabilities nil (:completionItem :completionItemKind :contextSupport :dynamicRegistration)) + (CompletionContext (:triggerKind) (:triggerCharacter)) + (CompletionItem (:label) (:additionalTextEdits :command :commitCharacters :data :deprecated :detail :documentation :filterText :insertText :insertTextFormat :insertTextMode :kind :preselect :sortText :tags :textEdit :score)) + (CompletionItemCapabilities nil (:commitCharactersSupport :deprecatedSupport :documentationFormat :preselectSupport :snippetSupport :tagSupport :insertReplaceSupport :resolveSupport)) + (CompletionItemKindCapabilities nil (:valueSet)) + (CompletionItemTagSupportCapabilities (:valueSet) nil) + (CompletionOptions nil (:resolveProvider :triggerCharacters :allCommitCharacters)) + (ConfigurationItem nil (:scopeUri :section)) + (CreateFileOptions nil (:ignoreIfExists :overwrite)) + (DeclarationCapabilities nil (:dynamicRegistration :linkSupport)) + (DefinitionCapabilities nil (:dynamicRegistration :linkSupport)) + (DeleteFileOptions nil (:ignoreIfNotExists :recursive)) + (Diagnostic (:range :message) (:code :relatedInformation :severity :source :tags)) + (DiagnosticRelatedInformation (:location :message) nil) + (DiagnosticsTagSupport (:valueSet) nil) + (DidChangeConfigurationCapabilities nil (:dynamicRegistration)) + (DidChangeWatchedFilesCapabilities nil (:dynamicRegistration)) + (DocumentFilter nil (:language :pattern :scheme)) + (DocumentHighlightCapabilities nil (:dynamicRegistration)) + (DocumentLinkCapabilities nil (:dynamicRegistration :tooltipSupport)) + (DocumentLinkOptions nil (:resolveProvider)) + (DocumentOnTypeFormattingOptions (:firstTriggerCharacter) (:moreTriggerCharacter)) + (DocumentSymbol (:kind :name :range :selectionRange) (:children :deprecated :detail)) + (DocumentSymbolCapabilities nil (:dynamicRegistration :hierarchicalDocumentSymbolSupport :symbolKind)) + (ExecuteCommandCapabilities nil (:dynamicRegistration)) + (ExecuteCommandOptions (:commands) nil) + (FileEvent (:type :uri) nil) + (FileSystemWatcher (:globPattern) (:kind)) + (FoldingRangeCapabilities nil (:dynamicRegistration :lineFoldingOnly :rangeLimit)) + (FoldingRangeProviderOptions nil (:documentSelector :id)) + (FormattingCapabilities nil (:dynamicRegistration)) + (FormattingOptions (:tabSize :insertSpaces) (:trimTrailingWhitespace :insertFinalNewline :trimFinalNewlines)) + (HoverCapabilities nil (:contentFormat :dynamicRegistration)) + (ImplementationCapabilities nil (:dynamicRegistration :linkSupport)) + (Location (:range :uri) nil) + (MarkedString (:language :value) nil) + (MarkupContent (:kind :value) nil) + (MessageActionItem (:title) nil) + (OnTypeFormattingCapabilities nil (:dynamicRegistration)) + (ParameterInformation (:label) (:documentation)) + (ParameterInformationCapabilities nil (:labelOffsetSupport)) + (Position (:character :line) nil) + (PublishDiagnosticsCapabilities nil (:relatedInformation :tagSupport :versionSupport)) + (Range (:start :end) nil) + (RangeFormattingCapabilities nil (:dynamicRegistration)) + (ReferenceContext (:includeDeclaration) nil) + (ReferencesCapabilities nil (:dynamicRegistration)) + (Registration (:method :id) (:registerOptions)) + (RenameCapabilities nil (:dynamicRegistration :prepareSupport)) + (RenameFileOptions nil (:ignoreIfExists :overwrite)) + (RenameOptions nil (:documentSelector :id :prepareProvider)) + (ResourceChange nil (:current :newUri)) + (ResourceOperation (:kind) nil) + (SaveOptions nil (:includeText)) + (SelectionRange (:range) (:parent)) + (SelectionRangeCapabilities nil (:dynamicRegistration)) + (SemanticHighlightingCapabilities nil (:semanticHighlighting)) + (SemanticHighlightingInformation (:line) (:tokens)) + (SemanticHighlightingServerCapabilities nil (:scopes)) + (ServerCapabilities nil (:callHierarchyProvider :codeActionProvider :codeLensProvider :colorProvider :completionProvider :declarationProvider :definitionProvider :documentFormattingProvider :documentHighlightProvider :documentLinkProvider :documentOnTypeFormattingProvider :documentRangeFormattingProvider :documentSymbolProvider :executeCommandProvider :experimental :foldingRangeProvider :hoverProvider :implementationProvider :referencesProvider :renameProvider :selectionRangeProvider :semanticHighlighting :signatureHelpProvider :textDocumentSync :typeDefinitionProvider :typeHierarchyProvider :workspace :workspaceSymbolProvider :semanticTokensProvider)) + (ServerInfo (:name) (:version)) + (SignatureHelp (:signatures) (:activeParameter :activeSignature)) + (SignatureHelpCapabilities nil (:contextSupport :dynamicRegistration :signatureInformation)) + (SignatureHelpContext (:triggerKind :isRetrigger) (:activeSignatureHelp :triggerCharacter)) + (SignatureHelpOptions nil (:retriggerCharacters :triggerCharacters)) + (SignatureInformation (:label) (:documentation :parameters)) + (SignatureInformationCapabilities nil (:documentationFormat :parameterInformation)) + (StaticRegistrationOptions nil (:documentSelector :id)) + (SymbolCapabilities nil (:dynamicRegistration :symbolKind)) + (SymbolKindCapabilities nil (:valueSet)) + (SynchronizationCapabilities nil (:didSave :dynamicRegistration :willSave :willSaveWaitUntil)) + (TextDocumentClientCapabilities nil (:callHierarchy :codeAction :codeLens :colorProvider :completion :declaration :definition :documentHighlight :documentLink :documentSymbol :foldingRange :formatting :hover :implementation :onTypeFormatting :publishDiagnostics :rangeFormatting :references :rename :selectionRange :semanticHighlightingCapabilities :signatureHelp :synchronization :typeDefinition :typeHierarchyCapabilities)) + (TextDocumentContentChangeEvent (:text) (:range :rangeLength)) + (TextDocumentEdit (:textDocument :edits) nil) + (TextDocumentIdentifier (:uri) nil) + (TextDocumentItem (:languageId :text :uri :version) nil) + (TextDocumentSyncOptions nil (:change :openClose :save :willSave :willSaveWaitUntil)) + (TextEdit (:newText :range) nil) + (InsertReplaceEdit (:newText :insert :replace) nil) + (SnippetTextEdit (:newText :range) (:insertTextFormat)) + (TypeDefinitionCapabilities nil (:dynamicRegistration :linkSupport)) + (TypeHierarchyCapabilities nil (:dynamicRegistration)) + (TypeHierarchyItem (:kind :name :range :selectionRange :uri) (:children :data :deprecated :detail :parents)) + (Unregistration (:method :id) nil) + (VersionedTextDocumentIdentifier (:uri) (:version)) + (WorkspaceClientCapabilities nil (:applyEdit :configuration :didChangeConfiguration :didChangeWatchedFiles :executeCommand :symbol :workspaceEdit :workspaceFolders)) + (WorkspaceEdit nil (:changes :documentChanges :resourceChanges)) + (WorkspaceEditCapabilities nil (:documentChanges :failureHandling :resourceChanges :resourceOperations)) + (WorkspaceFolder (:uri :name) nil) + (WorkspaceFoldersChangeEvent (:removed :added) nil) + (WorkspaceFoldersOptions nil (:changeNotifications :supported)) + (WorkspaceServerCapabilities nil (:workspaceFolders)) + (ApplyWorkspaceEditParams (:edit) (:label)) + (ApplyWorkspaceEditResponse (:applied) nil) + (CallHierarchyIncomingCall (:from :fromRanges) nil) + (CallHierarchyIncomingCallsParams (:item) nil) + (CallHierarchyOutgoingCall (:to :fromRanges) nil) + (CallHierarchyOutgoingCallsParams (:item) nil) + (CallHierarchyPrepareParams (:textDocument :position) (:uri)) + (CodeAction (:title) (:command :diagnostics :edit :isPreferred :kind :data)) + (CodeActionKind nil nil) + (CodeActionParams (:textDocument :context :range) nil) + (CodeLens (:range) (:command :data)) + (CodeLensParams (:textDocument) nil) + (CodeLensRegistrationOptions nil (:documentSelector :resolveProvider)) + (ColorInformation (:color :range) nil) + (ColorPresentation (:label) (:additionalTextEdits :textEdit)) + (ColorPresentationParams (:color :textDocument :range) nil) + (ColoringParams (:uri :infos) nil) + (ColoringStyle nil nil) + (CompletionList (:items :isIncomplete) nil) + (CompletionParams (:textDocument :position) (:context :uri)) + (CompletionRegistrationOptions nil (:documentSelector :resolveProvider :triggerCharacters)) + (ConfigurationParams (:items) nil) + (CreateFile (:kind :uri) (:options)) + (DeclarationParams (:textDocument :position) (:uri)) + (DefinitionParams (:textDocument :position) (:uri)) + (DeleteFile (:kind :uri) (:options)) + (DidChangeConfigurationParams (:settings) nil) + (DidChangeTextDocumentParams (:contentChanges :textDocument) (:uri)) + (DidChangeWatchedFilesParams (:changes) nil) + (DidChangeWatchedFilesRegistrationOptions (:watchers) nil) + (DidChangeWorkspaceFoldersParams (:event) nil) + (DidCloseTextDocumentParams (:textDocument) nil) + (DidOpenTextDocumentParams (:textDocument) (:text)) + (DidSaveTextDocumentParams (:textDocument) (:text)) + (DocumentColorParams (:textDocument) nil) + (DocumentFormattingParams (:textDocument :options) nil) + (DocumentHighlight (:range) (:kind)) + (DocumentHighlightParams (:textDocument :position) (:uri)) + (DocumentLink (:range) (:data :target :tooltip)) + (DocumentLinkParams (:textDocument) nil) + (DocumentLinkRegistrationOptions nil (:documentSelector :resolveProvider)) + (DocumentOnTypeFormattingParams (:ch :textDocument :options :position) nil) + (DocumentOnTypeFormattingRegistrationOptions (:firstTriggerCharacter) (:documentSelector :moreTriggerCharacter)) + (DocumentRangeFormattingParams (:textDocument :options :range) nil) + (DocumentSymbolParams (:textDocument) nil) + (DynamicRegistrationCapabilities nil (:dynamicRegistration)) + (ExecuteCommandParams (:command) (:arguments)) + (ExecuteCommandRegistrationOptions (:commands) nil) + (FailureHandlingKind nil nil) + (FoldingRange (:endLine :startLine) (:endCharacter :kind :startCharacter)) + (FoldingRangeKind nil nil) + (FoldingRangeRequestParams (:textDocument) nil) + (Hover (:contents) (:range)) + (HoverParams (:textDocument :position) (:uri)) + (ImplementationParams (:textDocument :position) (:uri)) + (InitializeError (:retry) nil) + (InitializeErrorCode nil nil) + (InitializeParams nil (:capabilities :clientInfo :clientName :initializationOptions :processId :rootPath :rootUri :trace :workspaceFolders)) + (InitializeResult (:capabilities) (:serverInfo)) + (InitializedParams nil nil) + (LocationLink (:targetSelectionRange :targetUri :targetRange) (:originSelectionRange)) + (MarkupKind nil nil) + (MessageParams (:type :message) nil) + (PrepareRenameParams (:textDocument :position) (:uri)) + (PrepareRenameResult (:range :placeholder) nil) + (PublishDiagnosticsParams (:diagnostics :uri) (:version)) + (ReferenceParams (:textDocument :context :position) (:uri)) + (RegistrationParams (:registrations) nil) + (RenameFile (:kind :newUri :oldUri) (:options)) + (RenameParams (:newName :textDocument :position) (:uri)) + (ResolveTypeHierarchyItemParams (:item :resolve :direction) nil) + (ResourceOperationKind nil nil) + (SelectionRangeParams (:textDocument :positions) nil) + (SemanticHighlightingParams (:textDocument :lines) nil) + (ShowMessageRequestParams (:type :message) (:actions)) + (SignatureHelpParams (:textDocument :position) (:context :uri)) + (SignatureHelpRegistrationOptions nil (:documentSelector :triggerCharacters)) + (SymbolInformation (:kind :name :location) (:containerName :deprecated)) + (TextDocumentChangeRegistrationOptions (:syncKind) (:documentSelector)) + (TextDocumentPositionParams (:textDocument :position) (:uri)) + (TextDocumentRegistrationOptions nil (:documentSelector)) + (TextDocumentSaveRegistrationOptions nil (:documentSelector :includeText)) + (TypeDefinitionParams (:textDocument :position) (:uri)) + (TypeHierarchyParams (:resolve :textDocument :position) (:direction :uri)) + (UnregistrationParams (:unregisterations) nil) + (WatchKind nil nil) + (WillSaveTextDocumentParams (:reason :textDocument) nil) + (WorkspaceSymbolParams (:query) nil)) + + +(provide 'lsp-protocol) + +;;; lsp-protocol.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-purescript.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-purescript.el new file mode 100644 index 0000000..d6e761a --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-purescript.el @@ -0,0 +1,72 @@ +;;; lsp-purescript.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, purescript + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the PureScript Programming Language. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-purescript nil + "LSP support for PureScript, using purescript-language-server." + :group 'lsp-mode + :link '(url-link "https://github.com/nwolverson/purescript-language-server")) + +(defcustom lsp-purescript-server-executable nil + "Path to server executable." + :type 'string + :risky t + :group 'lsp-purescript) + +(defcustom lsp-purescript-server-args + '("--stdio") + "Arguments to pass to the server." + :type '(repeat string) + :risky t + :group 'lsp-purescript) + +(defun lsp-purescript--server-command () + "Generate LSP startup command for purescript-language-server." + (cons (or lsp-purescript-server-executable + (lsp-package-path 'purescript-language-server)) + lsp-purescript-server-args)) + +(lsp-dependency 'purescript-language-server + '(:system "purescript-language-server") + '(:npm :package "purescript-language-server" + :path "purescript-language-server")) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection + #'lsp-purescript--server-command) + :major-modes '(purescript-mode) + :priority -1 + :server-id 'pursls + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'purescript-language-server callback error-callback)))) + + +(lsp-consistency-check lsp-purescript) + +(provide 'lsp-purescript) +;;; lsp-purescript.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-pwsh.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-pwsh.el new file mode 100644 index 0000000..0e90164 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-pwsh.el @@ -0,0 +1,360 @@ +;;; lsp-pwsh.el --- client for PowerShellEditorServices -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Kien Nguyen + +;; Author: kien.n.quang at gmail.com +;; Keywords: lsp + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; + +;;; Code: + +(require 'f) +(require 'dash) +(require 's) +(require 'ht) + +(require 'lsp-protocol) +(require 'lsp-mode) + +(defgroup lsp-pwsh nil + "LSP support for PowerShell, using the PowerShellEditorServices." + :group 'lsp-mode + :package-version '(lsp-mode . "6.2")) + +;; PowerShell vscode flags +(defcustom lsp-pwsh-help-completion "BlockComment" + "Controls the comment-based help completion behavior triggered by typing '##'. +Set the generated help style with 'BlockComment' or 'LineComment'. +Disable the feature with 'Disabled'." + :type + '(choice + (:tag "Disabled" "BlockComment" "LineComment")) + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-script-analysis-enable t + "Enables real-time script analysis from PowerShell Script Analyzer. +Uses the newest installed version of the PSScriptAnalyzer module or the +version bundled with this extension, if it is newer." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-script-analysis-settings-path "" + "Specifies the path to a PowerShell Script Analyzer settings file. +To override the default settings for all projects, enter an absolute path, +or enter a path relative to your workspace." + :type 'string + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-folding-enable t + "Enables syntax based code folding. +When disabled, the default indentation based code folding is used." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-folding-show-last-line t + "Shows the last line of a folded section. +Similar to the default VSCode folding style. +When disabled, the entire folded region is hidden." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-formatting-preset "Custom" + "Sets the codeformatting options to follow the given indent style. +Sets in a way that is compatible with PowerShell syntax. +For more information about the brace styles please refer to https://github.com/PoshCode/PowerShellPracticeAndStyle/issues/81." + :type + '(choice + (:tag "Custom" "Allman" "OTBS" "Stroustrup")) + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-formatting-open-brace-on-same-line t + "Places open brace on the same line as its associated statement." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-formatting-new-line-after-open-brace t + "Adds a newline (line break) after an open brace." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-formatting-new-line-after-close-brace t + "Adds a newline (line break) after a closing brace." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-formatting-pipeline-indentation-style "NoIndentation" + "Multi-line pipeline style settings." + :type + '(choice + (:tag "IncreaseIndentationForFirstPipeline" "IncreaseIndentationAfterEveryPipeline" "NoIndentation")) + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-formatting-whitespace-before-open-brace t + "Adds a space between a keyword and its associated scriptblock expression." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-formatting-whitespace-before-open-paren t + "Adds a space between a keyword (if, elseif, while, switch, etc) and its +associated conditional expression." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-formatting-whitespace-around-operator t + "Adds spaces before and after an operator ('=', '+', '-', etc.)." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-formatting-whitespace-after-separator t + "Adds a space after a separator (',' and ';')." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-formatting-whitespace-inside-brace t + "Adds a space after an opening brace ('{') and before a closing brace ('}')." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-formatting-whitespace-around-pipe t + "Adds a space before and after the pipeline operator ('|')." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-formatting-ignore-one-line-block t + "Does not reformat one-line code blocks, such as \"if (...) {...} else +{...}\"." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-formatting-align-property-value-pairs t + "Align assignment statements in a hashtable or a DSC Configuration." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-code-formatting-use-correct-casing nil + "Use correct casing for cmdlets." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-developer-editor-services-log-level "Normal" + "Sets the log level for the PowerShell Editor Services host executable. +Valid values are 'Diagnostic', 'Verbose', 'Normal', 'Warning', and 'Error'" + :type + '(choice + (:tag "Diagnostic" "Verbose" "Normal" "Warning" "Error")) + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-developer-editor-services-wait-for-debugger nil + "Launches the language service with the /waitForDebugger flag to force it to +wait for a .NET debugger to attach before proceeding." + :type 'boolean + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-developer-feature-flags nil + "An array of strings that enable experimental features in the PowerShell +extension." + :type + '(repeat string) + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(lsp-register-custom-settings + '(("powershell.developer.featureFlags" lsp-pwsh-developer-feature-flags) + ("powershell.developer.editorServicesWaitForDebugger" lsp-pwsh-developer-editor-services-wait-for-debugger t) + ("powershell.codeFormatting.useCorrectCasing" lsp-pwsh-code-formatting-use-correct-casing t) + ("powershell.codeFormatting.alignPropertyValuePairs" lsp-pwsh-code-formatting-align-property-value-pairs t) + ("powershell.codeFormatting.ignoreOneLineBlock" lsp-pwsh-code-formatting-ignore-one-line-block t) + ("powershell.codeFormatting.whitespaceAroundPipe" lsp-pwsh-code-formatting-whitespace-around-pipe t) + ("powershell.codeFormatting.whitespaceInsideBrace" lsp-pwsh-code-formatting-whitespace-inside-brace t) + ("powershell.codeFormatting.whitespaceAfterSeparator" lsp-pwsh-code-formatting-whitespace-after-separator t) + ("powershell.codeFormatting.whitespaceAroundOperator" lsp-pwsh-code-formatting-whitespace-around-operator t) + ("powershell.codeFormatting.whitespaceBeforeOpenParen" lsp-pwsh-code-formatting-whitespace-before-open-paren t) + ("powershell.codeFormatting.whitespaceBeforeOpenBrace" lsp-pwsh-code-formatting-whitespace-before-open-brace t) + ("powershell.codeFormatting.pipelineIndentationStyle" lsp-pwsh-code-formatting-pipeline-indentation-style) + ("powershell.codeFormatting.newLineAfterCloseBrace" lsp-pwsh-code-formatting-new-line-after-close-brace t) + ("powershell.codeFormatting.newLineAfterOpenBrace" lsp-pwsh-code-formatting-new-line-after-open-brace t) + ("powershell.codeFormatting.openBraceOnSameLine" lsp-pwsh-code-formatting-open-brace-on-same-line t) + ("powershell.codeFormatting.preset" lsp-pwsh-code-formatting-preset) + ("powershell.codeFolding.showLastLine" lsp-pwsh-code-folding-show-last-line t) + ("powershell.codeFolding.enable" lsp-pwsh-code-folding-enable t) + ("powershell.scriptAnalysis.settingsPath" lsp-pwsh-script-analysis-settings-path) + ("powershell.scriptAnalysis.enable" lsp-pwsh-script-analysis-enable t) + ("powershell.helpCompletion" lsp-pwsh-help-completion))) + +;; lsp-pwsh custom variables +(defcustom lsp-pwsh-ext-path (f-join lsp-server-install-dir "pwsh") + "The path to powershell vscode extension." + :type 'string + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-exe (or (executable-find "pwsh") (executable-find "powershell")) + "PowerShell executable." + :type 'string + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pwsh-dir (expand-file-name "PowerShellEditorServices" lsp-pwsh-ext-path) + "Path to PowerShellEditorServices without last slash." + :type 'string + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defvar lsp-pwsh-log-path (expand-file-name "logs" lsp-pwsh-ext-path) + "Path to directory where server will write log files. +Must not nil.") + +(defvar lsp-pwsh--sess-id (emacs-pid)) + +(defun lsp-pwsh--command () + "Return the command to start server." + + `(,lsp-pwsh-exe "-NoProfile" "-NonInteractive" "-NoLogo" + ,@(if (eq system-type 'windows-nt) '("-ExecutionPolicy" "Bypass")) + "-OutputFormat" "Text" + "-File" + ,(f-join lsp-pwsh-dir "PowerShellEditorServices/Start-EditorServices.ps1") + "-HostName" "\"Emacs Host\"" + "-HostProfileId" "'Emacs.LSP'" + "-HostVersion" "0.1" + "-LogPath" ,(f-join lsp-pwsh-log-path "emacs-powershell.log") + "-LogLevel" ,lsp-pwsh-developer-editor-services-log-level + "-SessionDetailsPath" + ,(format "%s/PSES-VSCode-%d" lsp-pwsh-log-path lsp-pwsh--sess-id) + ;; "-AdditionalModules" "@('PowerShellEditorServices.VSCode')" + "-Stdio" + "-BundledModulesPath" ,lsp-pwsh-dir + "-FeatureFlags" "@()")) + +(defun lsp-pwsh--extra-init-params () + "Return form describing parameters for language server.") + +(lsp-defun lsp-pwsh--apply-code-action-edits ((&Command :command :arguments?)) + "Handle ACTION for PowerShell.ApplyCodeActionEdits." + (-if-let* (((&pwsh:ScriptRegion :start-line-number :end-line-number + :start-column-number :end-column-number :text) + (lsp-seq-first arguments?)) + (start-position (lsp-make-position :line (1- start-line-number) + :character (1- start-column-number))) + (end-position (lsp-make-position :line (1- end-line-number) + :character (1- end-column-number))) + (edits `[,(lsp-make-text-edit :range (lsp-make-range :start start-position + :end end-position) + :newText text)])) + (lsp--apply-text-edits edits 'code-action) + (lsp-send-execute-command command arguments?))) + +(lsp-defun lsp-pwsh--show-code-action-document ((&Command :arguments?)) + "Handle ACTION for PowerShell.ShowCodeActionDocumentation." + (-if-let* ((rule-raw (lsp-seq-first arguments?)) + (rule-id (if (s-prefix-p "PS" rule-raw) (substring rule-raw 2) rule-raw))) + (browse-url + (concat "https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/" + rule-id + ".md")) + (lsp-warn "Cannot show documentation for code action, no ruleName was supplied"))) + +(defvar lsp-pwsh--major-modes '(powershell-mode)) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection #'lsp-pwsh--command + (lambda () + (f-exists? lsp-pwsh-dir))) + :major-modes lsp-pwsh--major-modes + :server-id 'pwsh-ls + :priority -1 + :multi-root t + :initialization-options #'lsp-pwsh--extra-init-params + :notification-handlers (ht ("powerShell/executionStatusChanged" #'ignore) + ("output" #'ignore)) + :action-handlers (ht ("PowerShell.ApplyCodeActionEdits" + #'lsp-pwsh--apply-code-action-edits) + ("PowerShell.ShowCodeActionDocumentation" + #'lsp-pwsh--show-code-action-document)) + :initialized-fn (lambda (w) + (with-lsp-workspace w + (lsp--set-configuration + (lsp-configuration-section "powershell"))) + (let ((caps (lsp--workspace-server-capabilities w))) + (lsp:set-server-capabilities-document-range-formatting-provider? caps t) + (lsp:set-server-capabilities-document-formatting-provider? caps t))) + :download-server-fn #'lsp-pwsh-setup)) + +(defcustom lsp-pwsh-github-asset-url + "https://github.com/%s/%s/releases/latest/download/%s" + "GitHub latest asset template url." + :type 'string + :group 'lsp-pwsh + :package-version '(lsp-mode . "6.2")) + +(defun lsp-pwsh-setup (_client callback error-callback update) + "Downloads PowerShellEditorServices to `lsp-pwsh-dir'. +CALLBACK is called when the download finish successfully otherwise +ERROR-CALLBACK is called. +UPDATE is non-nil if it is already downloaded. +FORCED if specified with prefix argument." + + (unless (and lsp-pwsh-exe (file-executable-p lsp-pwsh-exe)) + (user-error "Use `lsp-pwsh-exe' with the value of `%s' is not a valid powershell binary" + lsp-pwsh-exe)) + + (let ((url (format lsp-pwsh-github-asset-url "PowerShell" + "PowerShellEditorServices" "PowerShellEditorServices.zip")) + (temp-file (make-temp-file "ext" nil ".zip"))) + (unless (f-exists? lsp-pwsh-log-path) + (mkdir lsp-pwsh-log-path 'create-parent)) + (unless (and (not update) (f-exists? lsp-pwsh-dir)) + ;; since we know it's installed, use powershell to download the file + ;; (and avoid url.el bugginess or additional libraries) + (when (f-exists? lsp-pwsh-dir) (delete-directory lsp-pwsh-dir 'recursive)) + (lsp-async-start-process + callback + error-callback + lsp-pwsh-exe "-noprofile" "-noninteractive" "-nologo" + "-ex" "bypass" "-command" + "Invoke-WebRequest" "-UseBasicParsing" "-uri" url "-outfile" temp-file ";" + "Expand-Archive" "-Path" temp-file + "-DestinationPath" (file-name-directory lsp-pwsh-dir))))) + +(lsp-consistency-check lsp-pwsh) + +(provide 'lsp-pwsh) +;;; lsp-pwsh.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-pyls.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-pyls.el new file mode 100644 index 0000000..20a4524 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-pyls.el @@ -0,0 +1,504 @@ +;;; lsp-pyls.el --- pyls configuration -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Ivan Yonchovski + +;; Author: Ivan Yonchovski <yyoncho@gmail.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; PYLS configuration + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-pyls nil + "LSP support for Python, using Palantir's Python Language Server." + :group 'lsp-mode + :link '(url-link "https://github.com/palantir/python-language-server") + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-clients-python-library-directories '("/usr/") + "List of directories which will be considered to be libraries." + :risky t + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(define-obsolete-variable-alias + 'lsp-clients-python-command + 'lsp-pyls-server-command + "6.1") + +(defcustom lsp-pyls-disable-warning nil + "Disable Palantir python-language-server deprecation warning" + :group 'lsp-pyls + :type 'boolean + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-pyls-server-command '("pyls") + "Command to start pyls." + :risky t + :group 'lsp-pyls + :type '(repeat string) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-configuration-sources ["pycodestyle"] + "List of configuration sources to use." + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-jedi-completion-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-jedi-completion-include-params t + "Auto-completes methods and classes with tabstops for each +parameter." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-jedi-definition-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-jedi-definition-follow-imports t + "The goto call will follow imports." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-jedi-definition-follow-builtin-imports t + "If follow_imports is True will decide if it follow builtin +imports." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-jedi-hover-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-jedi-references-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-jedi-signature-help-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-jedi-symbols-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-jedi-symbols-all-scopes t + "If True lists the names of all scopes instead of only the +module namespace." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-mccabe-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-mccabe-threshold 15 + "The minimum threshold that triggers warnings about cyclomatic +complexity." + :type 'number + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-preload-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-preload-modules nil + "List of modules to import on startup" + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pylint-enabled nil + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pylint-args [] + "Arguments, passed to pylint" + :risky t + :type 'lsp-string-vector + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pycodestyle-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pycodestyle-exclude nil + "Exclude files or directories which match these patterns." + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pycodestyle-filename nil + "When parsing directories, only check filenames matching these +patterns." + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pycodestyle-select nil + "Select errors and warnings" + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pycodestyle-ignore nil + "Ignore errors and warnings" + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pycodestyle-hang-closing nil + "Hang closing bracket instead of matching indentation of +opening bracket's line." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pycodestyle-max-line-length nil + "Set maximum allowed line length." + :type 'number + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pydocstyle-enabled nil + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pydocstyle-convention nil + "Choose the basic list of checked errors by specifying an +existing convention." + :type '(choice (:tag "pep257" "numpy")) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pydocstyle-add-ignore nil + "Ignore errors and warnings in addition to the specified +convention." + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pydocstyle-add-select nil + "Select errors and warnings in addition to the specified +convention." + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pydocstyle-ignore nil + "Ignore errors and warnings" + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pydocstyle-select nil + "Select errors and warnings" + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pydocstyle-match "(?!test_).*\\.py" + "Check only files that exactly match the given regular +expression; default is to match files that don't start with +'test_' but end with '.py'." + :type 'string + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pydocstyle-match-dir "[^\\.].*" + "Search only dirs that exactly match the given regular +expression; default is to match dirs which do not begin with a +dot." + :type 'string + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-pyflakes-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-rope-completion-enabled nil + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-autopep8-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pyls-plugins-yapf-enabled nil + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-rope-extension-modules nil + "Builtin and c-extension modules that are allowed to be +imported and inspected by rope." + :type 'string + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-rope-rope-folder nil + "The name of the folder in which rope stores project +configurations and data. Pass `nil` for not using such a folder +at all." + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-pyls-plugins-flake8-enabled nil + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pyls-plugins-flake8-exclude nil + "List of glob patterns to exclude from checks." + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pyls-plugins-flake8-filename nil + "List of glob patterns to include for checks." + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pyls-plugins-flake8-hang-closing nil + "Toggle whether pycodestyle should enforce matching the indentation of the +opening bracket’s line. When you specify this, it will prefer that you hang the +closing bracket rather than match the indentation." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pyls-plugins-flake8-ignore nil + "A list of codes to ignore." + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pyls-plugins-flake8-max-line-length nil + "Set the maximum length that any line (with some exceptions) may be. +Exceptions include lines that are either strings or comments which are +entirely URLs." + :type 'integer + :group 'lsp-pyls + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pyls-plugins-flake8-select nil + "Specify the list of error codes you wish Flake8 to report. Similarly to +`lsp-pyls-plugins-flake8-ignore'. You can specify a portion of an error code to +get all that start with that string. For example, you can use E, E4, E43, and +E431" + :type '(repeat string) + :group 'lsp-pyls + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-pyls-plugins-flake8-config nil + "A path to a config file that will be the only config file read and used. +This will cause Flake8 to ignore all other config files that exist. + +NOTE: other parameters as `lsp-pyls-plugins-flake8-max-line-length' take +precedence over parameters referenced in config." + :type 'string + :group 'lsp-pyls + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-pyls-plugins-jedi-use-pyenv-environment nil + "If enabled, pass the environment got by pyenv to jedi" + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-pyls-plugins-jedi-environment nil + "Specify the environment that jedi runs on where <environmeent>/bin/python +should be the python executable. This option will be prioritized over +`lsp-pyls-plugins-jedi-use-pyenv-environment'." + :type 'string + :group 'lsp-pyls + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-pyls-plugins-jedi-completion-fuzzy nil + "If enabled, uses fuzzy completion in jedi. Requires pyls >= 0.32.0 +Can hit performance, as well as lsp-mode implements its own fuzzy search on +completion items." + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "7.0")) + +(defcustom lsp-pyls-plugins-jedi-completion-include-class-objects t + "If enabled, adds class objects to completion in order to avoid snippet +with init args. + +Has no effect if `lsp-pyls-plugins-jedi-completion-include-params' is disabled. +Requires pyls >= 0.33.0" + :type 'boolean + :group 'lsp-pyls + :package-version '(lsp-mode . "7.0")) + +(defcustom lsp-pyls-rename-backend 'jedi + "Choose renaming backend. + +Jedi is preferred but only works for python >= 3.6 and pyls >= 0.32.0 +Beware that Jedi is lazy and doesn't scan the whole project. +So it will rename only references it can find." + :type '(choice (const :tag "jedi" jedi) + (const :tag "rope" rope)) + :group 'lsp-pyls + :package-version '(lsp-mode . "7.0")) + + +(defun lsp-pyls-get-pyenv-environment () + "Get the pyenv-managed environment for current workspace, where +<ENV>/bin/python is the corresponding Python executable" + (if lsp-pyls-plugins-jedi-environment + lsp-pyls-plugins-jedi-environment + (when lsp-pyls-plugins-jedi-use-pyenv-environment + (let ((pyenv-version (getenv "PYENV_VERSION")) + (root (lsp-seq-first (lsp-find-roots-for-workspace lsp--cur-workspace (lsp-session))))) + (when root + (setenv "PYENV_VERSION" nil) + (let* ((pyenv-command-path (executable-find "pyenv")) + (python-env (when pyenv-command-path + (f-parent + (f-parent + (shell-command-to-string + (format "PYENV_DIR='%s' %s which python" + root pyenv-command-path))))))) + (if python-env (lsp--info "Configure pyls with environment: %s" python-env) + (lsp--warn "Can't find the python environment for + %s even if + `lsp-pyls-plugins-jedi-use-pyenv-environment` is + enabled") root) + (setenv "PYENV_VERSION" pyenv-version) + python-env)))))) + +(lsp-register-custom-settings + '(("pyls.rope.ropeFolder" lsp-pyls-rope-rope-folder) + ("pyls.rope.extensionModules" lsp-pyls-rope-extension-modules) + ("pyls.plugins.rope_rename.enabled" (lambda () (eq lsp-pyls-rename-backend 'rope)) t) + ("pyls.plugins.autopep8.enabled" lsp-pyls-plugins-autopep8-enabled t) + ("pyls.plugins.yapf.enabled" lsp-pyls-plugins-yapf-enabled t) + ("pyls.plugins.rope_completion.enabled" lsp-pyls-plugins-rope-completion-enabled t) + ("pyls.plugins.pyflakes.enabled" lsp-pyls-plugins-pyflakes-enabled t) + ("pyls.plugins.pydocstyle.matchDir" lsp-pyls-plugins-pydocstyle-match-dir) + ("pyls.plugins.pydocstyle.match" lsp-pyls-plugins-pydocstyle-match) + ("pyls.plugins.pydocstyle.select" lsp-pyls-plugins-pydocstyle-select) + ("pyls.plugins.pydocstyle.ignore" lsp-pyls-plugins-pydocstyle-ignore) + ("pyls.plugins.pydocstyle.addSelect" lsp-pyls-plugins-pydocstyle-add-select) + ("pyls.plugins.pydocstyle.addIgnore" lsp-pyls-plugins-pydocstyle-add-ignore) + ("pyls.plugins.pydocstyle.convention" lsp-pyls-plugins-pydocstyle-convention) + ("pyls.plugins.pydocstyle.enabled" lsp-pyls-plugins-pydocstyle-enabled t) + ("pyls.plugins.pycodestyle.maxLineLength" lsp-pyls-plugins-pycodestyle-max-line-length) + ("pyls.plugins.pycodestyle.hangClosing" lsp-pyls-plugins-pycodestyle-hang-closing t) + ("pyls.plugins.pycodestyle.ignore" lsp-pyls-plugins-pycodestyle-ignore) + ("pyls.plugins.pycodestyle.select" lsp-pyls-plugins-pycodestyle-select) + ("pyls.plugins.pycodestyle.filename" lsp-pyls-plugins-pycodestyle-filename) + ("pyls.plugins.pycodestyle.exclude" lsp-pyls-plugins-pycodestyle-exclude) + ("pyls.plugins.pycodestyle.enabled" lsp-pyls-plugins-pycodestyle-enabled t) + ("pyls.plugins.pylint.enabled" lsp-pyls-plugins-pylint-enabled t) + ("pyls.plugins.pylint.args" lsp-pyls-plugins-pylint-args) + ("pyls.plugins.flake8.enabled" lsp-pyls-plugins-flake8-enabled) + ("pyls.plugins.flake8.exclude" lsp-pyls-plugins-flake8-exclude) + ("pyls.plugins.flake8.filename" lsp-pyls-plugins-flake8-filename) + ("pyls.plugins.flake8.hangClosing" lsp-pyls-plugins-flake8-hang-closing) + ("pyls.plugins.flake8.ignore" lsp-pyls-plugins-flake8-ignore) + ("pyls.plugins.flake8.maxLineLength" lsp-pyls-plugins-flake8-max-line-length) + ("pyls.plugins.flake8.select" lsp-pyls-plugins-flake8-select) + ("pyls.plugins.flake8.config" lsp-pyls-plugins-flake8-config) + ("pyls.plugins.preload.modules" lsp-pyls-plugins-preload-modules) + ("pyls.plugins.preload.enabled" lsp-pyls-plugins-preload-enabled t) + ("pyls.plugins.mccabe.threshold" lsp-pyls-plugins-mccabe-threshold) + ("pyls.plugins.mccabe.enabled" lsp-pyls-plugins-mccabe-enabled t) + ("pyls.plugins.jedi_symbols.all_scopes" lsp-pyls-plugins-jedi-symbols-all-scopes t) + ("pyls.plugins.jedi_symbols.enabled" lsp-pyls-plugins-jedi-symbols-enabled t) + ("pyls.plugins.jedi_signature_help.enabled" lsp-pyls-plugins-jedi-signature-help-enabled t) + ("pyls.plugins.jedi_references.enabled" lsp-pyls-plugins-jedi-references-enabled t) + ("pyls.plugins.jedi_hover.enabled" lsp-pyls-plugins-jedi-hover-enabled t) + ("pyls.plugins.jedi_definition.follow_builtin_imports" lsp-pyls-plugins-jedi-definition-follow-builtin-imports t) + ("pyls.plugins.jedi_definition.follow_imports" lsp-pyls-plugins-jedi-definition-follow-imports t) + ("pyls.plugins.jedi_definition.enabled" lsp-pyls-plugins-jedi-definition-enabled t) + ("pyls.plugins.jedi_completion.include_params" lsp-pyls-plugins-jedi-completion-include-params t) + ("pyls.plugins.jedi_completion.enabled" lsp-pyls-plugins-jedi-completion-enabled t) + ("pyls.plugins.jedi_completion.include_class_objects" lsp-pyls-plugins-jedi-completion-include-class-objects t) + ("pyls.plugins.jedi.environment" lsp-pyls-get-pyenv-environment) + ("pyls.plugins.jedi_completion.fuzzy" lsp-pyls-plugins-jedi-completion-fuzzy t) + ("pyls.plugins.jedi_rename.enabled" (lambda () (eq lsp-pyls-rename-backend 'jedi)) t) + ("pyls.configurationSources" lsp-pyls-configuration-sources))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (lambda () lsp-clients-python-command)) + :major-modes '(python-mode cython-mode) + :priority -2 + :server-id 'pyls + :library-folders-fn (lambda (_workspace) lsp-clients-python-library-directories) + :initialized-fn (lambda (workspace) + (unless lsp-pyls-disable-warning + (warn (concat "The palantir python-language-server (pyls) is unmaintained; " + "a maintained fork is the python-lsp-server (pylsp) project; " + "you can install it with pip via: pip install python-lsp-server"))) + (with-lsp-workspace workspace + (lsp--set-configuration (lsp-configuration-section "pyls")))))) + +(lsp-consistency-check lsp-pyls) + +(provide 'lsp-pyls) +;;; lsp-pyls.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-pylsp.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-pylsp.el new file mode 100644 index 0000000..a24862c --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-pylsp.el @@ -0,0 +1,434 @@ +;;; lsp-pylsp.el --- python-lsp-server support -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 Doug Davis + +;; Author: Doug Davis <ddavis@ddavis.io> +;; Keywords: language tools + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; pylsp configuration + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-pylsp nil + "LSP support for Python, using python-lsp's Python Language Server." + :group 'lsp-mode + :link '(url-link "https://github.com/python-lsp/python-lsp-server")) + +(defcustom lsp-clients-pylsp-library-directories '("/usr/") + "List of directories which will be considered to be libraries." + :risky t + :type '(repeat string) + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-server-command '("pylsp") + "Command to start pylsp." + :risky t + :group 'lsp-pylsp + :type '(repeat string)) + +(defcustom lsp-pylsp-configuration-sources ["flake8"] + "List of configuration sources to use." + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-jedi-completion-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-jedi-completion-include-params t + "Auto-completes methods and classes with tabstops for each +parameter." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-jedi-definition-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-jedi-definition-follow-imports t + "The goto call will follow imports." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-jedi-definition-follow-builtin-imports t + "If follow_imports is True will decide if it follow builtin +imports." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-jedi-hover-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-jedi-references-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-jedi-signature-help-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-jedi-symbols-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-jedi-symbols-all-scopes t + "If True lists the names of all scopes instead of only the +module namespace." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-mccabe-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-mccabe-threshold 15 + "The minimum threshold that triggers warnings about cyclomatic +complexity." + :type 'number + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-preload-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-preload-modules nil + "List of modules to import on startup" + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pylint-enabled nil + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pylint-args [] + "Arguments, passed to pylint" + :risky t + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pycodestyle-enabled nil + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pycodestyle-exclude nil + "Exclude files or directories which match these patterns." + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pycodestyle-filename nil + "When parsing directories, only check filenames matching these +patterns." + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pycodestyle-select nil + "Select errors and warnings" + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pycodestyle-ignore nil + "Ignore errors and warnings" + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pycodestyle-hang-closing nil + "Hang closing bracket instead of matching indentation of +opening bracket's line." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pycodestyle-max-line-length nil + "Set maximum allowed line length." + :type 'number + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pydocstyle-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pydocstyle-convention nil + "Choose the basic list of checked errors by specifying an +existing convention." + :type '(choice (:tag "pep257" "numpy")) + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pydocstyle-add-ignore nil + "Ignore errors and warnings in addition to the specified +convention." + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pydocstyle-add-select nil + "Select errors and warnings in addition to the specified +convention." + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pydocstyle-ignore nil + "Ignore errors and warnings" + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pydocstyle-select nil + "Select errors and warnings" + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pydocstyle-match "(?!test_).*\\.py" + "Check only files that exactly match the given regular +expression; default is to match files that don't start with +'test_' but end with '.py'." + :type 'string + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pydocstyle-match-dir "[^\\.].*" + "Search only dirs that exactly match the given regular +expression; default is to match dirs which do not begin with a +dot." + :type 'string + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-pyflakes-enabled nil + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-rope-completion-enabled nil + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-autopep8-enabled nil + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-yapf-enabled nil + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-rope-extension-modules nil + "Builtin and c-extension modules that are allowed to be +imported and inspected by rope." + :type 'string + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-rope-rope-folder nil + "The name of the folder in which rope stores project +configurations and data. Pass `nil` for not using such a folder +at all." + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-flake8-enabled t + "Enable or disable the plugin." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-flake8-exclude nil + "List of glob patterns to exclude from checks." + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-flake8-filename nil + "List of glob patterns to include for checks." + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-flake8-hang-closing nil + "Toggle whether pycodestyle should enforce matching the indentation of the +opening bracket’s line. When you specify this, it will prefer that you hang the +closing bracket rather than match the indentation." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-flake8-ignore nil + "A list of codes to ignore." + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-flake8-max-line-length nil + "Set the maximum length that any line (with some exceptions) may be. +Exceptions include lines that are either strings or comments which are +entirely URLs." + :type 'integer + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-flake8-select nil + "Specify the list of error codes you wish Flake8 to report. Similarly to +`lsp-pylsp-plugins-flake8-ignore'. You can specify a portion of an error code to +get all that start with that string. For example, you can use E, E4, E43, and +E431" + :type 'lsp-string-vector + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-flake8-config nil + "A path to a config file that will be the only config file read and used. +This will cause Flake8 to ignore all other config files that exist. + +NOTE: other parameters as `lsp-pylsp-plugins-flake8-max-line-length' take +precedence over parameters referenced in config." + :type 'string + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-jedi-use-pyenv-environment nil + "If enabled, pass the environment got by pyenv to jedi" + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-jedi-environment nil + "Specify the environment that jedi runs on where <environmeent>/bin/python +should be the python executable. This option will be prioritized over +`lsp-pylsp-plugins-jedi-use-pyenv-environment'." + :type 'string + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-jedi-completion-fuzzy nil + "If enabled, uses fuzzy completion in jedi. Requires pylsp >= 0.32.0 +Can hit performance, as well as lsp-mode implements its own fuzzy search on +completion items." + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-plugins-jedi-completion-include-class-objects t + "If enabled, adds class objects to completion in order to avoid snippet +with init args. + +Has no effect if `lsp-pylsp-plugins-jedi-completion-include-params' is disabled. +Requires pylsp >= 0.33.0" + :type 'boolean + :group 'lsp-pylsp) + +(defcustom lsp-pylsp-rename-backend 'jedi + "Choose renaming backend. + +Jedi is preferred but only works for python >= 3.6 and pylsp >= 0.32.0 +Beware that Jedi is lazy and doesn't scan the whole project. +So it will rename only references it can find." + :type '(choice (const :tag "jedi" jedi) + (const :tag "rope" rope)) + :group 'lsp-pylsp) + +(defun lsp-pylsp-get-pyenv-environment () + "Get the pyenv-managed environment for current workspace, where +<ENV>/bin/python is the corresponding Python executable" + (if lsp-pylsp-plugins-jedi-environment + lsp-pylsp-plugins-jedi-environment + (when lsp-pylsp-plugins-jedi-use-pyenv-environment + (let ((pyenv-version (getenv "PYENV_VERSION")) + (root (lsp-seq-first (lsp-find-roots-for-workspace lsp--cur-workspace (lsp-session))))) + (when root + (setenv "PYENV_VERSION" nil) + (let* ((pyenv-command-path (executable-find "pyenv")) + (python-env (when pyenv-command-path + (f-parent + (f-parent + (shell-command-to-string + (format "PYENV_DIR='%s' %s which python" + root pyenv-command-path))))))) + (if python-env (lsp--info "Configure pylsp with environment: %s" python-env) + (lsp--warn "Can't find the python environment for + %s even if + `lsp-pylsp-plugins-jedi-use-pyenv-environment` is + enabled") root) + (setenv "PYENV_VERSION" pyenv-version) + python-env)))))) + +(lsp-register-custom-settings + '(("pylsp.rope.ropeFolder" lsp-pylsp-rope-rope-folder) + ("pylsp.rope.extensionModules" lsp-pylsp-rope-extension-modules) + ("pylsp.plugins.rope_rename.enabled" (lambda () (eq lsp-pylsp-rename-backend 'rope)) t) + ("pylsp.plugins.autopep8.enabled" lsp-pylsp-plugins-autopep8-enabled t) + ("pylsp.plugins.yapf.enabled" lsp-pylsp-plugins-yapf-enabled t) + ("pylsp.plugins.rope_completion.enabled" lsp-pylsp-plugins-rope-completion-enabled t) + ("pylsp.plugins.pyflakes.enabled" lsp-pylsp-plugins-pyflakes-enabled t) + ("pylsp.plugins.pydocstyle.matchDir" lsp-pylsp-plugins-pydocstyle-match-dir) + ("pylsp.plugins.pydocstyle.match" lsp-pylsp-plugins-pydocstyle-match) + ("pylsp.plugins.pydocstyle.select" lsp-pylsp-plugins-pydocstyle-select) + ("pylsp.plugins.pydocstyle.ignore" lsp-pylsp-plugins-pydocstyle-ignore) + ("pylsp.plugins.pydocstyle.addSelect" lsp-pylsp-plugins-pydocstyle-add-select) + ("pylsp.plugins.pydocstyle.addIgnore" lsp-pylsp-plugins-pydocstyle-add-ignore) + ("pylsp.plugins.pydocstyle.convention" lsp-pylsp-plugins-pydocstyle-convention) + ("pylsp.plugins.pydocstyle.enabled" lsp-pylsp-plugins-pydocstyle-enabled t) + ("pylsp.plugins.pycodestyle.maxLineLength" lsp-pylsp-plugins-pycodestyle-max-line-length) + ("pylsp.plugins.pycodestyle.hangClosing" lsp-pylsp-plugins-pycodestyle-hang-closing t) + ("pylsp.plugins.pycodestyle.ignore" lsp-pylsp-plugins-pycodestyle-ignore) + ("pylsp.plugins.pycodestyle.select" lsp-pylsp-plugins-pycodestyle-select) + ("pylsp.plugins.pycodestyle.filename" lsp-pylsp-plugins-pycodestyle-filename) + ("pylsp.plugins.pycodestyle.exclude" lsp-pylsp-plugins-pycodestyle-exclude) + ("pylsp.plugins.pycodestyle.enabled" lsp-pylsp-plugins-pycodestyle-enabled t) + ("pylsp.plugins.pylint.enabled" lsp-pylsp-plugins-pylint-enabled t) + ("pylsp.plugins.pylint.args" lsp-pylsp-plugins-pylint-args) + ("pylsp.plugins.flake8.enabled" lsp-pylsp-plugins-flake8-enabled) + ("pylsp.plugins.flake8.exclude" lsp-pylsp-plugins-flake8-exclude) + ("pylsp.plugins.flake8.filename" lsp-pylsp-plugins-flake8-filename) + ("pylsp.plugins.flake8.hangClosing" lsp-pylsp-plugins-flake8-hang-closing) + ("pylsp.plugins.flake8.ignore" lsp-pylsp-plugins-flake8-ignore) + ("pylsp.plugins.flake8.maxLineLength" lsp-pylsp-plugins-flake8-max-line-length) + ("pylsp.plugins.flake8.select" lsp-pylsp-plugins-flake8-select) + ("pylsp.plugins.flake8.config" lsp-pylsp-plugins-flake8-config) + ("pylsp.plugins.preload.modules" lsp-pylsp-plugins-preload-modules) + ("pylsp.plugins.preload.enabled" lsp-pylsp-plugins-preload-enabled t) + ("pylsp.plugins.mccabe.threshold" lsp-pylsp-plugins-mccabe-threshold) + ("pylsp.plugins.mccabe.enabled" lsp-pylsp-plugins-mccabe-enabled t) + ("pylsp.plugins.jedi_symbols.all_scopes" lsp-pylsp-plugins-jedi-symbols-all-scopes t) + ("pylsp.plugins.jedi_symbols.enabled" lsp-pylsp-plugins-jedi-symbols-enabled t) + ("pylsp.plugins.jedi_signature_help.enabled" lsp-pylsp-plugins-jedi-signature-help-enabled t) + ("pylsp.plugins.jedi_references.enabled" lsp-pylsp-plugins-jedi-references-enabled t) + ("pylsp.plugins.jedi_hover.enabled" lsp-pylsp-plugins-jedi-hover-enabled t) + ("pylsp.plugins.jedi_definition.follow_builtin_imports" lsp-pylsp-plugins-jedi-definition-follow-builtin-imports t) + ("pylsp.plugins.jedi_definition.follow_imports" lsp-pylsp-plugins-jedi-definition-follow-imports t) + ("pylsp.plugins.jedi_definition.enabled" lsp-pylsp-plugins-jedi-definition-enabled t) + ("pylsp.plugins.jedi_completion.include_params" lsp-pylsp-plugins-jedi-completion-include-params t) + ("pylsp.plugins.jedi_completion.enabled" lsp-pylsp-plugins-jedi-completion-enabled t) + ("pylsp.plugins.jedi_completion.include_class_objects" lsp-pylsp-plugins-jedi-completion-include-class-objects t) + ("pylsp.plugins.jedi.environment" lsp-pylsp-get-pyenv-environment) + ("pylsp.plugins.jedi_completion.fuzzy" lsp-pylsp-plugins-jedi-completion-fuzzy t) + ("pylsp.plugins.jedi_rename.enabled" (lambda () (eq lsp-pylsp-rename-backend 'jedi)) t) + ("pylsp.configurationSources" lsp-pylsp-configuration-sources))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (lambda () lsp-pylsp-server-command)) + :major-modes '(python-mode cython-mode) + :priority -1 + :server-id 'pylsp + :library-folders-fn (lambda (_workspace) lsp-clients-pylsp-library-directories) + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration (lsp-configuration-section "pylsp")))))) + +(lsp-consistency-check lsp-pylsp) + +(provide 'lsp-pylsp) +;;; lsp-pylsp.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-r.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-r.el new file mode 100644 index 0000000..da54bc3 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-r.el @@ -0,0 +1,49 @@ +;;; lsp-r.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, r + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the R Programming Language. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-r nil + "LSP support for R." + :group 'lsp-mode + :link '(url-link "https://github.com/REditorSupport/languageserver")) + +(defcustom lsp-clients-r-server-command '("R" "--slave" "-e" "languageserver::run()") + "Command to start the R language server." + :group 'lsp-r + :risky t + :type '(repeat string)) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection lsp-clients-r-server-command) + :major-modes '(ess-r-mode) + :server-id 'lsp-r)) + + +(lsp-consistency-check lsp-r) + +(provide 'lsp-r) +;;; lsp-r.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-racket.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-racket.el new file mode 100644 index 0000000..6ca7b5a --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-racket.el @@ -0,0 +1,77 @@ +;;; lsp-racket.el --- lsp-mode racket integration -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 lsp-mode maintainers + +;; Author: lsp-mode maintainers +;; Keywords: languages + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Client for the Racket language server. + +;;; Code: + +(require 'ht) +(require 'lsp-mode) + + +;; racket-langserver + +(defgroup lsp-racket-langserver nil + "LSP support for Racket, using racket-langserver" + :group 'lsp-mode + :link '(url-link "https://github.com/jeapostrophe/racket-langserver")) + +(defcustom lsp-racket-langserver-command '("racket" "--lib" "racket-langserver") + "Command to start the server." + :type 'string + :package-version '(lsp-mode . "7.1")) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection (lambda () lsp-racket-langserver-command)) + :major-modes '(racket-mode) + :priority 1 + :server-id 'racket-langserver)) + + +;; Theia + +(defgroup lsp-racket-language-server nil + "LSP support for Racket, using racket-language-server." + :group 'lsp-mode + :link '(url-link "https://github.com/theia-ide/racket-language-server")) + +(defcustom lsp-racket-language-server-path "racket-language-server" + "Executable path for the server." + :type 'string + :package-version '(lsp-mode . "7.1")) + +(defun lsp-racket-language-server-colorize-handler (&rest _args) + "Handler for the colorize notification." + ;; TODO: + nil) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection (lambda () lsp-racket-language-server-path)) + :major-modes '(racket-mode) + :priority -1 + :notification-handlers (ht ("racket/colorize" #'lsp-racket-language-server-colorize-handler)) + :server-id 'racket-language-server)) + +(lsp-consistency-check lsp-racket) + +(provide 'lsp-racket) +;;; lsp-racket.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-rf.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-rf.el new file mode 100644 index 0000000..eee0a16 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-rf.el @@ -0,0 +1,147 @@ +;;; lsp-rf.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, rf, robot + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the Robot Framework. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-rf nil + "Settings for Robot Framework Language Server." + :group 'lsp-mode + :link '(url-link "https://github.com/tomi/vscode-rf-language-server")) + +(defcustom lsp-rf-language-server-start-command '("~/.nvm/versions/node/v9.11.2/bin/node" "~/.vscode/extensions/tomiturtiainen.rf-intellisense-2.8.0/server/server.js") + "Path to the server.js file of the rf-intellisense server. +Accepts a list of strings (path/to/interpreter path/to/server.js)" + :type 'list + :group 'lsp-rf) + +(defcustom lsp-rf-language-server-include-paths [] + "An array of files that should be included by the parser. +Glob patterns as strings are accepted (eg. *.robot between double quotes)" + :type 'lsp-string-vector + :group 'lsp-rf) + +(defcustom lsp-rf-language-server-exclude-paths [] + "An array of files that should be ignored by the parser. +Glob patterns as strings are accepted (eg. *bad.robot between double quotes)" + :type 'lsp-string-vector + :group 'lsp-rf) + +(defcustom lsp-rf-language-server-dir "~/.vscode/extensions/tomiturtiainen.rf-intellisense-2.8.0/server/library-docs/" + "Libraries directory for libraries in `lsp-rf-language-server-libraries'" + :type 'string + :group 'lsp-rf) + +(defcustom lsp-rf-language-server-libraries ["BuiltIn-3.1.1" "Collections-3.0.4"] + "Libraries whose keywords are suggested with `auto-complete'." + :type '(repeat string) + ;; :type 'lsp-string-vector + :group 'lsp-rf) + +(defcustom lsp-rf-language-server-log-level "debug" + "What language server log messages are printed." + :type 'string + ;; :type '(choice (:tag "off" "errors" "info" "debug")) + :group 'lsp-rf) + +(defcustom lsp-rf-language-server-trace-server "verbose" + "Traces the communication between VSCode and the rfLanguageServer service." + :type 'string + ;; :type '(choice (:tag "off" "messages" "verbose")) + :group 'lsp-rf) + +(defun parse-rf-language-server-library-dirs (dirs) + (vconcat (mapcar + (lambda (x) + (concat + (expand-file-name + lsp-rf-language-server-dir) + x + ".json")) + dirs))) + +(defun expand-start-command () + (mapcar 'expand-file-name lsp-rf-language-server-start-command)) + +(defun parse-rf-language-server-globs-to-regex (vector) + "Convert a VECTOR of globs to a regex." + (--> (mapcan #'lsp-glob-to-regexps vector) + (s-join "\\|" it) + (concat "\\(?:" it "\\)"))) + +(defun parse-rf-language-server-include-path-regex (vector) + "Creates regexp to select files from workspace directory." + (let ((globs (if (eq vector []) + ["*.robot" "*.resource"] + vector))) + (parse-rf-language-server-globs-to-regex globs))) + +(defun parse-rf-language-server-exclude-paths (seq) + "Creates regexp to select files from workspace directory." + (if (eq lsp-rf-language-server-exclude-paths []) + seq + (cl-delete-if (lambda (x) (string-match-p + (parse-rf-language-server-globs-to-regex + lsp-rf-language-server-exclude-paths) + x)) + seq))) + +(lsp-register-custom-settings + '( + ("rfLanguageServer.trace.server" lsp-rf-language-server-trace-server) + ("rfLanguageServer.logLevel" lsp-rf-language-server-log-level) + ("rfLanguageServer.libraries" lsp-rf-language-server-libraries) + ("rfLanguageServer.excludePaths" lsp-rf-language-server-exclude-paths) + ("rfLanguageServer.includePaths" lsp-rf-language-server-include-paths))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (expand-start-command)) + :major-modes '(robot-mode) + :server-id 'rf-intellisense + ;; :library-folders-fn (lambda (_workspace) + ;; lsp-rf-language-server-libraries) + :library-folders-fn (lambda (_workspace) + (parse-rf-language-server-library-dirs + lsp-rf-language-server-libraries)) + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration + (lsp-configuration-section "rfLanguageServer")) + (lsp-request "buildFromFiles" + (list :files + (vconcat + (parse-rf-language-server-exclude-paths + (directory-files-recursively + (lsp--workspace-root workspace) + (parse-rf-language-server-include-path-regex + lsp-rf-language-server-include-paths)))))))))) + + + +(lsp-consistency-check lsp-rf) + +(provide 'lsp-rf) +;;; lsp-rf.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-rust.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-rust.el new file mode 100644 index 0000000..a85aba5 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-rust.el @@ -0,0 +1,1100 @@ +;;; lsp-rust.el --- Rust Client settings -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Ivan Yonchovski + +;; Author: Ivan Yonchovski <yyoncho@gmail.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; lsp-rust client + +;;; Code: + +(require 'lsp-mode) +(require 'ht) +(require 'dash) + +(defgroup lsp-rust nil + "LSP support for Rust, using Rust Language Server or rust-analyzer." + :group 'lsp-mode + :link '(url-link "https://github.com/rust-lang/rls") + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-server 'rust-analyzer + "Choose LSP server." + :type '(choice (const :tag "rls" rls) + (const :tag "rust-analyzer" rust-analyzer)) + :group 'lsp-rust + :package-version '(lsp-mode . "6.2")) + +;; RLS + +(defcustom lsp-rust-rls-server-command '("rls") + "Command to start RLS." + :type '(repeat string) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-library-directories '("~/.cargo/registry/src" "~/.rustup/toolchains") + "List of directories which will be considered to be libraries." + :risky t + :type '(repeat string) + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-sysroot nil + "If non-nil, use the given path as the sysroot for all rustc invocations +instead of trying to detect the sysroot automatically." + :type '(choice + (const :tag "None" nil) + (string :tag "Sysroot")) + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-target nil + "If non-nil, use the given target triple for all rustc invocations." + :type '(choice + (const :tag "None" nil) + (string :tag "Target")) + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-rustflags nil + "Flags added to RUSTFLAGS." + :type '(choice + (const :tag "None" nil) + (string :tag "Flags")) + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-clear-env-rust-log t + "Clear the RUST_LOG environment variable before running rustc or cargo." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-build-lib nil + "If non-nil, checks the project as if you passed the `--lib' argument to +cargo. + +Mutually exclusive with, and preferred over, `lsp-rust-build-bin'. (Unstable)" + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-build-bin nil + "If non-nil, checks the project as if you passed `-- bin <build_bin>' +argument to cargo. + +Mutually exclusive with `lsp-rust-build-lib'. (Unstable)" + :type '(choice + (const :tag "None" nil) + (string :tag "Binary")) + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-cfg-test nil + "If non-nil, checks the project as if you were running `cargo test' rather +than cargo build. + +I.e., compiles (but does not run) test code." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-unstable-features nil + "Enable unstable features." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-wait-to-build nil + "Time in milliseconds between receiving a change notification +and starting build. If not specified, automatically inferred by +the latest build duration." + :type '(choice + (const :tag "Auto" nil) + (number :tag "Time")) + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-show-warnings t + "Show warnings." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-crate-blacklist [ + "cocoa" + "gleam" + "glium" + "idna" + "libc" + "openssl" + "rustc_serialize" + "serde" + "serde_json" + "typenum" + "unicode_normalization" + "unicode_segmentation" + "winapi" + ] + "A list of Cargo crates to blacklist." + :type 'lsp-string-vector + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-build-on-save nil + "Only index the project when a file is saved and not on change." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-features [] + "List of Cargo features to enable." + :type 'lsp-string-vector + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-all-features nil + "Enable all Cargo features." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-analyzer-cargo-target nil + "Compilation target (target triple)." + :type 'string + :group 'lsp-rust + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-rust-no-default-features nil + "Do not enable default Cargo features." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-racer-completion t + "Enables code completion using racer." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-clippy-preference "opt-in" + "Controls eagerness of clippy diagnostics when available. +Valid values are (case-insensitive): + - \"off\": Disable clippy lints. + - \"opt-in\": Clippy lints are shown when crates specify `#![warn(clippy)]'. + - \"on\": Clippy lints enabled for all crates in workspace. + +You need to install clippy via rustup if you haven't already." + :type '(choice + (const "on") + (const "opt-in") + (const "off")) + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-jobs nil + "Number of Cargo jobs to be run in parallel." + :type '(choice + (const :tag "Auto" nil) + (number :tag "Jobs")) + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-all-targets t + "Checks the project as if you were running cargo check --all-targets. +I.e., check all targets and integration tests too." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-target-dir nil + "When specified, it places the generated analysis files at the +specified target directory. By default it is placed target/rls +directory." + :type '(choice + (const :tag "Default" nil) + (string :tag "Directory")) + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-rustfmt-path nil + "When specified, RLS will use the Rustfmt pointed at the path +instead of the bundled one" + :type '(choice + (const :tag "Bundled" nil) + (string :tag "Path")) + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-build-command nil + "EXPERIMENTAL (requires `rust.unstable_features') +If set, executes a given program responsible for rebuilding save-analysis to be +loaded by the RLS. The program given should output a list of resulting .json +files on stdout. + +Implies `rust.build_on_save': true." + :type '(choice + (const :tag "None" nil) + (string :tag "Command")) + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-full-docs nil + "Instructs cargo to enable full documentation extraction during +save-analysis while building the crate." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-rust-show-hover-context t + "Show additional context in hover tooltips when available. This +is often the type local variable declaration." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.1")) + +(lsp-register-custom-settings + '(("rust.show_hover_context" lsp-rust-show-hover-context t) + ("rust.full_docs" lsp-rust-full-docs t) + ("rust.build_command" lsp-rust-build-command) + ("rust.rustfmt_path" lsp-rust-rustfmt-path) + ("rust.target_dir" lsp-rust-target-dir) + ("rust.all_targets" lsp-rust-all-targets t) + ("rust.jobs" lsp-rust-jobs) + ("rust.clippy_preference" lsp-rust-clippy-preference) + ("rust.racer_completion" lsp-rust-racer-completion t) + ("rust.no_default_features" lsp-rust-no-default-features t) + ("rust.all_features" lsp-rust-all-features t) + ("rust.features" lsp-rust-features) + ("rust.build_on_save" lsp-rust-build-on-save t) + ("rust.crate_blacklist" lsp-rust-crate-blacklist) + ("rust.show_warnings" lsp-rust-show-warnings t) + ("rust.wait_to_build" lsp-rust-wait-to-build) + ("rust.unstable_features" lsp-rust-unstable-features t) + ("rust.cfg_test" lsp-rust-cfg-test t) + ("rust.build_bin" lsp-rust-build-bin) + ("rust.build_lib" lsp-rust-build-lib t) + ("rust.clear_env_rust_log" lsp-rust-clear-env-rust-log t) + ("rust.rustflags" lsp-rust-rustflags) + ("rust.target" lsp-rust-target) + ("rust.sysroot" lsp-rust-sysroot))) + +(defun lsp-clients--rust-window-progress (workspace params) + "Progress report handling. +PARAMS progress report notification data." + (-let [(&v1:ProgressParams :done? :message? :title) params] + (if (or done? (s-blank-str? message?)) + (lsp-workspace-status nil workspace) + (lsp-workspace-status (format "%s - %s" title (or message? "")) workspace)))) + +(lsp-defun lsp-rust--rls-run ((&Command :arguments? params)) + (-let* (((&rls:Cmd :env :binary :args :cwd) (lsp-seq-first params)) + (default-directory (or cwd (lsp-workspace-root) default-directory) )) + (compile + (format "%s %s %s" + (s-join " " (ht-amap (format "%s=%s" key value) env)) + binary + (s-join " " args))))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection (lambda () lsp-rust-rls-server-command)) + :major-modes '(rust-mode rustic-mode) + :priority (if (eq lsp-rust-server 'rls) 1 -1) + :initialization-options '((omitInitBuild . t) + (cmdRun . t)) + :notification-handlers (ht ("window/progress" 'lsp-clients--rust-window-progress)) + :action-handlers (ht ("rls.run" 'lsp-rust--rls-run)) + :library-folders-fn (lambda (_workspace) lsp-rust-library-directories) + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration + (lsp-configuration-section "rust")))) + :server-id 'rls)) + + +;; rust-analyzer +(defcustom lsp-rust-analyzer-server-command '("rust-analyzer") + "Command to start rust-analyzer." + :type '(repeat string) + :group 'lsp-rust + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-rust-analyzer-server-display-inlay-hints nil + "Show inlay hints." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-rust-analyzer-max-inlay-hint-length nil + "Max inlay hint length." + :type 'integer + :group 'lsp-rust + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-display-parameter-hints nil + "Whether to show function parameter name inlay hints at the call site." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-display-chaining-hints nil + "Whether to show inlay type hints for method chains." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-lru-capacity nil + "Number of syntax trees rust-analyzer keeps in memory." + :type 'integer + :group 'lsp-rust + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-cargo-watch-enable t + "Enable Cargo watch." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-cargo-watch-command "check" + "Cargo watch command." + :type 'string + :group 'lsp-rust + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-cargo-watch-args [] + "Cargo watch args." + :type 'lsp-string-vector + :group 'lsp-rust + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-cargo-override-command [] + "Advanced option, fully override the command rust-analyzer uses for checking. +The command should include `--message=format=json` or similar option." + :type 'lsp-string-vector + :group 'lsp-rust + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-cargo-all-targets t + "Cargo watch all targets or not." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-use-client-watching t + "Use client watching" + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-exclude-globs [] + "Exclude globs" + :type 'lsp-string-vector + :group 'lsp-rust + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-exclude-dirs [] + "These directories will be ignored by rust-analyzer." + :type 'lsp-string-vector + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-rust-analyzer-macro-expansion-method 'lsp-rust-analyzer-macro-expansion-default + "Use a different function if you want formatted macro expansion results and +syntax highlighting." + :type 'function + :group 'lsp-rust + :package-version '(lsp-mode . "6.2.2")) + +(defcustom lsp-rust-analyzer-diagnostics-enable t + "Whether to show native rust-analyzer diagnostics." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-diagnostics-enable-experimental t + "Whether to show native rust-analyzer diagnostics that are still experimental +\(might have more false positives than usual)." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-rust-analyzer-diagnostics-disabled [] + "List of native rust-analyzer diagnostics to disable." + :type 'lsp-string-vector + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-rust-analyzer-diagnostics-warnings-as-hint [] + "List of warnings that should be displayed with hint severity." + :type 'lsp-string-vector + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-rust-analyzer-diagnostics-warnings-as-info [] + "List of warnings that should be displayed with info severity." + :type 'lsp-string-vector + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(define-obsolete-variable-alias + 'lsp-rust-analyzer-cargo-load-out-dirs-from-check + 'lsp-rust-analyzer-cargo-run-build-scripts + "7.1.0") + +(defcustom lsp-rust-analyzer-cargo-run-build-scripts t + "Whether to run build scripts (`build.rs`) for more precise code analysis." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-rust-analyzer-rustfmt-extra-args [] + "Additional arguments to rustfmt." + :type 'lsp-string-vector + :group 'lsp-rust + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-rustfmt-override-command [] + "Advanced option, fully override the command rust-analyzer uses +for formatting." + :type 'lsp-string-vector + :group 'lsp-rust + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-completion-add-call-parenthesis t + "Whether to add parenthesis when completing functions." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-completion-add-call-argument-snippets t + "Whether to add argument snippets when completing functions." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-completion-postfix-enable t + "Whether to show postfix snippets like `dbg`, `if`, `not`, etc." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-call-info-full t + "Whether to show function name and docs in parameter hints." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-proc-macro-enable nil + "Enable Proc macro support. +Implies `lsp-rust-analyzer-cargo-run-build-scripts'" + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "6.3.2")) + +(defcustom lsp-rust-analyzer-import-merge-behaviour "full" + "The strategy to use when inserting new imports or merging imports. +Valid values are: + - \"none\": No merging + - \"full\": Merge all layers of the import trees + - \"last\": Only merge the last layer of the import trees" + :type '(choice + (const "none") + (const "full") + (const "last")) + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-rust-analyzer-import-prefix "plain" + "The path structure for newly inserted paths to use. +Valid values are: + - \"plain\": Insert import paths relative to the current module, using up to +one `super' prefix if the parent module contains the requested item. + - \"by_self\": Prefix all import paths with `self' if they don't begin with +`self', `super', `crate' or a crate name. + - \"by_crate\": Force import paths to be absolute by always starting +them with `crate' or the crate name they refer to." + :type '(choice + (const "plain") + (const "by_self") + (const "by_crate")) + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-rust-analyzer-import-granularity "crate" + "How imports should be grouped into use statements." + :type '(choice + (const "crate" :doc "Merge imports from the same crate into a single use statement. This kind of nesting is only supported in Rust versions later than 1.24.") + (const "module" :doc "Merge imports from the same module into a single use statement.") + (const "item" :doc "Don’t merge imports at all, creating one import per item.") + (const "preserve" :doc "Do not change the granularity of any imports. For auto-import this has the same effect as `\"item\"'")) + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-rust-analyzer-cargo-auto-reload t + "Automatically refresh project info via `cargo metadata' on `Cargo.toml' changes." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-rust-analyzer-use-rustc-wrapper-for-build-scripts t + "Use `RUSTC_WRAPPER=rust-analyzer' when running build scripts to avoid +compiling unnecessary things." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-rust-analyzer-completion-auto-import-enable t + "Toggles the additional completions that automatically add imports when +completed. `lsp-completion-enable-additional-text-edit' must be non-nil + for this feature to be fully enabled." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-rust-analyzer-completion-auto-self-enable t + "Toggles the additional completions that automatically show method calls +and field accesses with self prefixed to them when inside a method." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-rust-analyzer-import-enforce-granularity nil + "Whether to enforce the import granularity setting for all files. + If set to nil rust-analyzer will try to keep import styles consistent per file." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-rust-analyzer-import-group t + "Group inserted imports by the following order: +https://rust-analyzer.github.io/manual.html#auto-import. + Groups are separated by newlines." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-rust-analyzer-highlighting-strings t + "Use semantic tokens for strings." + :type 'boolean + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-rust-analyzer-rustc-source nil + "Path to the Cargo.toml of the rust compiler workspace." + :type 'string + :group 'lsp-rust + :package-version '(lsp-mode . "7.1.0")) + +(defun lsp-rust-analyzer--make-init-options () + "Init options for rust-analyzer" + `(:diagnostics (:enable ,(lsp-json-bool lsp-rust-analyzer-diagnostics-enable) + :enableExperimental ,(lsp-json-bool lsp-rust-analyzer-diagnostics-enable-experimental) + :disabled ,lsp-rust-analyzer-diagnostics-disabled + :warningsAsHint ,lsp-rust-analyzer-diagnostics-warnings-as-hint + :warningsAsInfo ,lsp-rust-analyzer-diagnostics-warnings-as-info) + :assist (:importMergeBehaviour ,lsp-rust-analyzer-import-merge-behaviour + :importPrefix ,lsp-rust-analyzer-import-prefix + :importGranularity ,lsp-rust-analyzer-import-granularity + :importEnforceGranularity ,(lsp-json-bool lsp-rust-analyzer-import-enforce-granularity) + :importGroup ,(lsp-json-bool lsp-rust-analyzer-import-group)) + :lruCapacity ,lsp-rust-analyzer-lru-capacity + :checkOnSave (:enable ,(lsp-json-bool lsp-rust-analyzer-cargo-watch-enable) + :command ,lsp-rust-analyzer-cargo-watch-command + :extraArgs ,lsp-rust-analyzer-cargo-watch-args + :allTargets ,(lsp-json-bool lsp-rust-analyzer-cargo-all-targets) + :overrideCommand ,lsp-rust-analyzer-cargo-override-command) + :files (:exclude ,lsp-rust-analyzer-exclude-globs + :watcher ,(lsp-json-bool (if lsp-rust-analyzer-use-client-watching + "client" + "notify")) + :excludeDirs ,lsp-rust-analyzer-exclude-dirs) + :cargo (:allFeatures ,(lsp-json-bool lsp-rust-all-features) + :noDefaultFeatures ,(lsp-json-bool lsp-rust-no-default-features) + :features ,lsp-rust-features + :target ,lsp-rust-analyzer-cargo-target + :runBuildScripts ,(lsp-json-bool lsp-rust-analyzer-cargo-run-build-scripts) + ; Obsolete, but used by old Rust-Analyzer versions + :loadOutDirsFromCheck ,(lsp-json-bool lsp-rust-analyzer-cargo-run-build-scripts) + :autoreload ,(lsp-json-bool lsp-rust-analyzer-cargo-auto-reload) + :useRustcWrapperForBuildScripts ,(lsp-json-bool lsp-rust-analyzer-use-rustc-wrapper-for-build-scripts)) + :rustfmt (:extraArgs ,lsp-rust-analyzer-rustfmt-extra-args + :overrideCommand ,lsp-rust-analyzer-rustfmt-override-command) + :inlayHints (:typeHints ,(lsp-json-bool lsp-rust-analyzer-server-display-inlay-hints) + :chainingHints ,(lsp-json-bool lsp-rust-analyzer-display-chaining-hints) + :parameterHints ,(lsp-json-bool lsp-rust-analyzer-display-parameter-hints) + :maxLength ,lsp-rust-analyzer-max-inlay-hint-length) + :completion (:addCallParenthesis ,(lsp-json-bool lsp-rust-analyzer-completion-add-call-parenthesis) + :addCallArgumentSnippets ,(lsp-json-bool lsp-rust-analyzer-completion-add-call-argument-snippets) + :postfix (:enable ,(lsp-json-bool lsp-rust-analyzer-completion-postfix-enable)) + :autoimport (:enable ,(lsp-json-bool lsp-rust-analyzer-completion-auto-import-enable)) + :autoself (:enable ,(lsp-json-bool lsp-rust-analyzer-completion-auto-self-enable))) + :callInfo (:full ,(lsp-json-bool lsp-rust-analyzer-call-info-full)) + :procMacro (:enable ,(lsp-json-bool lsp-rust-analyzer-proc-macro-enable)) + :rustcSource ,lsp-rust-analyzer-rustc-source + :highlighting (:strings ,(lsp-json-bool lsp-rust-analyzer-highlighting-strings)))) + +(defconst lsp-rust-notification-handlers + '(("rust-analyzer/publishDecorations" . (lambda (_w _p))))) + +(defconst lsp-rust-action-handlers + '()) + +(define-derived-mode lsp-rust-analyzer-syntax-tree-mode special-mode "Rust-Analyzer-Syntax-Tree" + "Mode for the rust-analyzer syntax tree buffer.") + +(defun lsp-rust-analyzer-syntax-tree () + "Display syntax tree for current buffer." + (interactive) + (-let* ((root (lsp-workspace-root default-directory)) + (params (lsp-make-rust-analyzer-syntax-tree-params + :text-document (lsp--text-document-identifier) + :range? (if (use-region-p) + (lsp--region-to-range (region-beginning) (region-end)) + (lsp--region-to-range (point-min) (point-max))))) + (results (lsp-send-request (lsp-make-request + "rust-analyzer/syntaxTree" + params)))) + (let ((buf (get-buffer-create (format "*rust-analyzer syntax tree %s*" root))) + (inhibit-read-only t)) + (with-current-buffer buf + (lsp-rust-analyzer-syntax-tree-mode) + (erase-buffer) + (insert results) + (goto-char (point-min))) + (pop-to-buffer buf)))) + +(define-derived-mode lsp-rust-analyzer-status-mode special-mode "Rust-Analyzer-Status" + "Mode for the rust-analyzer status buffer.") + +(defun lsp-rust-analyzer-status () + "Displays status information for rust-analyzer." + (interactive) + (-let* ((root (lsp-workspace-root default-directory)) + (params (lsp-make-rust-analyzer-analyzer-status-params + :text-document (lsp--text-document-identifier))) + (results (lsp-send-request (lsp-make-request + "rust-analyzer/analyzerStatus" + params)))) + (let ((buf (get-buffer-create (format "*rust-analyzer status %s*" root))) + (inhibit-read-only t)) + (with-current-buffer buf + (lsp-rust-analyzer-status-mode) + (erase-buffer) + (insert results) + (pop-to-buffer buf))))) + +(defun lsp-rust-analyzer-join-lines () + "Join selected lines into one, smartly fixing up whitespace and trailing commas." + (interactive) + (let* ((params (lsp-make-rust-analyzer-join-lines-params + :text-document (lsp--text-document-identifier) + :ranges (vector (if (use-region-p) + (lsp--region-to-range (region-beginning) (region-end)) + (lsp--region-to-range (point) (point)))))) + (result (lsp-send-request (lsp-make-request "experimental/joinLines" params)))) + (lsp--apply-text-edits result 'code-action))) + +(defun lsp-rust-analyzer-reload-workspace () + "Reload workspace, picking up changes from Cargo.toml" + (interactive) + (lsp--cur-workspace-check) + (lsp-send-request (lsp-make-request "rust-analyzer/reloadWorkspace"))) + +(defcustom lsp-rust-analyzer-download-url + (format "https://github.com/rust-analyzer/rust-analyzer/releases/latest/download/%s" + (pcase system-type + ('gnu/linux "rust-analyzer-x86_64-unknown-linux-gnu.gz") + ('darwin "rust-analyzer-x86_64-apple-darwin.gz") + ('windows-nt "rust-analyzer-x86_64-pc-windows-msvc.gz"))) + "Automatic download url for Rust Analyzer" + :type 'string + :group 'lsp-rust + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-rust-analyzer-store-path (f-join lsp-server-install-dir + "rust" + (if (eq system-type 'windows-nt) + "rust-analyzer.exe" + "rust-analyzer")) + "The path to the file in which `rust-analyzer' will be stored." + :type 'file + :group 'lsp-rust + :package-version '(lsp-mode . "7.1")) + +(lsp-dependency + 'rust-analyzer + `(:download :url lsp-rust-analyzer-download-url + :decompress :gzip + :store-path lsp-rust-analyzer-store-path + :set-executable? t) + '(:system "rust-analyzer")) + +(lsp-defun lsp-rust--analyzer-run-single ((&Command :arguments?)) + (lsp-rust-analyzer-run (lsp-seq-first arguments?))) + +(lsp-defun lsp-rust--analyzer-show-references + ((&Command :title :arguments? [_uri _filepos references])) + (lsp-show-xrefs (lsp--locations-to-xref-items references) nil + (s-contains-p "reference" title))) + +(declare-function dap-debug "ext:dap-mode" (template) t) + +(lsp-defun lsp-rust--analyzer-debug-lens ((&Command :arguments? [args])) + (lsp-rust-analyzer-debug args)) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection + (lambda () + `(,(or (executable-find + (cl-first lsp-rust-analyzer-server-command)) + (lsp-package-path 'rust-analyzer) + "rust-analyzer") + ,@(cl-rest lsp-rust-analyzer-server-command)))) + :major-modes '(rust-mode rustic-mode) + :priority (if (eq lsp-rust-server 'rust-analyzer) 1 -1) + :initialization-options 'lsp-rust-analyzer--make-init-options + :notification-handlers (ht<-alist lsp-rust-notification-handlers) + :action-handlers (ht ("rust-analyzer.runSingle" #'lsp-rust--analyzer-run-single) + ("rust-analyzer.debugSingle" #'lsp-rust--analyzer-debug-lens) + ("rust-analyzer.showReferences" #'lsp-rust--analyzer-show-references)) + :library-folders-fn (lambda (_workspace) lsp-rust-library-directories) + :after-open-fn (lambda () + (when lsp-rust-analyzer-server-display-inlay-hints + (lsp-rust-analyzer-inlay-hints-mode))) + :ignore-messages nil + :server-id 'rust-analyzer + :custom-capabilities `((experimental . ((snippetTextEdit . ,(and lsp-enable-snippet (featurep 'yasnippet)))))) + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'rust-analyzer callback error-callback)))) + +(defun lsp-rust-switch-server (&optional lsp-server) + "Switch priorities of lsp servers, unless LSP-SERVER is already active." + (interactive) + (let ((current-server (if (> (lsp--client-priority (gethash 'rls lsp-clients)) 0) + 'rls + 'rust-analyzer))) + (unless (eq lsp-server current-server) + (dolist (server '(rls rust-analyzer)) + (when (natnump (setf (lsp--client-priority (gethash server lsp-clients)) + (* (lsp--client-priority (gethash server lsp-clients)) -1))) + (message (format "Switched to server %s." server))))))) + +;; inlay hints + +(defvar-local lsp-rust-analyzer-inlay-hints-timer nil) + +(defface lsp-rust-analyzer-inlay-face + '((t :inherit font-lock-comment-face)) + "The face to use for the Rust Analyzer inlays." + :group 'lsp-rust + :package-version '(lsp-mode . "7.0")) + +(defface lsp-rust-analyzer-inlay-type-face + '((t :inherit lsp-rust-analyzer-inlay-face)) + "Face for inlay type hints (e.g. inferred variable types)." + :group 'lsp-rust + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-rust-analyzer-inlay-type-space-format "%s" + "Format string for spacing around variable inlays +\(not part of the inlay face)." + :type '(string :tag "String") + :group 'lsp-rust + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-rust-analyzer-inlay-type-format ": %s" + "Format string for variable inlays (part of the inlay face)." + :type '(string :tag "String") + :group 'lsp-rust + :package-version '(lsp-mode . "7.1")) + +(defface lsp-rust-analyzer-inlay-param-face + '((t :inherit lsp-rust-analyzer-inlay-face)) + "Face for inlay parameter hints (e.g. function parameter names at call-site)." + :group 'lsp-rust + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-rust-analyzer-inlay-param-space-format "%s " + "Format string for spacing around parameter inlays +\(not part of the inlay face)." + :type '(string :tag "String") + :group 'lsp-rust + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-rust-analyzer-inlay-param-format "%s:" + "Format string for parameter inlays (part of the inlay face)." + :type '(string :tag "String") + :group 'lsp-rust + :package-version '(lsp-mode . "7.1")) + +(defface lsp-rust-analyzer-inlay-chain-face + '((t :inherit lsp-rust-analyzer-inlay-face)) + "Face for inlay chaining hints (e.g. inferred chain intermediate types)." + :group 'lsp-rust + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-rust-analyzer-inlay-chain-space-format "%s" + "Format string for spacing around chain inlays (not part of the inlay face)." + :type '(string :tag "String") + :group 'lsp-rust + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-rust-analyzer-inlay-chain-format ": %s" + "Format string for chain inlays (part of the inlay face)." + :type '(string :tag "String") + :group 'lsp-rust + :package-version '(lsp-mode . "7.1")) + +(defun lsp-rust-analyzer-update-inlay-hints (buffer) + (if (and (lsp-rust-analyzer-initialized?) + (eq buffer (current-buffer))) + (lsp-request-async + "rust-analyzer/inlayHints" + (lsp-make-rust-analyzer-inlay-hints-params + :text-document (lsp--text-document-identifier)) + (lambda (res) + (remove-overlays (point-min) (point-max) 'lsp-rust-analyzer-inlay-hint t) + (dolist (hint res) + (-let* (((&rust-analyzer:InlayHint :range :label :kind) hint) + ((&RangeToPoint :start :end) range) + (overlay (make-overlay start end nil 'front-advance 'end-advance))) + (overlay-put overlay 'lsp-rust-analyzer-inlay-hint t) + (overlay-put overlay 'evaporate t) + (cond + ((equal kind lsp/rust-analyzer-inlay-hint-kind-type-hint) + (overlay-put overlay 'after-string + (format lsp-rust-analyzer-inlay-type-space-format + (propertize (format lsp-rust-analyzer-inlay-type-format label) + 'font-lock-face 'lsp-rust-analyzer-inlay-type-face)))) + + ((equal kind lsp/rust-analyzer-inlay-hint-kind-param-hint) + (overlay-put overlay 'before-string + (format lsp-rust-analyzer-inlay-param-space-format + (propertize (format lsp-rust-analyzer-inlay-param-format label) + 'font-lock-face 'lsp-rust-analyzer-inlay-param-face)))) + + ((equal kind lsp/rust-analyzer-inlay-hint-kind-chaining-hint) + (overlay-put overlay 'after-string + (format lsp-rust-analyzer-inlay-chain-space-format + (propertize (format lsp-rust-analyzer-inlay-chain-format label) + 'font-lock-face 'lsp-rust-analyzer-inlay-chain-face)))))))) + :mode 'tick)) + nil) + +(defun lsp-rust-analyzer-initialized? () + (when-let ((workspace (lsp-find-workspace 'rust-analyzer (buffer-file-name)))) + (eq 'initialized (lsp--workspace-status workspace)))) + +(defun lsp-rust-analyzer-inlay-hints-change-handler (&rest _rest) + (when lsp-rust-analyzer-inlay-hints-timer + (cancel-timer lsp-rust-analyzer-inlay-hints-timer)) + (setq lsp-rust-analyzer-inlay-hints-timer + (run-with-idle-timer 0.1 nil #'lsp-rust-analyzer-update-inlay-hints (current-buffer)))) + +(define-minor-mode lsp-rust-analyzer-inlay-hints-mode + "Mode for displaying inlay hints." + :lighter nil + (cond + (lsp-rust-analyzer-inlay-hints-mode + (lsp-rust-analyzer-update-inlay-hints (current-buffer)) + (add-hook 'lsp-on-change-hook #'lsp-rust-analyzer-inlay-hints-change-handler nil t)) + (t + (remove-overlays (point-min) (point-max) 'lsp-rust-analyzer-inlay-hint t) + (remove-hook 'lsp-on-change-hook #'lsp-rust-analyzer-inlay-hints-change-handler t)))) + +(defun lsp-rust-analyzer-expand-macro () + "Expands the macro call at point recursively." + (interactive) + (-if-let* ((params (lsp-make-rust-analyzer-expand-macro-params + :text-document (lsp--text-document-identifier) + :position (lsp--cur-position))) + (response (lsp-send-request (lsp-make-request + "rust-analyzer/expandMacro" + params))) + ((&rust-analyzer:ExpandedMacro :expansion) response)) + (funcall lsp-rust-analyzer-macro-expansion-method expansion) + (message "No macro found at point, or it could not be expanded."))) + +(defun lsp-rust-analyzer-macro-expansion-default (result) + "Default method for displaying macro expansion." + (let* ((root (lsp-workspace-root default-directory)) + (buf (get-buffer-create (get-buffer-create (format "*rust-analyzer macro expansion %s*" root))))) + (with-current-buffer buf + (let ((inhibit-read-only t)) + (erase-buffer) + (insert result) + (special-mode))) + (display-buffer buf))) + +;; runnables +(defvar lsp-rust-analyzer--last-runnable nil) + +(defun lsp-rust-analyzer--runnables () + (lsp-send-request (lsp-make-request + "experimental/runnables" + (lsp-make-rust-analyzer-runnables-params + :text-document (lsp--text-document-identifier) + :position? (lsp--cur-position))))) + +(defun lsp-rust-analyzer--select-runnable () + (lsp--completing-read + "Select runnable:" + (if lsp-rust-analyzer--last-runnable + (cons lsp-rust-analyzer--last-runnable + (-remove (-lambda ((&rust-analyzer:Runnable :label)) + (equal label (lsp-get lsp-rust-analyzer--last-runnable :label))) + (lsp-rust-analyzer--runnables))) + (lsp-rust-analyzer--runnables)) + (-lambda ((&rust-analyzer:Runnable :label)) label))) + + +(defun lsp-rust-analyzer--common-runner (runnable) + "Execute a given RUNNABLE. + +Extract the arguments, prepare the minor mode (cargo-process-mode if possible) +and run a compilation" + (-let* (((&rust-analyzer:Runnable :kind :label :args) runnable) + ((&rust-analyzer:RunnableArgs :cargo-args :executable-args :workspace-root?) args) + (default-directory (or workspace-root? default-directory))) + (if (not (string-equal kind "cargo")) + (lsp--error "'%s' runnable is not supported" kind) + (compilation-start + (string-join (append (list "cargo") cargo-args (when executable-args '("--")) executable-args '()) " ") + ;; cargo-process-mode is nice, but try to work without it... + (if (functionp 'cargo-process-mode) 'cargo-process-mode nil) + (lambda (_) (concat "*" label "*")))))) + + +(defun lsp-rust-analyzer-run (runnable) + "Select and run a RUNNABLE action." + (interactive (list (lsp-rust-analyzer--select-runnable))) + (when (lsp-rust-analyzer--common-runner runnable) + (setq lsp-rust-analyzer--last-runnable runnable))) + +(defun lsp-rust-analyzer-debug (runnable) + "Select and debug a RUNNABLE action." + (interactive (list (lsp-rust-analyzer--select-runnable))) + (unless (featurep 'dap-cpptools) + (user-error "You must require `dap-cpptools'")) + (-let (((&rust-analyzer:Runnable + :args (&rust-analyzer:RunnableArgs :cargo-args :workspace-root? :executable-args) + :label) runnable)) + (cl-case (aref cargo-args 0) + ("run" (aset cargo-args 0 "build")) + ("test" (when (-contains? (append cargo-args ()) "--no-run") + (cl-callf append cargo-args (list "--no-run"))))) + (->> (append (list (executable-find "cargo")) + cargo-args + (list "--message-format=json")) + (s-join " ") + (shell-command-to-string) + (s-lines) + (-keep (lambda (s) + (condition-case nil + (-let* ((json-object-type 'plist) + ((msg &as &plist :reason :executable) (json-read-from-string s))) + (when (and executable (string= "compiler-artifact" reason)) + executable)) + (error)))) + (funcall + (lambda (artifact-spec) + (pcase artifact-spec + (`() (user-error "No compilation artifacts or obtaining the runnable artifacts failed")) + (`(,spec) spec) + (_ (user-error "Multiple compilation artifacts are not supported"))))) + (list :type "cppdbg" + :request "launch" + :name label + :args executable-args + :cwd workspace-root? + :sourceLanguages ["rust"] + :program) + (dap-debug)))) + +(defun lsp-rust-analyzer-rerun (&optional runnable) + (interactive (list (or lsp-rust-analyzer--last-runnable + (lsp-rust-analyzer--select-runnable)))) + (lsp-rust-analyzer-run (or runnable lsp-rust-analyzer--last-runnable))) + +;; goto parent module +(cl-defun lsp-rust-find-parent-module (&key display-action) + "Find parent module of current module." + (interactive) + (lsp-find-locations "experimental/parentModule" nil :display-action display-action)) + +(defun lsp-rust-analyzer-open-cargo-toml (&optional new-window) + "Open the closest Cargo.toml from the current file. + +Rust-Analyzer LSP protocol documented here and added in November 2020 +https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#open-cargotoml + +If NEW-WINDOW (interactively the prefix argument) is non-nil, +open in a new window." + (interactive "P") + (-if-let (workspace (lsp-find-workspace 'rust-analyzer)) + (-if-let* ((response (with-lsp-workspace workspace + (lsp-send-request (lsp-make-request + "experimental/openCargoToml" + (lsp-make-rust-analyzer-open-cargo-toml-params + :text-document (lsp--text-document-identifier)))))) + ((&Location :uri :range) response)) + (funcall (if new-window #'find-file-other-window #'find-file) + (lsp--uri-to-path uri)) + (lsp--warn "Couldn't find a Cargo.toml file or your version of rust-analyzer doesn't support this extension")) + (lsp--error "OpenCargoToml is an extension available only with rust-analyzer"))) + + +(defun lsp-rust-analyzer--related-tests () + "Get runnable test items related to the current TextDocumentPosition. +Calls a rust-analyzer LSP extension endpoint that returns a wrapper over Runnable[]" + (lsp-send-request (lsp-make-request + "rust-analyzer/relatedTests" + (lsp--text-document-position-params)))) + +(defun lsp-rust-analyzer--select-related-test () + "Call the endpoint and ask for user selection. + +Cannot reuse `lsp-rust-analyzer--select-runnable' because the runnables endpoint +responds with Runnable[], while relatedTests responds with TestInfo[], which is a wrapper +over runnable. Also, this method doesn't set the `lsp-rust-analyzer--last-runnable' variable" + (-if-let* ((resp (lsp-rust-analyzer--related-tests)) + (runnables (seq-map + #'lsp:rust-analyzer-related-tests-runnable + resp))) + (lsp--completing-read + "Select test: " + runnables + #'lsp:rust-analyzer-runnable-label))) + +(defun lsp-rust-analyzer-related-tests (runnable) + "Execute a RUNNABLE test related to the current document position. + +Rust-Analyzer LSP protocol extension +https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/dev/lsp-extensions.md#related-tests" + (interactive (list (lsp-rust-analyzer--select-related-test))) + (if runnable + (lsp-rust-analyzer--common-runner runnable) + (lsp--info "There are no tests related to the symbol at point"))) + + +(lsp-consistency-check lsp-rust) + +(provide 'lsp-rust) +;;; lsp-rust.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-semantic-tokens.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-semantic-tokens.el new file mode 100644 index 0000000..00e6b45 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-semantic-tokens.el @@ -0,0 +1,758 @@ +;;; lsp-semantic-tokens.el --- Semantic tokens -*- lexical-binding: t; -*- +;; +;; Copyright (C) 2020 emacs-lsp maintainers +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. +;; +;;; Commentary: +;; +;; Semantic tokens +;; https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_semanticTokens +;; +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-semantic-tokens nil + "LSP support for semantic-tokens." + :prefix "lsp-semantic-tokens-" + :group 'lsp-mode + :tag "LSP Semantic tokens") + +(define-obsolete-variable-alias 'lsp-semantic-highlighting-warn-on-missing-face 'lsp-semantic-tokens-warn-on-missing-face "lsp-mode 7.1") + +(defcustom lsp-semantic-tokens-warn-on-missing-face nil + "Warning on missing face for token type/modifier. +When non-nil, this option will emit a warning any time a token +or modifier type returned by a language server has no face associated with it." + :group 'lsp-semantic-tokens + :type 'boolean) + +(defcustom lsp-semantic-tokens-apply-modifiers nil + "Whether semantic tokens should take token modifiers into account." + :group 'lsp-semantic-tokens + :type 'boolean) + +(defcustom lsp-semantic-tokens-allow-ranged-requests t + "Whether to use ranged semantic token requests when available. + +Note that even when this is set to t, delta requests will +be preferred whenever possible, unless +`lsp-semantic-tokens-allow-delta-requests' is false." + :group 'lsp-semantic-tokens + :type 'boolean) + +(defcustom lsp-semantic-tokens-allow-delta-requests t + "Whether to use semantic token delta requests when available. + +When supported by the language server, delta requests are always +preferred over both full and ranged token requests." + :group 'lsp-semantic-tokens + :type 'boolean) + +(defface lsp-face-semhl-constant + '((t :inherit font-lock-constant-face)) + "Face used for semantic highlighting scopes matching constant scopes." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-variable + '((t :inherit font-lock-variable-name-face)) + "Face used for semantic highlighting scopes matching variable.*. +Unless overridden by a more specific face association." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-function + '((t :inherit font-lock-function-name-face)) + "Face used for semantic highlighting scopes matching entity.name.function.*. +Unless overridden by a more specific face association." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-method + '((t :inherit lsp-face-semhl-function)) + "Face used for semantic highlighting scopes matching entity.name.method.*. +Unless overridden by a more specific face association." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-namespace + '((t :inherit font-lock-type-face :weight bold)) + "Face used for semantic highlighting scopes matching entity.name.namespace.*. +Unless overridden by a more specific face association." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-comment + '((t (:inherit font-lock-comment-face))) + "Face used for comments." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-keyword + '((t (:inherit font-lock-keyword-face))) + "Face used for keywords." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-string + '((t (:inherit font-lock-string-face))) + "Face used for keywords." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-number + '((t (:inherit font-lock-constant-face))) + "Face used for numbers." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-regexp + '((t (:inherit font-lock-string-face :slant italic))) + "Face used for regexps." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-operator + '((t (:inherit font-lock-function-name-face))) + "Face used for operators." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-namespace + '((t (:inherit font-lock-keyword-face))) + "Face used for namespaces." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-type + '((t (:inherit font-lock-type-face))) + "Face used for types." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-struct + '((t (:inherit font-lock-type-face))) + "Face used for structs." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-class + '((t (:inherit font-lock-type-face))) + "Face used for classes." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-interface + '((t (:inherit font-lock-type-face))) + "Face used for interfaces." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-enum + '((t (:inherit font-lock-type-face))) + "Face used for enums." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-type-parameter + '((t (:inherit font-lock-type-face))) + "Face used for type parameters." + :group 'lsp-semantic-tokens) + +;; function face already defined, move here when support +;; for theia highlighting gets removed +(defface lsp-face-semhl-member + '((t (:inherit font-lock-variable-name-face))) + "Face used for members." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-property + '((t (:inherit font-lock-variable-name-face))) + "Face used for properties." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-event + '((t (:inherit font-lock-variable-name-face))) + "Face used for event properties." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-macro + '((t (:inherit font-lock-preprocessor-face))) + "Face used for macros." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-variable + '((t (:inherit font-lock-variable-name-face))) + "Face used for variables." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-parameter + '((t (:inherit font-lock-variable-name-face))) + "Face used for parameters." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-label + '((t (:inherit font-lock-comment-face))) + "Face used for labels." + :group 'lsp-semantic-tokens) + +(defface lsp-face-semhl-deprecated + '((t :strike-through t)) + "Face used for semantic highlighting scopes matching constant scopes." + :group 'lsp-semantic-tokens) + +(defvar lsp-semantic-token-faces + '(("comment" . lsp-face-semhl-comment) + ("keyword" . lsp-face-semhl-keyword) + ("string" . lsp-face-semhl-string) + ("number" . lsp-face-semhl-number) + ("regexp" . lsp-face-semhl-regexp) + ("operator" . lsp-face-semhl-operator) + ("namespace" . lsp-face-semhl-namespace) + ("type" . lsp-face-semhl-type) + ("struct" . lsp-face-semhl-struct) + ("class" . lsp-face-semhl-class) + ("interface" . lsp-face-semhl-interface) + ("enum" . lsp-face-semhl-enum) + ("typeParameter" . lsp-face-semhl-type-parameter) + ("function" . lsp-face-semhl-function) + ("method" . lsp-face-semhl-method) + ("member" . lsp-face-semhl-member) + ("property" . lsp-face-semhl-property) + ("event" . lsp-face-semhl-event) + ("macro" . lsp-face-semhl-macro) + ("variable" . lsp-face-semhl-variable) + ("parameter" . lsp-face-semhl-parameter) + ("label" . lsp-face-semhl-label) + ("enumConstant" . lsp-face-semhl-constant) + ("enumMember" . lsp-face-semhl-constant) + ("dependent" . lsp-face-semhl-type) + ("concept" . lsp-face-semhl-interface)) + "Faces to use for semantic tokens.") + +(defvar lsp-semantic-token-modifier-faces + ;; TODO: add default definitions + '(("declaration" . lsp-face-semhl-interface) + ("deprecated" . lsp-face-semhl-deprecated) + ("readonly" . lsp-face-semhl-constant)) + "Semantic tokens modifier faces. +Faces to use for semantic token modifiers if +`lsp-semantic-tokens-apply-modifiers' is non-nil.") + +(defvar lsp-semantic-tokens-capabilities + `((semanticTokens + . ((dynamicRegistration . t) + (requests . ((range . t) (full . t))) + (tokenModifiers . ,(if lsp-semantic-tokens-apply-modifiers + (apply 'vector (mapcar #'car lsp-semantic-token-modifier-faces)) [])) + (tokenTypes . ,(apply 'vector (mapcar #'car lsp-semantic-token-faces))) + (formats . ["relative"]))))) + + +(defvar lsp--semantic-tokens-idle-timer nil) + +(defvar-local lsp--semantic-tokens-cache nil + "Previously returned token set. + +When non-nil, `lsp--semantic-tokens-cache' should adhere to the +following lsp-interface: +`(_SemanticTokensCache + (:_documentVersion :_ranged) + (:response :_region))'.") + +(defsubst lsp--semantic-tokens-putcache (k v) + "Set key K of `lsp--semantic-tokens-cache' to V." + (setq lsp--semantic-tokens-cache + (plist-put lsp--semantic-tokens-cache k v))) + +(defvar-local lsp--semantic-tokens-teardown nil) + +(defun lsp--semantic-tokens-request-full-token-set-when-idle (fontify-immediately) + "Request full token set after an idle timeout of `lsp-idle-delay'. + +If FONTIFY-IMMEDIATELY is non-nil, fontification will be performed immediately + once the corresponding response is received." + (when lsp--semantic-tokens-idle-timer (cancel-timer lsp--semantic-tokens-idle-timer)) + (let ((buf (current-buffer))) + (setq lsp--semantic-tokens-idle-timer + (run-with-idle-timer + lsp-idle-delay + nil + (lambda () + (when (buffer-live-p buf) + (with-current-buffer buf + (lsp--semantic-tokens-request nil fontify-immediately)))))))) + +(defun lsp--semantic-tokens-ingest-range-response (response) + "Handle RESPONSE to semanticTokens/range request." + (lsp--semantic-tokens-putcache :response response) + (lsp--semantic-tokens-putcache :_ranged t) + (lsp--semantic-tokens-request-full-token-set-when-idle nil)) + +(defun lsp--semantic-tokens-ingest-full-response (response) + "Handle RESPONSE to semanticTokens/full request." + (lsp--semantic-tokens-putcache :response response) + (lsp--semantic-tokens-putcache :_ranged nil)) + +(defsubst lsp--semantic-tokens-apply-delta-edits (old-data edits) + "Apply EDITS obtained from full/delta request to OLD-DATA." + (let* ((old-token-count (length old-data)) + (old-token-index 0) + (substrings)) + (cl-loop + for edit across edits + when (< old-token-index (lsp-get edit :start)) + do + (push (substring old-data old-token-index (lsp-get edit :start)) substrings) + (push (lsp-get edit :data) substrings) + (setq old-token-index (+ (lsp-get edit :start) (lsp-get edit :deleteCount))) + finally do (push (substring old-data old-token-index old-token-count) substrings)) + (apply #'vconcat (nreverse substrings)))) + +(defun lsp--semantic-tokens-ingest-full/delta-response (response) + "Handle RESPONSE to semanticTokens/full/delta request." + (if (lsp-get response :edits) + (let ((old-data (--> lsp--semantic-tokens-cache (plist-get it :response) (lsp-get it :data)))) + (when old-data + (lsp--semantic-tokens-putcache + :response (lsp-put response + :data (lsp--semantic-tokens-apply-delta-edits + old-data (lsp-get response :edits)))) + (lsp--semantic-tokens-putcache :_ranged nil))) + ;; server decided to send full response instead + (lsp--semantic-tokens-ingest-full-response response))) + + +(defun lsp--semantic-tokens-request (region fontify-immediately) + "Send semantic tokens request to the language server. + +A full/delta request will be sent if delta requests are supported by +the language server, allowed via `lsp-semantic-tokens-allow-delta-requests', +and if a full set of tokens had previously been received. +Otherwise, a ranged request will be dispatched if REGION is non-nil, +ranged requests are supported by the language server, and allowed via +`lsp-semantic-tokens-allow-delta-requests'. In all other cases, a full +tokens request will be dispatched. + +If FONTIFY-IMMEDIATELY is non-nil, fontification will be performed immediately + upon receiving the response." + (let ((request-type "textDocument/semanticTokens/full") + (request `(:textDocument ,(lsp--text-document-identifier))) + (response-handler nil)) + (cond + ((and lsp-semantic-tokens-allow-delta-requests + (lsp-feature? "textDocument/semanticTokensFull/Delta") + (--> lsp--semantic-tokens-cache + (plist-get it :response) + (and (lsp-get it :resultId) (lsp-get it :data) (not (lsp-get it :_ranged))))) + (setq request-type "textDocument/semanticTokens/full/delta") + (setq response-handler #'lsp--semantic-tokens-ingest-full/delta-response) + (setq request + (plist-put request :previousResultId + (lsp-get (plist-get lsp--semantic-tokens-cache :response) :resultId)))) + ((and lsp-semantic-tokens-allow-ranged-requests region + (lsp-feature? "textDocument/semanticTokensRangeProvider")) + (setq request-type "textDocument/semanticTokens/range") + (setq request + (plist-put request :range (lsp--region-to-range (car region) (cdr region)))) + (setq response-handler #'lsp--semantic-tokens-ingest-range-response)) + (t (setq response-handler #'lsp--semantic-tokens-ingest-full-response))) + (when lsp--semantic-tokens-idle-timer (cancel-timer lsp--semantic-tokens-idle-timer)) + (lsp-request-async + request-type request + (lambda (response) + (lsp--semantic-tokens-putcache :_documentVersion lsp--cur-version) + (funcall response-handler response) + (when fontify-immediately (font-lock-flush))) + :error-handler (lambda (&rest _) (lsp--semantic-tokens-request-full-token-set-when-idle t)) + :mode 'tick + :cancel-token (format "semantic-tokens-%s" (lsp--buffer-uri))))) + + +(defun lsp-semantic-tokens--fontify (old-fontify-region beg-orig end-orig &optional loudly) + "Apply fonts to retrieved semantic tokens. +OLD-FONTIFY-REGION is the underlying region fontification function, +e.g., `font-lock-fontify-region'. +BEG-ORIG and END-ORIG deliminate the requested fontification region and maybe +modified by OLD-FONTIFY-REGION. +LOUDLY will be forwarded to OLD-FONTIFY-REGION as-is." + ;; TODO: support multiple language servers per buffer? + (let ((faces (seq-some #'lsp--workspace-semantic-tokens-faces lsp--buffer-workspaces)) + (modifier-faces + (when lsp-semantic-tokens-apply-modifiers + (seq-some #'lsp--workspace-semantic-tokens-modifier-faces lsp--buffer-workspaces))) + old-bounds + beg end) + (cond + ((or (eq nil faces) + (eq nil lsp--semantic-tokens-cache) + (eq nil (plist-get lsp--semantic-tokens-cache :response))) + ;; default to non-semantic highlighting until first response has arrived + (funcall old-fontify-region beg-orig end-orig loudly)) + ((not (= lsp--cur-version (plist-get lsp--semantic-tokens-cache :_documentVersion))) + ;; delay fontification until we have fresh tokens + '(jit-lock-bounds 0 . 0)) + (t + (setq old-bounds (funcall old-fontify-region beg-orig end-orig loudly)) + ;; this is to prevent flickering when semantic token highlighting + ;; is layered on top of, e.g., tree-sitter-hl, or clojure-mode's syntax highlighting. + (setq beg (min beg-orig (cadr old-bounds)) + end (max end-orig (cddr old-bounds))) + (-let* ((inhibit-field-text-motion t) + (data (lsp-get (plist-get lsp--semantic-tokens-cache :response) :data)) + (i0 0) + (i-max (1- (length data))) + (current-line 1) + (line-delta) + (column 0) + (face) + (line-start-pos) + (line-min) + (line-max-inclusive) + (text-property-beg) + (text-property-end)) + (save-mark-and-excursion + (save-restriction + (widen) + (goto-char beg) + (goto-char (line-beginning-position)) + (setq line-min (line-number-at-pos)) + (with-silent-modifications + (goto-char end) + (goto-char (line-end-position)) + (setq line-max-inclusive (line-number-at-pos)) + (forward-line (- line-min line-max-inclusive)) + (let ((skip-lines (- line-min current-line))) + (while (and (<= i0 i-max) (< (aref data i0) skip-lines)) + (setq skip-lines (- skip-lines (aref data i0))) + (setq i0 (+ i0 5))) + (setq current-line (- line-min skip-lines))) + (forward-line (- current-line line-min)) + (setq line-start-pos (point)) + (cl-loop + for i from i0 to i-max by 5 do + (setq line-delta (aref data i)) + (unless (= line-delta 0) + (forward-line line-delta) + (setq line-start-pos (point)) + (setq column 0) + (setq current-line (+ current-line line-delta))) + (setq column (+ column (aref data (1+ i)))) + (setq face (aref faces (aref data (+ i 3)))) + (setq text-property-beg (+ line-start-pos column)) + (setq text-property-end (+ text-property-beg (aref data (+ i 2)))) + (when face + (put-text-property text-property-beg text-property-end 'face face)) + (cl-loop for j from 0 to (1- (length modifier-faces)) do + (when (and (aref modifier-faces j) + (> (logand (aref data (+ i 4)) (lsh 1 j)) 0)) + (add-face-text-property text-property-beg text-property-end + (aref modifier-faces j)))) + when (> current-line line-max-inclusive) return nil))))) + (let ((token-region (plist-get lsp--semantic-tokens-cache :_region))) + (if token-region + `(jit-lock-bounds ,(max beg (car token-region)) . ,(min end (cdr token-region))) + `(jit-lock-bounds ,beg . ,end))))))) + +(defun lsp-semantic-tokens--request-update () + "Request semantic-tokens update." + (lsp--semantic-tokens-request (cons (window-start) (window-end)) t)) + +(defun lsp--semantic-tokens-as-defined-by-workspace (workspace) + "Return plist of token-types and token-modifiers defined by WORKSPACE, or nil if none are defined." + (when-let ((token-capabilities + (or + (-some-> + (lsp--registered-capability "textDocument/semanticTokens") + (lsp--registered-capability-options)) + (lsp:server-capabilities-semantic-tokens-provider? + (lsp--workspace-server-capabilities workspace))))) + (-let* (((&SemanticTokensOptions :legend) token-capabilities)) + `(:token-types ,(lsp:semantic-tokens-legend-token-types legend) + :token-modifiers ,(lsp:semantic-tokens-legend-token-modifiers legend))))) + +(defun lsp-semantic-tokens-suggest-overrides () + "Suggest face overrides that best match the faces chosen by `font-lock-fontify-region'." + (interactive) + (-when-let* ((token-info (-some #'lsp--semantic-tokens-as-defined-by-workspace lsp--buffer-workspaces)) + ((&plist :token-types token-types :token-modifiers token-modifiers) token-info)) + (let* ((tokens (lsp-request + "textDocument/semanticTokens/full" + `(:textDocument, (lsp--text-document-identifier)))) + (inhibit-field-text-motion t) + (data (lsp-get tokens :data)) + (associated-faces '()) + (line-delta) + ;; KLUDGE: clear cache so our font-lock advice won't apply semantic-token faces + (old-cache lsp--semantic-tokens-cache) + (face-or-faces)) + (setq lsp--semantic-tokens-cache nil) + (save-restriction + (save-excursion + (widen) + (font-lock-fontify-region (point-min) (point-max) t) + (save-mark-and-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (cl-loop + for i from 0 to (1- (length data)) by 5 do + (setq line-delta (aref data i)) + (unless (= line-delta 0) (forward-line line-delta)) + (forward-char (aref data (+ i 1))) + (setq face-or-faces (get-text-property (point) 'face)) + ;; TODO: consider modifiers? + (when face-or-faces + (--each (if (listp face-or-faces) face-or-faces (list face-or-faces)) + (cl-pushnew `(,(aref data (+ i 3)) . ,it) associated-faces :test #'equal)))) + (setq lsp--semantic-tokens-cache old-cache) + (font-lock-flush))))) + (switch-to-buffer (get-buffer-create "*Suggested Overrides*")) + (insert "(") + ;; TODO: sort alternatives by frequency + (--each-indexed (-group-by #'car associated-faces) + (insert (if (= it-index 0) "(" "\n (")) + (insert (format "%s . " (aref token-types (car it)))) + (--each-indexed (mapcar #'cdr (cdr it)) + (insert (if (= it-index 0) (format "%s)" (prin1-to-string it)) + (format " ; Alternative: %s" (prin1-to-string it)))))) + (insert ")")))) + + +;;;###autoload +(defun lsp--semantic-tokens-initialize-buffer () + "Initialize the buffer for semantic tokens. +IS-RANGE-PROVIDER is non-nil when server supports range requests." + (let* ((old-extend-region-functions font-lock-extend-region-functions) + ;; make sure font-lock always fontifies entire lines (TODO: do we also have + ;; to change some jit-lock-...-region functions/variables?) + (new-extend-region-functions + (if (memq 'font-lock-extend-region-wholelines old-extend-region-functions) + old-extend-region-functions + (cons 'font-lock-extend-region-wholelines old-extend-region-functions)))) + (setq lsp--semantic-tokens-cache nil) + (setq font-lock-extend-region-functions new-extend-region-functions) + (add-function :around (local 'font-lock-fontify-region-function) #'lsp-semantic-tokens--fontify) + (add-hook 'lsp-on-change-hook #'lsp-semantic-tokens--request-update nil t) + (lsp-semantic-tokens--request-update) + (setq lsp--semantic-tokens-teardown + (lambda () + (setq font-lock-extend-region-functions old-extend-region-functions) + (when lsp--semantic-tokens-idle-timer + (cancel-timer lsp--semantic-tokens-idle-timer) + (setq lsp--semantic-tokens-idle-timer nil)) + (setq lsp--semantic-tokens-cache nil) + (remove-function (local 'font-lock-fontify-region-function) + #'lsp-semantic-tokens--fontify) + (remove-hook 'lsp-on-change-hook #'lsp-semantic-tokens--request-update t))))) + +(defun lsp--semantic-tokens-build-face-map (identifiers faces category varname) + "Build map of FACES for IDENTIFIERS using CATEGORY and VARNAME." + (apply 'vector + (mapcar (lambda (id) + (let ((maybe-face (cdr (assoc id faces)))) + (when (and lsp-semantic-tokens-warn-on-missing-face (not maybe-face)) + (lsp-warn "No face has been associated to the %s '%s': consider adding a corresponding definition to %s" + category id varname)) maybe-face)) identifiers))) + +(defun lsp-semantic-tokens--replace-alist-values (a b) + "Replace alist A values with B ones where available." + (-map + (-lambda ((ak . av)) + (cons ak (alist-get ak b av nil #'string=))) + a)) + +(defun lsp-semantic-tokens--type-faces-for (client) + "Return the semantic token type faces for CLIENT." + (lsp-semantic-tokens--replace-alist-values lsp-semantic-token-faces + (plist-get (lsp--client-semantic-tokens-faces-overrides client) :types))) + +(defun lsp-semantic-tokens--modifier-faces-for (client) + "Return the semantic token type faces for CLIENT." + (lsp-semantic-tokens--replace-alist-values lsp-semantic-token-modifier-faces + (plist-get (lsp--client-semantic-tokens-faces-overrides client) :modifiers))) + +(defun lsp--semantic-tokens-on-refresh () + "Invoked in response to workspace/semanticTokens/refresh requests." + (cl-loop for workspace in (lsp-workspaces) + for ws-buffer in (lsp--workspace-buffers workspace) do + (unless (equal (current-buffer) ws-buffer) + (setf (buffer-local-value 'lsp--semantic-tokens-cache ws-buffer) nil))) + (lsp--semantic-tokens-request-full-token-set-when-idle t)) + +;;;###autoload +(defun lsp--semantic-tokens-initialize-workspace (workspace) + "Initialize semantic tokens for WORKSPACE." + (cl-assert workspace) + (-let (((&plist :token-types types :token-modifiers modifiers) + (lsp--semantic-tokens-as-defined-by-workspace workspace)) + (client (lsp--workspace-client workspace))) + (setf (lsp--workspace-semantic-tokens-faces workspace) + (lsp--semantic-tokens-build-face-map + types (lsp-semantic-tokens--type-faces-for client) + "semantic token" "lsp-semantic-token-faces")) + (setf (lsp--workspace-semantic-tokens-modifier-faces workspace) + (lsp--semantic-tokens-build-face-map + modifiers (lsp-semantic-tokens--modifier-faces-for client) + "semantic token modifier" "lsp-semantic-token-modifier-faces")))) + +;;;###autoload +(defun lsp-semantic-tokens--warn-about-deprecated-setting () + "Warn about deprecated semantic highlighting variable." + (when (boundp 'lsp-semantic-highlighting) + (pcase lsp-semantic-highlighting + (:semantic-tokens + (lsp-warn "It seems you wish to use semanticTokens-based + highlighting. To do so, please remove any references to the + deprecated variable `lsp-semantic-highlighting' from your + configuration and set `lsp-semantic-tokens-enable' to `t' + instead.") + (setq lsp-semantic-tokens-enable t)) + ((or :immediate :deferred) + (lsp-warn "It seems you wish to use Theia-based semantic + highlighting. This protocol has been superseded by the + semanticTokens protocol specified by LSP v3.16 and is no longer + supported by lsp-mode. If your language server provides + semanticToken support, please set + `lsp-semantic-tokens-enable' to `t' to use it."))))) + +;;;###autoload +(defun lsp-semantic-tokens--enable () + "Enable semantic tokens mode." + (when (and lsp-semantic-tokens-enable + (lsp-feature? "textDocument/semanticTokens")) + (lsp-semantic-tokens--warn-about-deprecated-setting) + (lsp-semantic-tokens-mode 1) + (mapc #'lsp--semantic-tokens-initialize-workspace + (lsp--find-workspaces-for "textDocument/semanticTokens")) + (lsp--semantic-tokens-initialize-buffer))) + +(defun lsp-semantic-tokens--disable () + "Disable semantic tokens mode." + (lsp-semantic-tokens-mode -1)) + +;;;###autoload +(define-minor-mode lsp-semantic-tokens-mode + "Toggle semantic-tokens support." + :group 'lsp-semantic-tokens + :global nil + (cond + (lsp-semantic-tokens-mode + (add-hook 'lsp-configure-hook #'lsp-semantic-tokens--enable nil t) + (add-hook 'lsp-unconfigure-hook #'lsp-semantic-tokens--disable nil t) + (lsp--semantic-tokens-initialize-buffer)) + (t + (remove-hook 'lsp-configure-hook #'lsp-semantic-tokens--enable t) + (remove-hook 'lsp-unconfigure-hook #'lsp-semantic-tokens--disable t) + (when lsp--semantic-tokens-teardown + (funcall lsp--semantic-tokens-teardown)) + (lsp-semantic-tokens--request-update) + (setq lsp--semantic-tokens-idle-timer nil + lsp--semantic-tokens-cache nil + lsp--semantic-tokens-teardown nil)))) + +;; debugging helpers +(defun lsp--semantic-tokens-verify () + "Store current token set and compare with the response to a full token request." + (interactive) + (let ((old-tokens (--> lsp--semantic-tokens-cache (plist-get it :response) (lsp-get it :data))) + (old-version (--> lsp--semantic-tokens-cache (plist-get it :_documentVersion)))) + (if (not (equal lsp--cur-version old-version)) + (message "Stored documentVersion %d differs from current version %d" old-version lsp--cur-version) + (lsp-request-async + "textDocument/semanticTokens/full" `(:textDocument ,(lsp--text-document-identifier)) + (lambda (response) + (let ((new-tokens (lsp-get response :data))) + (if (equal old-tokens new-tokens) + (message "New tokens (total count %d) are identical to previously held token set" + (length new-tokens)) + (message "Newly returned tokens differ from old token set") + (print old-tokens) + (print new-tokens)))) + :mode 'tick + :cancel-token (format "semantic-tokens-%s" (lsp--buffer-uri)))))) + +(defvar-local lsp-semantic-tokens--log '()) + +(defvar-local lsp-semantic-tokens--prev-response nil) + +(defun lsp-semantic-tokens--log-buffer-contents (tag) + "Log buffer contents for TAG." + (save-restriction + (save-excursion + (widen) (push `(:tag ,tag + :buffer-contents ,(buffer-substring (point-min) (point-max)) + :prev-response ,lsp-semantic-tokens--prev-response) + lsp-semantic-tokens--log)))) + +(defun lsp-semantic-tokens-enable-log () + "Enable logging of intermediate fontification states. + +This is a debugging tool, and may incur significant performance penalties." + (setq lsp-semantic-tokens--log '()) + (defadvice lsp-semantic-tokens--fontify (around advice-tokens-fontify activate) + (lsp-semantic-tokens--log-buffer-contents 'before) + (let ((result ad-do-it)) + (lsp-semantic-tokens--log-buffer-contents 'after) + result)) + (defadvice lsp--semantic-tokens-ingest-full/delta-response + (before log-delta-response (response) activate) + (setq lsp-semantic-tokens--prev-response `(:request-type "delta" + :response ,response + :version ,lsp--cur-version))) + (defadvice lsp--semantic-tokens-ingest-full-response + (before log-full-response (response) activate) + (setq lsp-semantic-tokens--prev-response `(:request-type "full" + :response ,response + :version ,lsp--cur-version))) + (defadvice lsp--semantic-tokens-ingest-range-response + (before log-range-response (response) activate) + (setq lsp-semantic-tokens--prev-response `(:request-type "range" + :response ,response + :version ,lsp--cur-version)))) + +(defun lsp-semantic-tokens-disable-log () + "Disable logging of intermediate fontification states." + (ad-unadvise 'lsp-semantic-tokens--fontify) + (ad-unadvise 'lsp--semantic-tokens-ingest-full/delta-response) + (ad-unadvise 'lsp--semantic-tokens-ingest-full-response) + (ad-unadvise 'lsp--semantic-tokens-ingest-range-response)) + +(declare-function htmlize-buffer "ext:htmlize") + +(defun lsp-semantic-tokens-export-log () + "Write HTML-formatted snapshots of previous fontification results to /tmp." + (require 'htmlize) + (let* ((outdir (f-join "/tmp" "semantic-token-snapshots")) + (progress-reporter + (make-progress-reporter + (format "Writing buffer snapshots to %s..." outdir) + 0 (length lsp-semantic-tokens--log)))) + (f-mkdir outdir) + (--each-indexed (reverse lsp-semantic-tokens--log) + (-let* (((&plist :tag tag + :buffer-contents buffer-contents + :prev-response prev-response) it) + (html-buffer)) + ;; FIXME: doesn't update properly; sit-for helps... somewhat, + ;; but unreliably + (when (= (% it-index 5) 0) + (progress-reporter-update progress-reporter it-index) + (sit-for 0.01)) + ;; we're emitting 2 snapshots (before & after) per update, so request + ;; parameters should only change on every 2nd invocation + (when (cl-evenp it-index) + (with-temp-buffer + (insert (prin1-to-string prev-response)) + (write-file (f-join outdir (format "parameters_%d.el" (/ it-index 2)))))) + (with-temp-buffer + (insert buffer-contents) + (setq html-buffer (htmlize-buffer)) + (with-current-buffer html-buffer + ;; some configs such as emacs-doom may autoformat on save; switch to + ;; fundamental-mode to avoid this + (fundamental-mode) + (write-file (f-join outdir (format "buffer_%d_%s.html" (/ it-index 2) tag))))) + (kill-buffer html-buffer))) + (progress-reporter-done progress-reporter))) + +(lsp-consistency-check lsp-semantic-tokens) + +(provide 'lsp-semantic-tokens) +;;; lsp-semantic-tokens.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-solargraph.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-solargraph.el new file mode 100644 index 0000000..968b32a --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-solargraph.el @@ -0,0 +1,166 @@ +;;; lsp-solargraph.el --- Solargraph server configuration -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Ivan Yonchovski + +;; Author: Ivan Yonchovski <yyoncho@gmail.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-solargraph nil + "LSP support for Ruby, using the Solargraph language server." + :group 'lsp-mode + :link '(url-link "https://github.com/castwide/solargraph") + :package-version '(lsp-mode . "6.1")) + +;; (defcustom lsp-solargraph-check-gem-version t +;; "Automatically check if a new version of the Solargraph gem is available." +;; :type 'boolean) + +(defcustom lsp-solargraph-completion t + "Enable completion" + :type 'boolean + :group 'lsp-solargraph + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-solargraph-hover t + "Enable hover" + :type 'boolean + :group 'lsp-solargraph + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-solargraph-diagnostics t + "Enable diagnostics" + :type 'boolean + :group 'lsp-solargraph + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-solargraph-autoformat nil + "Enable automatic formatting while typing (WARNING: experimental)" + :type 'boolean + :group 'lsp-solargraph + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-solargraph-formatting t + "Enable document formatting" + :type 'boolean + :group 'lsp-solargraph + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-solargraph-symbols t + "Enable symbols" + :type 'boolean + :group 'lsp-solargraph + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-solargraph-definitions t + "Enable definitions (go to, etc.)" + :type 'boolean + :group 'lsp-solargraph + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-solargraph-rename t + "Enable symbol renaming" + :type 'boolean + :group 'lsp-solargraph + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-solargraph-references t + "Enable finding references" + :type 'boolean + :group 'lsp-solargraph + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-solargraph-folding t + "Enable folding ranges" + :type 'boolean + :group 'lsp-solargraph + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-solargraph-log-level "warn" + "Level of debug info to log. `warn` is least and `debug` is most." + :type '(choice (const :tag "warn" "info" "debug")) + :group 'lsp-solargraph + :package-version '(lsp-mode . "6.1")) + +;; https://github.com/castwide/solargraph#solargraph-and-bundler +(defcustom lsp-solargraph-use-bundler nil + "Run solargraph under bundler" + :type 'boolean + :safe #'booleanp + :group 'lsp-solargraph + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-solargraph-multi-root t + "If non nil, `solargraph' will be started in multi-root mode." + :type 'boolean + :safe #'booleanp + :group 'lsp-solargraph + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-solargraph-library-directories + '("~/.rbenv/" "/usr/lib/ruby/" "~/.rvm/" "~/.gem/") + "List of directories which will be considered to be libraries." + :type '(repeat string) + :group 'lsp-solargraph + :package-version '(lsp-mode . "7.0.1")) + +(defun lsp-solargraph--build-command () + "Build solargraph command" + (let ((lsp-command '("solargraph" "stdio"))) + (if lsp-solargraph-use-bundler + (append '("bundle" "exec") lsp-command) + lsp-command))) + +(lsp-register-custom-settings + '(("solargraph.logLevel" lsp-solargraph-log-level) + ("solargraph.folding" lsp-solargraph-folding t) + ("solargraph.references" lsp-solargraph-references t) + ("solargraph.rename" lsp-solargraph-rename t) + ("solargraph.definitions" lsp-solargraph-definitions t) + ("solargraph.symbols" lsp-solargraph-symbols t) + ("solargraph.formatting" lsp-solargraph-formatting t) + ("solargraph.autoformat" lsp-solargraph-autoformat t) + ("solargraph.diagnostics" lsp-solargraph-diagnostics t) + ("solargraph.hover" lsp-solargraph-hover t) + ("solargraph.completion" lsp-solargraph-completion t) + ("solargraph.useBundler" lsp-solargraph-use-bundler t))) + +;; Ruby +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection + #'lsp-solargraph--build-command) + :major-modes '(ruby-mode enh-ruby-mode) + :priority -1 + :multi-root lsp-solargraph-multi-root + :library-folders-fn (lambda (_workspace) lsp-solargraph-library-directories) + :server-id 'ruby-ls + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration + (lsp-configuration-section "solargraph")))))) + +(lsp-consistency-check lsp-solargraph) + +(provide 'lsp-solargraph) +;;; lsp-solargraph.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-sorbet.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-sorbet.el new file mode 100644 index 0000000..f11ab47 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-sorbet.el @@ -0,0 +1,59 @@ +;;; lsp-sorbet.el --- Sorbet server configuration -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 + +;; Author: Christopher Wilson <chris@sencjw.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; lsp-sorbet client + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-sorbet nil + "LSP support for Ruby, using the Sorbet language server." + :group 'lsp-mode + :link '(url-link "https://github.com/sorbet/sorbet") + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-sorbet-use-bundler nil + "Run sorbet under bundler" + :type 'boolean + :group 'lsp-sorbet + :package-version '(lsp-mode . "7.1.0")) + +(defun lsp-sorbet--build-command () + "Build sorbet command" + (let ((lsp-command '("srb" "typecheck" "--lsp" "--disable-watchman"))) + (if lsp-sorbet-use-bundler + (append '("bundle" "exec") lsp-command) + lsp-command))) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection + #'lsp-sorbet--build-command) + :priority -2 + :major-modes '(ruby-mode enh-ruby-mode) + :server-id 'sorbet-ls)) + +(lsp-consistency-check lsp-sorbet) + +(provide 'lsp-sorbet) +;;; lsp-sorbet.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-sqls.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-sqls.el new file mode 100644 index 0000000..72ad70a --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-sqls.el @@ -0,0 +1,190 @@ +;;; lsp-sqls.el --- SQL Client settings -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Shunya Ishii + +;; Author: Shunya Ishii +;; Keywords: sql lsp + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP client for SQL + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-sqls nil + "LSP support for SQL, using sqls" + :group 'lsp-mode + :link '(url-link "https://github.com/lighttiger2505/sqls") + :package-version `(lsp-mode . "7.0")) + +(defcustom lsp-sqls-server "sqls" + "Path to the `sqls` binary." + :group 'lsp-sqls + :risky t + :type 'file + :package-version `(lsp-mode . "7.0")) + +(defcustom lsp-sqls-workspace-config-path "workspace" + "If non-nil then setup workspace configuration with json file path." + :group 'lsp-sqls + :risky t + :type '(choice (const "workspace") + (const "root")) + :package-version `(lsp-mode . "7.0")) + +(defun lsp-sqls--make-launch-cmd () + (-let [base `(,lsp-sqls-server)] + ;; we can add some options to command. (e.g. "-config") + base)) + + +(defcustom lsp-sqls-timeout 0.5 + "Timeout to use for `sqls' requests." + :type 'number + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-sqls-connections nil + "The connections to the SQL server(s)." + :type '(repeat (alist :key-type (choice + (const :tag "Driver" driver) + (const :tag "Connection String" dataSourceName)) + :value-type string))) + +(defun lsp-sqls-setup-workspace-configuration () + "Setup workspace configuration using json file depending on `lsp-sqls-workspace-config-path'." + + (if lsp-sqls-connections + (lsp--set-configuration `(:sqls (:connections ,(apply #'vector lsp-sqls-connections)))) + (when-let ((config-json-path (cond + ((equal lsp-sqls-workspace-config-path "workspace") + ".sqls/config.json") + ((equal lsp-sqls-workspace-config-path "root") + (-> (lsp-workspace-root) + (f-join ".sqls/config.json")))))) + (when (file-exists-p config-json-path) + (lsp--set-configuration (lsp--read-json-file config-json-path)))))) + +(defun lsp-sqls--show-results (result) + (with-current-buffer (get-buffer-create "*sqls results*") + (with-help-window (buffer-name) + (erase-buffer) + (insert result)))) + +(defun lsp-sql-execute-query (&optional command start end) + "Execute COMMAND on buffer text against current database. +Buffer text is between START and END. If START and END are nil, +use the current region if set, otherwise the entire buffer." + (interactive) + (lsp-sqls--show-results + (lsp-request + "workspace/executeCommand" + (list :command "executeQuery" + :arguments (or + (when command + (lsp:command-arguments? command)) + (vector (lsp--buffer-uri))) + :timeout lsp-sqls-timeout + :range (list + :start (lsp--point-to-position + (cond + (start start) + ((use-region-p) (region-beginning)) + (t (point-min)))) + :end (lsp--point-to-position + (cond + (end end) + ((use-region-p) (region-end)) + (t (point-max))))))))) + +(defun lsp-sql-execute-paragraph (&optional command) + "Execute COMMAND on paragraph against current database." + (interactive) + (let ((start (save-excursion (backward-paragraph) (point))) + (end (save-excursion (forward-paragraph) (point)))) + (lsp-sql-execute-query command start end))) + +(defun lsp-sql-show-databases (&optional _command) + "Show databases." + (interactive) + (lsp-sqls--show-results + (lsp-request + "workspace/executeCommand" + (list :command "showDatabases" :timeout lsp-sqls-timeout)))) + +(defun lsp-sql-show-schemas (&optional _command) + "Show schemas." + (interactive) + (lsp-sqls--show-results + (lsp-request + "workspace/executeCommand" + (list :command "showSchemas" :timeout lsp-sqls-timeout)))) + +(defun lsp-sql-show-connections (&optional _command) + "Show connections." + (interactive) + (lsp-sqls--show-results + (lsp-request + "workspace/executeCommand" + (list :command "showConnections" :timeout lsp-sqls-timeout)))) + +(defun lsp-sql-switch-database (&optional _command) + "Switch database." + (interactive) + (lsp-workspace-command-execute + "switchDatabase" + (vector (completing-read + "Select database: " + (s-lines (lsp-workspace-command-execute "showDatabases")) + nil + t)))) + +(defun lsp-sql-switch-connection (&optional _command) + "Switch connection." + (interactive) + (lsp-workspace-command-execute + "switchConnections" + (vector (cl-first + (s-match "\\([[:digit:]]*\\)" + (completing-read + "Select connection: " + (s-lines (lsp-workspace-command-execute "showConnections")) + nil + t)))))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection #'lsp-sqls--make-launch-cmd) + :major-modes '(sql-mode) + :priority -1 + :action-handlers (ht ("executeQuery" #'lsp-sql-execute-query) + ("showDatabases" #'lsp-sql-show-databases) + ("showSchemas" #'lsp-sql-show-schemas) + ("showConnections" #'lsp-sql-show-connections) + ("switchDatabase" #'lsp-sql-switch-database) + ("switchConnections" #'lsp-sql-switch-connection)) + :server-id 'sqls + :initialized-fn (lambda (workspace) + (-> workspace + (lsp--workspace-server-capabilities) + (lsp:set-server-capabilities-execute-command-provider? t)) + (with-lsp-workspace workspace + (lsp-sqls-setup-workspace-configuration))))) + +(lsp-consistency-check lsp-sqls) + +(provide 'lsp-sqls) +;;; lsp-sqls.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-steep.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-steep.el new file mode 100644 index 0000000..f1ecba4 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-steep.el @@ -0,0 +1,73 @@ +;;; lsp-steep.el --- lsp-mode for Steep -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Masafumi Koba + +;; Author: Masafumi Koba <ybiquitous@gmail.com> +;; Keywords: languages + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP client for Steep which is a Ruby type checker. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-steep nil + "LSP support for Steep, using the Steep language server." + :group 'lsp-mode + :link '(url-link "https://github.com/soutaro/steep")) + +(defcustom lsp-steep-log-level "warn" + "Log level of Steep." + :type '(choice + (const "fatal") + (const "error") + (const "warn") + (const "info") + (const "debug")) + :group 'lsp-steep) + +(defcustom lsp-steep-use-bundler t + "Run Steep using Bunder." + :type 'boolean + :safe #'booleanp + :group 'lsp-steep) + +(defcustom lsp-steep-server-path nil + "Path of the Steep language server executable. +If specified, `lsp-steep-use-bundler' is ignored." + :type 'file + :group 'lsp-steep + :package-version '(lsp-mode . "7.1")) + +(defun lsp-steep--build-command () + "Build a command to start the Steep language server." + (append + (if (and lsp-steep-use-bundler (not lsp-steep-server-path)) '("bundle" "exec")) + (list (or lsp-steep-server-path "steep") "langserver" "--log-level" lsp-steep-log-level))) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection #'lsp-steep--build-command) + :major-modes '(ruby-mode enh-ruby-mode) + :priority -3 + :server-id 'steep-ls)) + +(lsp-consistency-check lsp-steep) + +(provide 'lsp-steep) +;;; lsp-steep.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-svelte.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-svelte.el new file mode 100644 index 0000000..47f4c8e --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-svelte.el @@ -0,0 +1,307 @@ +;;; lsp-svelte.el --- LSP Svelte integration -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Stepan Lusnikov + +;; Author: Stepan Lusnikov <endenwer@gmail.com> +;; Keywords: lsp svelte + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP client for Svelte + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-svelte nil + "LSP support for Svelte." + :group 'lsp-mode + :link '(url-link + "https://github.com/sveltejs/language-tools")) + +(lsp-dependency 'svelte-language-server + '(:system "svelteserver") + '(:npm :package "svelte-language-server" + :path "svelteserver")) + +(defcustom lsp-svelte-plugin-typescript-enable t + "Enable the TypeScript plugin" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-typescript-diagnostics-enable t + "Enable diagnostic messages for TypeScript" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-typescript-hover-enable t + "Enable hover info for TypeScript" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-typescript-document-symbols-enable t + "Enable document symbols for TypeScript" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-typescript-completions-enable t + "Enable completions for TypeScript" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-typescript-find-references-enable t + "Enable find-references for TypeScript" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-typescript-definitions-enable t + "Enable go to definition for TypeScript" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-typescript-code-actions-enable t + "Enable code actions for TypeScript" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-typescript-selection-range-enable t + "Enable selection range for TypeScript" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-typescript-signature-help-enable t + "Enable signature help (parameter hints) for TypeScript" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-typescript-rename-enable t + "Enable rename functionality for JS/TS variables inside Svelte files" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-css-enable t + "Enable the CSS plugin" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-css-globals "" + "Which css files should be checked for global variables +(`--global-var: value;`). + +These variables are added to the css completions. String of comma-separated +file paths or globs relative to workspace root." + :type 'string + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-css-diagnostics-enable t + "Enable diagnostic messages for CSS" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-css-hover-enable t + "Enable hover info for CSS" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-css-completions-enable t + "Enable auto completions for CSS" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-css-completions-emmet t + "Enable emmet auto completions for CSS" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-css-document-colors-enable t + "Enable document colors for CSS" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-css-color-presentations-enable t + "Enable color picker for CSS" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-css-document-symbols-enable t + "Enable document symbols for CSS" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-css-selection-range-enable t + "Enable selection range for CSS" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-html-enable t + "Enable the HTML plugin" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-html-hover-enable t + "Enable hover info for HTML" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-html-completions-enable t + "Enable auto completions for HTML" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-html-completions-emmet t + "Enable emmet auto completions for HTML" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-html-tag-complete-enable t + "Enable HTML tag auto closing" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-html-document-symbols-enable t + "Enable document symbols for HTML" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-svelte-enable t + "Enable the Svelte plugin" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-svelte-diagnostics-enable t + "Enable diagnostic messages for Svelte" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-svelte-compiler-warnings nil + "Svelte compiler warning codes to ignore or to treat as errors. +Example: '((css-unused-selector . ignore) (unused-export-let . error))" + :type '(alist :key-type (symbol :tag "Warning code") + :value-type (choice + (const :tag "Ignore" ignore) + (const :tag "Treat as error" error))) + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-svelte-format-enable t + "Enable formatting for Svelte (includes css & js)" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-svelte-completions-enable t + "Enable auto completions for Svelte" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-svelte-hover-enable t + "Enable hover information for Svelte" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-svelte-code-actions-enable t + "Enable Code Actions for Svelte" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-svelte-selection-range-enable t + "Enable selection range for Svelte" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(defcustom lsp-svelte-plugin-svelte-rename-enable t + "Enable rename/move Svelte files functionality" + :type 'boolean + :package-version '(lsp-mode . "7.1.0")) + +(lsp-register-custom-settings + '(("svelte.plugin.svelte.rename.enable" lsp-svelte-plugin-svelte-rename-enable t) + ("svelte.plugin.svelte.selectionRange.enable" lsp-svelte-plugin-svelte-selection-range-enable t) + ("svelte.plugin.svelte.codeActions.enable" lsp-svelte-plugin-svelte-code-actions-enable t) + ("svelte.plugin.svelte.hover.enable" lsp-svelte-plugin-svelte-hover-enable t) + ("svelte.plugin.svelte.completions.enable" lsp-svelte-plugin-svelte-completions-enable t) + ("svelte.plugin.svelte.format.enable" lsp-svelte-plugin-svelte-format-enable t) + ("svelte.plugin.svelte.compilerWarnings" lsp-svelte-plugin-svelte-compiler-warnings) + ("svelte.plugin.svelte.diagnostics.enable" lsp-svelte-plugin-svelte-diagnostics-enable t) + ("svelte.plugin.svelte.enable" lsp-svelte-plugin-svelte-enable t) + ("svelte.plugin.html.documentSymbols.enable" lsp-svelte-plugin-html-document-symbols-enable t) + ("svelte.plugin.html.tagComplete.enable" lsp-svelte-plugin-html-tag-complete-enable t) + ("svelte.plugin.html.completions.emmet" lsp-svelte-plugin-html-completions-emmet t) + ("svelte.plugin.html.completions.enable" lsp-svelte-plugin-html-completions-enable t) + ("svelte.plugin.html.hover.enable" lsp-svelte-plugin-html-hover-enable t) + ("svelte.plugin.html.enable" lsp-svelte-plugin-html-enable t) + ("svelte.plugin.css.selectionRange.enable" lsp-svelte-plugin-css-selection-range-enable t) + ("svelte.plugin.css.documentSymbols.enable" lsp-svelte-plugin-css-document-symbols-enable t) + ("svelte.plugin.css.colorPresentations.enable" lsp-svelte-plugin-css-color-presentations-enable t) + ("svelte.plugin.css.documentColors.enable" lsp-svelte-plugin-css-document-colors-enable t) + ("svelte.plugin.css.completions.emmet" lsp-svelte-plugin-css-completions-emmet t) + ("svelte.plugin.css.completions.enable" lsp-svelte-plugin-css-completions-enable t) + ("svelte.plugin.css.hover.enable" lsp-svelte-plugin-css-hover-enable t) + ("svelte.plugin.css.diagnostics.enable" lsp-svelte-plugin-css-diagnostics-enable t) + ("svelte.plugin.css.globals" lsp-svelte-plugin-css-globals) + ("svelte.plugin.css.enable" lsp-svelte-plugin-css-enable t) + ("svelte.plugin.typescript.rename.enable" lsp-svelte-plugin-typescript-rename-enable t) + ("svelte.plugin.typescript.signatureHelp.enable" lsp-svelte-plugin-typescript-signature-help-enable t) + ("svelte.plugin.typescript.selectionRange.enable" lsp-svelte-plugin-typescript-selection-range-enable t) + ("svelte.plugin.typescript.codeActions.enable" lsp-svelte-plugin-typescript-code-actions-enable t) + ("svelte.plugin.typescript.definitions.enable" lsp-svelte-plugin-typescript-definitions-enable t) + ("svelte.plugin.typescript.findReferences.enable" lsp-svelte-plugin-typescript-find-references-enable t) + ("svelte.plugin.typescript.completions.enable" lsp-svelte-plugin-typescript-completions-enable t) + ("svelte.plugin.typescript.documentSymbols.enable" lsp-svelte-plugin-typescript-document-symbols-enable t) + ("svelte.plugin.typescript.hover.enable" lsp-svelte-plugin-typescript-hover-enable t) + ("svelte.plugin.typescript.diagnostics.enable" lsp-svelte-plugin-typescript-diagnostics-enable t) + ("svelte.plugin.typescript.enable" lsp-svelte-plugin-typescript-enable t))) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection + (lambda () + `(,(lsp-package-path 'svelte-language-server) + "--stdio"))) + :activation-fn (lambda (file-name _mode) + (string= (f-ext file-name) + "svelte")) + :initialization-options + (lambda () + (list :config (ht-get* (lsp-configuration-section "svelte.plugin") + "svelte" + "plugin") + :prettierConfig (lsp-configuration-section "prettier") + :emmetConfig (lsp-configuration-section "emmet") + :typescriptConfig: (list :typescript (lsp-configuration-section "typescript") + :javascript (lsp-configuration-section "javascript")) + :dontFilterIncompleteCompletions t)) + :server-id 'svelte-ls + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'svelte-language-server callback error-callback)) + :initialized-fn + (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration + (ht-merge (lsp-configuration-section "svelte") + (lsp-configuration-section "javascript") + (lsp-configuration-section "typescript"))) + (lsp--server-register-capability + (lsp-make-registration + :id "js/ts/id" + :method "workspace/didChangeWatchedFiles" + :register-options? (lsp-make-did-change-watched-files-registration-options + :watchers + (vector (lsp-make-file-system-watcher :glob-pattern "**/*.js") + (lsp-make-file-system-watcher :glob-pattern "**/*.ts"))))))))) + +(lsp-consistency-check lsp-svelte) + +(provide 'lsp-svelte) +;;; lsp-svelte.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-terraform.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-terraform.el new file mode 100644 index 0000000..af215f4 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-terraform.el @@ -0,0 +1,68 @@ +;;; lsp-terraform.el --- Terraform Client settings -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Ross Donaldson + +;; Author: Ross Donaldson +;; Keywords: terraform lsp + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP client for Terraform + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-terraform nil + "LSP support for Terraform, using terraform-lsp" + :group 'lsp-mode + :link '(url-link "https://github.com/juliosueiras/terraform-lsp") + :package-version `(lsp-mode . "6.2")) + +(defcustom lsp-terraform-server "terraform-lsp" + "Path to the `terraform-lsp' binary." + :group 'lsp-terraform + :risky t + :type '(choice + (file :tag "File") + (repeat string)) + :package-version `(lsp-mode . "6.2")) + +(defcustom lsp-terraform-enable-logging nil + "If non-nil, enable `terraform-ls''s native logging." + :group 'lsp-terraform + :risky t + :type 'boolean + :package-version `(lsp-mode . "6.2")) + +(defun lsp-terraform--make-launch-cmd () + (-let [base (if (stringp lsp-terraform-server) + `(,lsp-terraform-server) + lsp-terraform-server)] + (when lsp-terraform-enable-logging + (push "-enable-log-file" base)) + base)) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection #'lsp-terraform--make-launch-cmd) + :major-modes '(terraform-mode) + :priority -1 + :server-id 'tfls)) + +(lsp-consistency-check lsp-terraform) + +(provide 'lsp-terraform) +;;; lsp-terraform.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-tex.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-tex.el new file mode 100644 index 0000000..3cd6d08 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-tex.el @@ -0,0 +1,68 @@ +;;; lsp-tex.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, tex + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the Tex Typesetting Language. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-tex nil + "LSP support for TeX and friends, using Digestif and texlab." + :group 'lsp-mode + :link '(url-link "https://github.com/astoff/digestif/") + :link '(url-link "https://github.com/latex-lsp/texlab")) + +(defcustom lsp-tex-server 'texlab + "Choose LSP tex server." + :type '(choice (const :tag "texlab" texlab) + (const :tag "digestif" digestif)) + :group 'lsp-tex) + +(defcustom lsp-clients-digestif-executable "digestif" + "Command to start the Digestif language server." + :group 'lsp-tex + :risky t + :type 'file) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection lsp-clients-digestif-executable) + :major-modes '(plain-tex-mode latex-mode context-mode texinfo-mode) + :priority (if (eq lsp-tex-server 'digestif) 1 -1) + :server-id 'digestif)) + +(defcustom lsp-clients-texlab-executable "texlab" + "Command to start the texlab language server." + :group 'lsp-tex + :risky t + :type 'file) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection lsp-clients-texlab-executable) + :major-modes '(plain-tex-mode latex-mode) + :priority (if (eq lsp-tex-server 'texlab) 1 -1) + :server-id 'texlab)) + +(lsp-consistency-check lsp-tex) + +(provide 'lsp-tex) +;;; lsp-tex.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-v.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-v.el new file mode 100644 index 0000000..a809a07 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-v.el @@ -0,0 +1,50 @@ +;;; lsp-v.el --- lsp-mode V integration -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 remimimimi + +;; Author: remimimimi +;; Keywords: languages,tools + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; client for vls, the V language server + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-v nil + "LSP support for V via vls." + :group 'lsp-mode + :link '(url-link "https://github.com/vlang/vls/tree/master")) + +(defcustom lsp-v-vls-executable "vls" + "The vls executable to use. +Leave as just the executable name to use the default behavior of +finding the executable with variable `exec-path'." + :group 'lsp-v + :type 'string) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection (lambda () lsp-v-vls-executable)) + :activation-fn (lsp-activate-on "V") + :server-id 'v-ls)) + +(lsp-consistency-check lsp-v) + +(provide 'lsp-v) +;;; lsp-v.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-vala.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-vala.el new file mode 100644 index 0000000..98f4e16 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-vala.el @@ -0,0 +1,51 @@ +;;; lsp-vala.el --- Vala Client settings -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Daniel Svensson + +;; Author: Daniel Svensson +;; Keywords: vala lsp + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP client for Vala + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-vala nil + "LSP support for Vala, using vala-language-server" + :group 'lsp-mode + :link '(url-link "https://github.com/benwaffle/vala-language-server") + :package-version `(lsp-mode . "7.1.0")) + +(defcustom lsp-clients-vala-ls-executable "vala-language-server" + "Path to the `vala-language-server' binary." + :group 'lsp-vala + :risky t + :type 'file + :package-version `(lsp-mode . "7.1.0")) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection (lambda () lsp-clients-vala-ls-executable)) + :major-modes '(vala-mode) + :priority -1 + :server-id 'valals)) + +(lsp-consistency-check lsp-vala) + +(provide 'lsp-vala) +;;; lsp-vala.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-verilog.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-verilog.el new file mode 100644 index 0000000..56df709 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-verilog.el @@ -0,0 +1,186 @@ +;;; lsp-verilog.el --- Verilog Client settings -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Patrick Grogan + +;; Author: Patrick Grogan <pogrogan@gmail.com> +;; Created: 7 December 2019 +;; Keywords: languages, lsp, verilog + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: +;; LSP client support for Verilog/SystemVerilog. Two language servers +;; are available: +;; 1) HDL Checker. See https://github.com/suoto/hdl_checker +;; 2) SVLangserver. See https://github.com/imc-trading/svlangserver +;; +;; This file is based on the lsp-vhdl.el file. +;; + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-svlangserver nil + "Settings for the SystemVerilog language server client." + :group 'lsp-mode + :link '(url-link "https://github.com/imc-trading/svlangserver") + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-clients-svlangserver-includeIndexing '["**/*.{sv,svh}"] + "Files included for indexing (glob pattern)" + :group 'lsp-svlangserver + :type '(lsp-repeatable-vector string) + :safe (lambda (x) (seq-every-p #'stringp x))) + +(defcustom lsp-clients-svlangserver-excludeIndexing '["test/**/*.{sv,svh}"] + "Files excluded for indexing (glob pattern)" + :group 'lsp-svlangserver + :type '(lsp-repeatable-vector string) + :safe (lambda (x) (seq-every-p #'stringp x))) + +(defcustom lsp-clients-svlangserver-defines nil + "Defines needed for linting" + :group 'lsp-svlangserver + :type '(lsp-repeatable-vector string) + :safe (lambda (x) (seq-every-p #'stringp x))) + +(defcustom lsp-clients-svlangserver-launchConfiguration "verilator -sv --lint-only -Wall" + "Verilator command used for linting" + :group 'lsp-svlangserver + :type 'string + :safe (lambda (x) (stringp x))) + +(defcustom lsp-clients-svlangserver-lintOnUnsaved t + "Enable linting on unsaved files" + :group 'lsp-svlangserver + :type 'boolean + :safe (lambda (x) (booleanp x))) + +(defcustom lsp-clients-svlangserver-formatCommand "verible-verilog-format" + "Verible verilog format command" + :group 'lsp-svlangserver + :type 'string + :safe (lambda (x) (stringp x))) + +(defcustom lsp-clients-svlangserver-disableCompletionProvider nil + "Disable auto completion provided by the language server" + :group 'lsp-svlangserver + :type 'boolean + :safe (lambda (x) (booleanp x))) + +(defcustom lsp-clients-svlangserver-disableHoverProvider nil + "Disable hover over help provided by the language server" + :group 'lsp-svlangserver + :type 'boolean + :safe (lambda (x) (booleanp x))) + +(defcustom lsp-clients-svlangserver-disableSignatureHelpProvider nil + "Disable signature help provided by the language server" + :group 'lsp-svlangserver + :type 'boolean + :safe (lambda (x) (booleanp x))) + +(defcustom lsp-clients-svlangserver-disableLinting nil + "Disable verilator linting" + :group 'lsp-svlangserver + :type 'boolean + :safe (lambda (x) (booleanp x))) + +(defcustom lsp-clients-svlangserver-workspace-additional-dirs nil + "Additional directories to be managed by this instance of svlangserver" + :group 'lsp-svlangserver + :type '(lsp-repeatable-vector string) + :safe (lambda (x) (seq-every-p #'stringp x))) + +(defcustom lsp-clients-svlangserver-bin-path "svlangserver" + "svlangserver binary path" + :group 'lsp-svlangserver + :type 'string + :safe (lambda (x) (stringp x))) + +(defcustom lsp-clients-svlangserver-bin-args nil + "command line arguments for svlangserver binary" + :group 'lsp-svlangserver + :type '(lsp-repeatable-vector string) + :safe (lambda (x) (seq-every-p #'stringp x))) + +(defcustom lsp-clients-svlangserver-node-command "node" + "node binary path" + :group 'lsp-svlangserver + :type 'string + :safe (lambda (x) (stringp x))) + +(defcustom lsp-clients-svlangserver-module-path "svlangserver.js" + "svlangserver module path" + :group 'lsp-svlangserver + :type 'string + :safe (lambda (x) (stringp x))) + +(lsp-dependency 'svlangserver + '(:system "svlangserver")) + +(defun lsp-clients-svlangserver-get-workspace-additional-dirs (_workspace) + lsp-clients-svlangserver-workspace-additional-dirs) + +(defun lsp-clients-svlangserver-command () + (let ((svlangserver-bin-path (lsp-package-path 'svlangserver))) + (if svlangserver-bin-path + (cons svlangserver-bin-path lsp-clients-svlangserver-bin-args) + (if (file-exists-p lsp-clients-svlangserver-bin-path) + (cons lsp-clients-svlangserver-bin-path lsp-clients-svlangserver-bin-args) + (if (file-exists-p lsp-clients-svlangserver-module-path) + `(,lsp-clients-svlangserver-node-command ,lsp-clients-svlangserver-module-path ,"--stdio") + `(,"svlangserver")))))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection 'lsp-clients-svlangserver-command) + :major-modes '(verilog-mode) + :priority -1 + :library-folders-fn 'lsp-clients-svlangserver-get-workspace-additional-dirs + :server-id 'svlangserver)) + +(lsp-register-custom-settings '(("systemverilog.includeIndexing" lsp-clients-svlangserver-includeIndexing) + ("systemverilog.excludeIndexing" lsp-clients-svlangserver-excludeIndexing) + ("systemverilog.defines" lsp-clients-svlangserver-defines) + ("systemverilog.launchConfiguration" lsp-clients-svlangserver-launchConfiguration) + ("systemverilog.lintOnUnsaved" lsp-clients-svlangserver-lintOnUnsaved) + ("systemverilog.formatCommand" lsp-clients-svlangserver-formatCommand) + ("systemverilog.disableCompletionProvider" lsp-clients-svlangserver-disableCompletionProvider) + ("systemverilog.disableHoverProvider" lsp-clients-svlangserver-disableHoverProvider) + ("systemverilog.disableSignatureHelpProvider" lsp-clients-svlangserver-disableSignatureHelpProvider) + ("systemverilog.disableLinting" lsp-clients-svlangserver-disableLinting))) + +(defgroup lsp-verilog nil + "LSP support for Verilog/SystemVerilog." + :group 'lsp-mode + :link '(url-link "https://github.com/suoto/hdl_checker")) + +(defcustom lsp-clients-verilog-executable '("hdl_checker" "--lsp") + "Command to start the hdl_checker language server." + :group 'lsp-verilog + :risky t + :type 'file) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection lsp-clients-verilog-executable) + :major-modes '(verilog-mode) + :language-id "verilog" + :priority -2 + :server-id 'lsp-verilog)) + +(lsp-consistency-check lsp-verilog) + +(provide 'lsp-verilog) +;;; lsp-verilog.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-vetur.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-vetur.el new file mode 100644 index 0000000..f23c539 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-vetur.el @@ -0,0 +1,869 @@ +;;; lsp-vetur.el --- vls configuration -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Ivan Yonchovski + +;; Author: Ivan Yonchovski <yyoncho@gmail.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; VLS configuration + +;;; Code: + +(require 'lsp-mode) +(require 'lsp-html) + +(defgroup lsp-vetur nil + "LSP support for Vue, using the Vue Language Server." + :group 'lsp-mode + :link '(url-link "https://github.com/vuejs/vetur/tree/master/server") + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-use-workspace-dependencies nil + "Use dependencies from workspace. Currently only for +TypeScript." + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-completion-auto-import t + "Include completion for module export and auto import them" + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-completion-use-scaffold-snippets t + "Enable/disable Vetur's built-in scaffolding snippets" + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-completion-tag-casing "kebab" + "Casing conversion for tag completion" + :type '(choice + (const "initial") + (const "kebab")) + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-grammar-custom-blocks '((docs . "md") (i18n . "json")) + "Mapping from custom block tag name to language name. Used for + generating grammar to support syntax highlighting for custom + blocks." + :type 'alist + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-validation-template t + "Validate vue-html in <template> using eslint-plugin-vue" + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-language-features-code-actions t + "Enable/disable code actions." + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-vetur-validation-style t + "Validate css/scss/less/postcss in <style>" + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-validation-script t + "Validate js/ts in <script>" + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-format-enable t + "Enable/disable the Vetur document formatter." + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-format-options-tab-size 2 + "Number of spaces per indentation level. Inherited by all formatters." + :type 'number + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-format-options-use-tabs nil + "Use tabs for indentation. Inherited by all formatters." + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-format-default-formatter-html "prettyhtml" + "Default formatter for <template> region" + :type '(choice + (const "none") + (const "prettyhtml") + (const "js-beautify-html") + (const "prettier")) + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-format-default-formatter-css "prettier" + "Default formatter for <style> region" + :type '(choice + (const "none") + (const "prettier")) + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-format-default-formatter-postcss "prettier" + "Default formatter for <style lang='postcss'> region" + :type '(choice + (const "none") + (const "prettier")) + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-format-default-formatter-scss "prettier" + "Default formatter for <style lang='scss'> region" + :type '(choice + (const "none") + (const "prettier")) + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-format-default-formatter-less "prettier" + "Default formatter for <style lang='less'> region" + :type '(choice + (const "none") + (const "prettier")) + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-format-default-formatter-stylus "stylus-supremacy" + "Default formatter for <style lang='stylus'> region" + :type '(choice + (const "none") + (const "stylus-supremacy")) + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-format-default-formatter-js "prettier" + "Default formatter for <script> region" + :type '(choice + (const "none") + (const "prettier") + (const "prettier-eslint") + (const "vscode-typescript")) + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-format-default-formatter-ts "prettier" + "Default formatter for <script> region" + :type '(choice + (const "none") + (const "prettier") + (const "vscode-typescript")) + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-format-default-formatter-options + '((js-beautify-html (wrap_attributes . "force-expand-multiline")) + (prettyhtml (printWidth . 100) + (singleQuote . :json-false) + (wrapAttributes . :json-false) + (sortAttributes . :json-false))) + "Options for all default formatters" + :type 'alist + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-format-style-initial-indent nil + "Whether to have initial indent for <style> region" + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-format-script-initial-indent nil + "Whether to have initial indent for <script> region" + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-trace-server "off" + "Traces the communication between VS Code and Vue Language Server." + :type '(choice + (const "off") + (const "messages") + (const "verbose")) + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-dev-vls-path "" + "The vls path for development" + :type 'string + :group 'lsp-vetur + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-vetur-dev-vls-port -1 + "The vls port for development" + :type 'integer + :group 'lsp-vetur + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-vetur-dev-log-level "INFO" + "The vls log level for development" + :type '(choice + (const "INFO") + (const "DEBUG")) + :group 'lsp-vetur + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-vetur-experimental-template-interpolation-service nil + "Whether to have template interpolation service" + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.3")) + +(defcustom lsp-typescript-tsdk nil + "Specifies the folder path containing the tsserver and +lib*.d.ts files to use." + :type '(repeat string) + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-disable-automatic-type-acquisition nil + "Disables automatic type acquisition. Automatic type +acquisition fetches `@types` packages from npm to improve +IntelliSense for external libraries." + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-npm nil + "Specifies the path to the NPM executable used for Automatic +Type Acquisition. Requires using TypeScript 2.3.4 or newer in the +workspace." + :type '(repeat string) + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-check-npm-is-installed t + "Check if NPM is installed for Automatic Type Acquisition." + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-references-code-lens-enabled nil + "Enable/disable references CodeLens in JavaScript files." + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-references-code-lens-enabled nil + "Enable/disable references CodeLens in TypeScript files." + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-implementations-code-lens-enabled nil + "Enable/disable implementations CodeLens. This CodeLens shows +the implementers of an interface." + :type 'boolean + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-tsserver-log "off" + "Enables logging of the TS server to a file. This log can be +used to diagnose TS Server issues. The log may contain file +paths, source code, and other potentially sensitive information +from your project." + :type '(choice + (const "off") + (const "terse") + (const "normal") + (const "verbose")) + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-tsserver-plugin-paths nil + "Additional paths to discover Typescript Language Service +plugins. Requires using TypeScript 2.3.0 or newer in the +workspace." + :type '(repeat string) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-tsserver-trace "off" + "Enables tracing of messages sent to the TS server. This trace +can be used to diagnose TS Server issues. The trace may contain +file paths, source code, and other potentially sensitive +information from your project." + :type '(choice + (const "off") + (const "messages") + (const "verbose")) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-suggest-complete-function-calls nil + "Complete functions with their parameter signature." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-suggest-complete-function-calls nil + "Complete functions with their parameter signature." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-report-style-checks-as-warnings t + "Report style checks as warnings." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-validate-enable t + "Enable/disable TypeScript validation." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-enable t + "Enable/disable default TypeScript formatter." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-insert-space-after-comma-delimiter t + "Defines space handling after a comma delimiter." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-insert-space-after-constructor nil + "Defines space handling after the constructor keyword. Requires +using TypeScript 2.3.0 or newer in the workspace." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-insert-space-after-semicolon-in-for-statements t + "Defines space handling after a semicolon in a for statement." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-insert-space-before-and-after-binary-operators t + "Defines space handling after a binary operator." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-insert-space-after-keywords-in-control-flow-statements t + "Defines space handling after keywords in a control flow +statement." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-insert-space-after-function-keyword-for-anonymous-functions t + "Defines space handling after function keyword for anonymous +functions." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-insert-space-before-function-parenthesis nil + "Defines space handling before function argument parentheses." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-insert-space-after-opening-and-before-closing-nonempty-parenthesis nil + "Defines space handling after opening and before closing +non-empty parenthesis." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-insert-space-after-opening-and-before-closing-nonempty-brackets nil + "Defines space handling after opening and before closing +non-empty brackets." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-insert-space-after-opening-and-before-closing-nonempty-braces t + "Defines space handling after opening and before closing +non-empty braces. Requires using TypeScript 2.3.0 or newer in the +workspace." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-insert-space-after-opening-and-before-closing-template-string-braces nil + "Defines space handling after opening and before closing +template string braces." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-insert-space-after-opening-and-before-closing-jsx-expression-braces nil + "Defines space handling after opening and before closing JSX +expression braces." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-insert-space-after-type-assertion nil + "Defines space handling after type assertions in TypeScript. +Requires using TypeScript 2.4 or newer in the workspace." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-place-open-brace-on-new-line-for-functions nil + "Defines whether an open brace is put onto a new line for +functions or not." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-format-place-open-brace-on-new-line-for-control-blocks nil + "Defines whether an open brace is put onto a new line for +control blocks or not." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-validate-enable t + "Enable/disable JavaScript validation." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-format-enable t + "Enable/disable default JavaScript formatter." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-format-insert-space-after-comma-delimiter t + "Defines space handling after a comma delimiter." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-format-insert-space-after-constructor nil + "Defines space handling after the constructor keyword. Requires +using TypeScript 2.3.0 or newer in the workspace." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-format-insert-space-after-semicolon-in-for-statements t + "Defines space handling after a semicolon in a for statement." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-format-insert-space-before-and-after-binary-operators t + "Defines space handling after a binary operator." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-format-insert-space-after-keywords-in-control-flow-statements t + "Defines space handling after keywords in a control flow +statement." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-format-insert-space-after-function-keyword-for-anonymous-functions t + "Defines space handling after function keyword for anonymous +functions." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-format-insert-space-before-function-parenthesis nil + "Defines space handling before function argument parentheses." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-format-insert-space-after-opening-and-before-closing-nonempty-parenthesis nil + "Defines space handling after opening and before closing +non-empty parenthesis." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-format-insert-space-after-opening-and-before-closing-nonempty-brackets nil + "Defines space handling after opening and before closing +non-empty brackets." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-format-insert-space-after-opening-and-before-closing-nonempty-braces t + "Defines space handling after opening and before closing +non-empty braces. Requires using TypeScript 2.3.0 or newer in the +workspace." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-format-insert-space-after-opening-and-before-closing-template-string-braces nil + "Defines space handling after opening and before closing +template string braces." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-format-insert-space-after-opening-and-before-closing-jsx-expression-braces nil + "Defines space handling after opening and before closing JSX +expression braces." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-format-place-open-brace-on-new-line-for-functions nil + "Defines whether an open brace is put onto a new line for +functions or not." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-format-place-open-brace-on-new-line-for-control-blocks nil + "Defines whether an open brace is put onto a new line for +control blocks or not." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-implicit-project-config-check-js nil + "Enable/disable semantic checking of JavaScript files. Existing +jsconfig.json or tsconfig.json files override this setting. +Requires using TypeScript 2.3.1 or newer in the workspace." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-implicit-project-config-experimental-decorators nil + nil + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-suggest-names t + "Enable/disable including unique names from the file in +JavaScript suggestions." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-tsc-auto-detect "on" + "Controls auto detection of tsc tasks." + :type '(choice + (const "on") + (const "off") + (const "build") + (const "watch")) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-suggest-paths t + "Enable/disable suggestions for paths in import statements and +require calls." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-suggest-paths t + "Enable/disable suggestions for paths in import statements and +require calls." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-suggest-auto-imports t + "Enable/disable auto import suggestions. Requires using +TypeScript 2.6.1 or newer in the workspace." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-suggest-auto-imports t + "Enable/disable auto import suggestions. Requires using +TypeScript 2.6.1 or newer in the workspace." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-suggest-complete-js-docs t + "Enable/disable suggestion to complete JSDoc comments." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-suggest-complete-js-docs t + "Enable/disable suggestion to complete JSDoc comments." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-locale nil + nil + :type '(choice + (const "de") + (const "es") + (const "en") + (const "fr") + (const "it") + (const "ja") + (const "ko") + (const "ru") + (const "zh-CN") + (const "zh-TW") + nil) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-suggestion-actions-enabled t + "Enable/disable suggestion diagnostics for JavaScript files in +the editor. Requires using TypeScript 2.8 or newer in the +workspace." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-suggestion-actions-enabled t + "Enable/disable suggestion diagnostics for TypeScript files in +the editor. Requires using TypeScript 2.8 or newer in the +workspace." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-preferences-quote-style "auto" nil + :type '(choice + (const "auto") + (const "single") + (const "double")) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-preferences-quote-style "auto" nil + :type '(choice + (const "auto") + (const "single") + (const "double")) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-preferences-import-module-specifier "auto" + "Preferred path style for auto imports." + :type '(choice + (const "auto") + (const "relative") + (const "non-relative")) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-preferences-import-module-specifier "auto" + "Infer the shortest path type." + :type '(choice + (const "auto") + (const "relative") + (const "non-relative")) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-preferences-rename-shorthand-properties t + "Enable/disable introducing aliases for object shorthand +properties during renames. Requires using TypeScript 3.4 or newer +in the workspace." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-preferences-rename-shorthand-properties t + "Enable/disable introducing aliases for object shorthand +properties during renames. Requires using TypeScript 3.4 or newer +in the workspace." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-update-imports-on-file-move-enabled "prompt" + "Enable/disable automatic updating of import paths when you +rename or move a file in VS Code. Requires using TypeScript 2.9 +or newer in the workspace." + :type '(choice + (const "prompt") + (const "always") + (const "never")) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-update-imports-on-file-move-enabled "prompt" + "Prompt on each rename." + :type '(choice + (const "prompt") + (const "always") + (const "never")) + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-auto-closing-tags t + "Enable/disable automatic closing of JSX tags. Requires using +TypeScript 3.0 or newer in the workspace." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-auto-closing-tags t + "Enable/disable automatic closing of JSX tags. Requires using +TypeScript 3.0 or newer in the workspace." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-javascript-suggest-enabled t + "Enabled/disable autocomplete suggestions." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-suggest-enabled t + "Enabled/disable autocomplete suggestions." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-typescript-surveys-enabled t + "Enabled/disable occasional surveys that help us improve VS +Code's JavaScript and TypeScript support." + :type 'boolean + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-vetur-emmet "never" + "Controls the Emmet suggestions that show up in the suggestion/completion list." + :type '(choice + (const "never") + (const "inMarkupAndStylesheetFilesOnly") + (const "always" )) + :group 'lsp-vetur + :package-version '(lsp-mode . "6.1")) + +(lsp-register-custom-settings + '(("javascript.autoClosingTags" lsp-javascript-auto-closing-tags t) + ("javascript.format.enable" lsp-javascript-format-enable t) + ("javascript.format.insertSpaceAfterCommaDelimiter" lsp-javascript-format-insert-space-after-comma-delimiter t) + ("javascript.format.insertSpaceAfterConstructor" lsp-javascript-format-insert-space-after-constructor t) + ("javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions" lsp-javascript-format-insert-space-after-function-keyword-for-anonymous-functions t) + ("javascript.format.insertSpaceAfterKeywordsInControlFlowStatements" lsp-javascript-format-insert-space-after-keywords-in-control-flow-statements t) + ("javascript.format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces" lsp-javascript-format-insert-space-after-opening-and-before-closing-jsx-expression-braces t) + ("javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces" lsp-javascript-format-insert-space-after-opening-and-before-closing-nonempty-braces t) + ("javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets" lsp-javascript-format-insert-space-after-opening-and-before-closing-nonempty-brackets t) + ("javascript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis" lsp-javascript-format-insert-space-after-opening-and-before-closing-nonempty-parenthesis t) + ("javascript.format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces" lsp-javascript-format-insert-space-after-opening-and-before-closing-template-string-braces t) + ("javascript.format.insertSpaceAfterSemicolonInForStatements" lsp-javascript-format-insert-space-after-semicolon-in-for-statements t) + ("javascript.format.insertSpaceBeforeAndAfterBinaryOperators" lsp-javascript-format-insert-space-before-and-after-binary-operators t) + ("javascript.format.insertSpaceBeforeFunctionParenthesis" lsp-javascript-format-insert-space-before-function-parenthesis t) + ("javascript.format.placeOpenBraceOnNewLineForControlBlocks" lsp-javascript-format-place-open-brace-on-new-line-for-control-blocks t) + ("javascript.format.placeOpenBraceOnNewLineForFunctions" lsp-javascript-format-place-open-brace-on-new-line-for-functions t) + ("javascript.implicitProjectConfig.checkJs" lsp-javascript-implicit-project-config-check-js t) + ("javascript.implicitProjectConfig.experimentalDecorators" lsp-javascript-implicit-project-config-experimental-decorators t) + ("javascript.preferences.importModuleSpecifier" lsp-javascript-preferences-import-module-specifier) + ("javascript.preferences.quoteStyle" lsp-javascript-preferences-quote-style) + ("javascript.preferences.renameShorthandProperties" lsp-javascript-preferences-rename-shorthand-properties t) + ("javascript.referencesCodeLens.enabled" lsp-javascript-references-code-lens-enabled t) + ("javascript.suggest.autoImports" lsp-javascript-suggest-auto-imports t) + ("javascript.suggest.completeFunctionCalls" lsp-javascript-suggest-complete-function-calls t) + ("javascript.suggest.completeJSDocs" lsp-javascript-suggest-complete-js-docs t) + ("javascript.suggest.enabled" lsp-javascript-suggest-enabled t) + ("javascript.suggest.names" lsp-javascript-suggest-names t) + ("javascript.suggest.paths" lsp-javascript-suggest-paths t) + ("javascript.suggestionActions.enabled" lsp-javascript-suggestion-actions-enabled t) + ("javascript.updateImportsOnFileMove.enabled" lsp-javascript-update-imports-on-file-move-enabled) + ("javascript.validate.enable" lsp-javascript-validate-enable t) + ("typescript.autoClosingTags" lsp-typescript-auto-closing-tags t) + ("typescript.check.npmIsInstalled" lsp-typescript-check-npm-is-installed t) + ("typescript.disableAutomaticTypeAcquisition" lsp-typescript-disable-automatic-type-acquisition t) + ("typescript.format.enable" lsp-typescript-format-enable t) + ("typescript.format.insertSpaceAfterCommaDelimiter" lsp-typescript-format-insert-space-after-comma-delimiter t) + ("typescript.format.insertSpaceAfterConstructor" lsp-typescript-format-insert-space-after-constructor t) + ("typescript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions" lsp-typescript-format-insert-space-after-function-keyword-for-anonymous-functions t) + ("typescript.format.insertSpaceAfterKeywordsInControlFlowStatements" lsp-typescript-format-insert-space-after-keywords-in-control-flow-statements t) + ("typescript.format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces" lsp-typescript-format-insert-space-after-opening-and-before-closing-jsx-expression-braces t) + ("typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces" lsp-typescript-format-insert-space-after-opening-and-before-closing-nonempty-braces t) + ("typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets" lsp-typescript-format-insert-space-after-opening-and-before-closing-nonempty-brackets t) + ("typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis" lsp-typescript-format-insert-space-after-opening-and-before-closing-nonempty-parenthesis t) + ("typescript.format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces" lsp-typescript-format-insert-space-after-opening-and-before-closing-template-string-braces t) + ("typescript.format.insertSpaceAfterSemicolonInForStatements" lsp-typescript-format-insert-space-after-semicolon-in-for-statements t) + ("typescript.format.insertSpaceAfterTypeAssertion" lsp-typescript-format-insert-space-after-type-assertion t) + ("typescript.format.insertSpaceBeforeAndAfterBinaryOperators" lsp-typescript-format-insert-space-before-and-after-binary-operators t) + ("typescript.format.insertSpaceBeforeFunctionParenthesis" lsp-typescript-format-insert-space-before-function-parenthesis t) + ("typescript.format.placeOpenBraceOnNewLineForControlBlocks" lsp-typescript-format-place-open-brace-on-new-line-for-control-blocks t) + ("typescript.format.placeOpenBraceOnNewLineForFunctions" lsp-typescript-format-place-open-brace-on-new-line-for-functions t) + ("typescript.implementationsCodeLens.enabled" lsp-typescript-implementations-code-lens-enabled t) + ("typescript.locale" lsp-typescript-locale) + ("typescript.npm" lsp-typescript-npm) + ("typescript.preferences.importModuleSpecifier" lsp-typescript-preferences-import-module-specifier) + ("typescript.preferences.quoteStyle" lsp-typescript-preferences-quote-style) + ("typescript.preferences.renameShorthandProperties" lsp-typescript-preferences-rename-shorthand-properties t) + ("typescript.referencesCodeLens.enabled" lsp-typescript-references-code-lens-enabled t) + ("typescript.reportStyleChecksAsWarnings" lsp-typescript-report-style-checks-as-warnings t) + ("typescript.suggest.autoImports" lsp-typescript-suggest-auto-imports t) + ("typescript.suggest.completeFunctionCalls" lsp-typescript-suggest-complete-function-calls t) + ("typescript.suggest.completeJSDocs" lsp-typescript-suggest-complete-js-docs t) + ("typescript.suggest.enabled" lsp-typescript-suggest-enabled t) + ("typescript.suggest.paths" lsp-typescript-suggest-paths t) + ("typescript.suggestionActions.enabled" lsp-typescript-suggestion-actions-enabled t) + ("typescript.surveys.enabled" lsp-typescript-surveys-enabled t) + ("typescript.tsc.autoDetect" lsp-typescript-tsc-auto-detect) + ("typescript.tsdk" lsp-typescript-tsdk) + ("typescript.tsserver.log" lsp-typescript-tsserver-log) + ("typescript.tsserver.pluginPaths" lsp-typescript-tsserver-plugin-paths) + ("typescript.tsserver.trace" lsp-typescript-tsserver-trace) + ("typescript.updateImportsOnFileMove.enabled" lsp-typescript-update-imports-on-file-move-enabled) + ("typescript.validate.enable" lsp-typescript-validate-enable t) + ("vetur.trace.server" lsp-vetur-trace-server) + ("vetur.format.scriptInitialIndent" lsp-vetur-format-script-initial-indent t) + ("vetur.format.styleInitialIndent" lsp-vetur-format-style-initial-indent t) + ("vetur.format.defaultFormatterOptions" lsp-vetur-format-default-formatter-options) + ("vetur.format.defaultFormatter.ts" lsp-vetur-format-default-formatter-ts) + ("vetur.format.defaultFormatter.js" lsp-vetur-format-default-formatter-js) + ("vetur.format.defaultFormatter.stylus" lsp-vetur-format-default-formatter-stylus) + ("vetur.format.defaultFormatter.less" lsp-vetur-format-default-formatter-less) + ("vetur.format.defaultFormatter.scss" lsp-vetur-format-default-formatter-scss) + ("vetur.format.defaultFormatter.postcss" lsp-vetur-format-default-formatter-postcss) + ("vetur.format.defaultFormatter.css" lsp-vetur-format-default-formatter-css) + ("vetur.format.defaultFormatter.html" lsp-vetur-format-default-formatter-html) + ("vetur.format.options.useTabs" lsp-vetur-format-options-use-tabs t) + ("vetur.format.options.tabSize" lsp-vetur-format-options-tab-size) + ("vetur.format.enable" lsp-vetur-format-enable t) + ("vetur.validation.script" lsp-vetur-validation-script t) + ("vetur.validation.style" lsp-vetur-validation-style t) + ("vetur.validation.template" lsp-vetur-validation-template t) + ("vetur.languageFeatures.codeActions" lsp-vetur-language-features-code-actions t) + ("vetur.grammar.customBlocks" lsp-vetur-grammar-custom-blocks) + ("vetur.completion.tagCasing" lsp-vetur-completion-tag-casing) + ("vetur.completion.useScaffoldSnippets" lsp-vetur-completion-use-scaffold-snippets t) + ("vetur.completion.autoImport" lsp-vetur-completion-auto-import t) + ("vetur.useWorkspaceDependencies" lsp-vetur-use-workspace-dependencies t) + ("vetur.dev.vlsPath" lsp-vetur-dev-vls-path) + ("vetur.dev.vlsPort" lsp-vetur-dev-vls-port) + ("vetur.dev.logLevel" lsp-vetur-dev-log-level) + ("vetur.experimental.templateInterpolationService" lsp-vetur-experimental-template-interpolation-service t) + ("emmet.showExpandedAbbreviation" lsp-vetur-emmet))) + +(define-obsolete-variable-alias + 'lsp-vetur-server + 'lsp-vetur-server-command + "lsp-mode 6.1") + +(defcustom lsp-vetur-global-snippets-dir (expand-file-name (locate-user-emacs-file ".snippets/vetur")) + "Path to snippets dir." + :type 'file + :risky t + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-vetur-server-command '("vls") + "Command to start vetur." + :type '(repeat string) + :risky t + :package-version '(lsp-mode . "6.1")) + +(lsp-dependency 'vetur-language-server + '(:system "vls") + '(:npm :package "vls" :path "vls")) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (lambda () + `(,(or (executable-find (cl-first lsp-vetur-server-command)) + (lsp-package-path 'vetur-language-server)) + ,@(cl-rest lsp-vetur-server-command)))) + :activation-fn (lambda (filename _mode) + (string= (file-name-extension filename) "vue")) + :priority -1 + :multi-root t + :ignore-messages '("readFile .*? requested by Vue but content not available") + :server-id 'vls + :initialization-options (lambda () (ht-merge (lsp-configuration-section "vetur") + (lsp-configuration-section "html") + (lsp-configuration-section "javascript") + (lsp-configuration-section "typescript") + (lsp-configuration-section "emmet") + (ht ("globalSnippetDir" lsp-vetur-global-snippets-dir)))) + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration + (ht-merge (lsp-configuration-section "vetur") + (lsp-configuration-section "html") + (lsp-configuration-section "javascript") + (lsp-configuration-section "emmet") + (lsp-configuration-section "typescript"))))) + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'vetur-language-server + callback error-callback)))) + +(lsp-consistency-check lsp-vetur) + +(provide 'lsp-vetur) +;;; lsp-vetur.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-vhdl.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-vhdl.el new file mode 100644 index 0000000..aa55e0e --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-vhdl.el @@ -0,0 +1,121 @@ +;;; lsp-vhdl.el --- VHDL Client settings -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Christian Birk Sørensen + +;; Author: Christian Birk Sørensen <chrbirks+emacs@gmail.com> +;; Created: 6 October 2019 +;; Keywords: languages, lsp, vhdl + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP support for VHDL using using an external language server. Currently +;; the supported servers are: +;; +;; VHDL-tool. See http://www.vhdltool.com/configuration for setting up the +;; project file. +;; +;; HDL Checker. See https://github.com/suoto/hdl_checker/wiki/setting-up-a-project +;; for setting up the project file. +;; +;; VHDL LS. See https://github.com/kraigher/rust_hdl#configuration for setting +;; up the project file. +;; +;; GHDL LS. See https://github.com/ghdl/ghdl-language-server for setting up the +;; project file. +;; +;; Set the symbol lsp-vhdl-server to select the language server and set +;; lsp-vhdl-server-path if the binary is not in the user PATH. + +;;; Code: + +(require 'lsp-mode) + +(defvar vhdl-tool-bin-name "vhdl-tool" + "Name of the VHDL Tool binary.") + +(defvar hdl-checker-bin-name "hdl_checker" + "Name of HDL Checker binary.") + +(defvar vhdl-ls-bin-name "vhdl_ls" + "Name of the VHDL LS binary.") + +(defvar ghdl-ls-bin-name "ghdl-ls" + "Name of the GHDL LS binary.") + +(defgroup lsp-vhdl nil + "LSP support for VHDL. Set lsp-vhdl-server to select server. The default is to use VHDL-tool." + :group 'lsp-mode) + +(defcustom lsp-vhdl-server 'vhdl-tool + "Select which server to use: +VHDL-tool: A syntax checking, type checking and linting tool (http://vhdltool.com). +HDL Checker: A wrapper for third party tools such as GHDL, ModelSim, Vivado Simulator (https://github.com/suoto/hdl_checker). +VHDL LS: A complete VHDL language server protocol implementation with diagnostics, navigate to symbol, find all references etc. (https://github.com/kraigher/rust_hdl)." + :type '(choice (const :tag "VHDL-tool" vhdl-tool) + (const :tag "HDL Checker" hdl-checker) + (const :tag "VHDL LS" vhdl-ls) + (const :tag "GHDL LS" ghdl-ls)) + :group 'lsp-vhdl) + +(defcustom lsp-vhdl-server-path nil + "Path to binary server file." + :group 'lsp-vhdl + :risky t + :type 'file) + +(defvar lsp-vhdl--params nil) + +(defun lsp-vhdl--create-connection () + "Returns lsp-stdio-connection based on the selected server" + (lsp-vhdl--set-server-path) + (lsp-vhdl--set-server-args) + (lsp-stdio-connection + (lambda () (cons (plist-get lsp-vhdl--params 'server-path) (plist-get lsp-vhdl--params 'server-args))) + (lambda () (executable-find (plist-get lsp-vhdl--params 'server-path))))) + +(defun lsp-vhdl--set-server-path() + "Set path to server binary based on selection in lsp-vhdl-server." + (cond ((eq lsp-vhdl-server 'hdl-checker) (if (eq lsp-vhdl-server-path nil) + (setq lsp-vhdl--params (plist-put lsp-vhdl--params 'server-path hdl-checker-bin-name)) + (setq lsp-vhdl--params (plist-put lsp-vhdl--params 'server-path lsp-vhdl-server-path)))) + ((eq lsp-vhdl-server 'vhdl-tool) (if (eq lsp-vhdl-server-path nil) + (setq lsp-vhdl--params (plist-put lsp-vhdl--params 'server-path vhdl-tool-bin-name)) + (setq lsp-vhdl--params (plist-put lsp-vhdl--params 'server-path lsp-vhdl-server-path)))) + ((eq lsp-vhdl-server 'vhdl-ls) (if (eq lsp-vhdl-server-path nil) + (setq lsp-vhdl--params (plist-put lsp-vhdl--params 'server-path vhdl-ls-bin-name)) + (setq lsp-vhdl--params (plist-put lsp-vhdl--params 'server-path lsp-vhdl-server-path)))) + ((eq lsp-vhdl-server 'ghdl-ls) (if (eq lsp-vhdl-server-path nil) + (setq lsp-vhdl--params (plist-put lsp-vhdl--params 'server-path ghdl-ls-bin-name)) + (setq lsp-vhdl--params (plist-put lsp-vhdl--params 'server-path lsp-vhdl-server-path)))))) + +(defun lsp-vhdl--set-server-args() + "Set server arguments based on server selection." + (cond ((eq lsp-vhdl-server 'hdl-checker) (setq lsp-vhdl--params (plist-put lsp-vhdl--params 'server-args '("--lsp")))) + ((eq lsp-vhdl-server 'vhdl-tool) (setq lsp-vhdl--params (plist-put lsp-vhdl--params 'server-args '("lsp")))) + ((eq lsp-vhdl-server 'vhdl-ls) (setq lsp-vhdl--params (plist-put lsp-vhdl--params 'server-args '()))) + ((eq lsp-vhdl-server 'ghdl-ls) (setq lsp-vhdl--params (plist-put lsp-vhdl--params 'server-args '()))))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-vhdl--create-connection) + :major-modes '(vhdl-mode) + :language-id "VHDL" + :priority -1 + :server-id 'lsp-vhdl)) + +(lsp-consistency-check lsp-vhdl) + +(provide 'lsp-vhdl) +;;; lsp-vhdl.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-vimscript.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-vimscript.el new file mode 100644 index 0000000..9f1fec2 --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-vimscript.el @@ -0,0 +1,75 @@ +;;; lsp-vimscript.el --- description -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 emacs-lsp maintainers + +;; Author: emacs-lsp maintainers +;; Keywords: lsp, vim, vimscript + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; LSP Clients for the VimScript Programming Language. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-vim nil + "LSP support for viml using vim-language-server." + :group 'lsp-mode + :link '(url-link "https://github.com/iamcco/vim-language-server")) + +(defcustom lsp-clients-vim-executable '("vim-language-server" "--stdio") + "Command to start the vim language server." + :group 'lsp-vim + :risky t + :type 'file) + +(defcustom lsp-clients-vim-initialization-options '((iskeyword . "vim iskeyword option") + (vimruntime . "/usr/bin/vim") + (runtimepath . "/usr/bin/vim") + (diagnostic . ((enable . t))) + (indexes . ((runtimepath . t) + (gap . 100) + (count . 3))) + (suggest . ((fromVimruntime . t) + (fromRuntimepath . :json-false)))) + "Initialization options for vim language server." + :group 'lsp-vim + :type 'alist) + +(lsp-dependency 'vim-language-server + '(:system "vim-language-server") + '(:npm :package "vim-language-server" + :path "vim-language-server")) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (lambda () + `(,(or (executable-find (cl-first lsp-clients-vim-executable)) + (lsp-package-path 'vim-language-server)) + ,@(cl-rest lsp-clients-vim-executable)))) + :major-modes '(vimrc-mode) + :priority -1 + :server-id 'vimls + :initialization-options (lambda () lsp-clients-vim-initialization-options) + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'vim-language-server + callback error-callback)))) + +(lsp-consistency-check lsp-vimscript) + +(provide 'lsp-vimscript) +;;; lsp-vimscript.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-xml.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-xml.el new file mode 100644 index 0000000..439f02f --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-xml.el @@ -0,0 +1,245 @@ +;;; lsp-xml.el --- LSP XML server integration -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Ivan Yonchovski + +;; Author: Ivan Yonchovski <yyoncho@gmail.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-xml nil + "Settings for rls." + :group 'tools + :tag "Language Server" + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-trace-server "off" + "Traces the communication between VS Code and the XML language server." + :type '(choice + (const "off") + (const "messages") + (const "verbose")) + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-catalogs nil + "Array of XML Catalogs" + :type '(repeat string) + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-logs-client t + "Should the server log to client output" + :type 'boolean + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-format-split-attributes nil + "Split multiple attributes each onto a new line" + :type 'boolean + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-format-join-cdata-lines nil + "Join lines in a CDATA tag's content" + :type 'boolean + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-format-join-comment-lines nil + "Join comment content on format" + :type 'boolean + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-format-space-before-empty-close-tag t + "Insert space before end of self closing tag. +Example: <tag/> -> <tag />" + :type 'boolean + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-format-join-content-lines nil + "Normalize the whitespace of content inside an element. +Newlines and excess whitespace are removed." + :type 'boolean + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-format-preserve-empty-content nil + "Preserve empty content/whitespace in a tag." + :type 'boolean + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-format-enabled t + "Enable/disable ability to format document" + :type 'boolean + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-format-quotations "doubleQuotes" + "Which type of quotes to use for attribute values when + formatting." + :type '(choice + (const "doubleQuotes") + (const "singleQuotes")) + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-file-associations nil + "Allows XML schemas to be associated to file name patterns. + Example: [{ \"systemId\":\"path/to/file.xsd\",\"pattern\": + \"file1.xml\" },{ \"systemId\": + \"http://www.w3.org/2001/XMLSchema.xsd\",\"pattern\": + \"**/*.xsd\" }]" + :type '(repeat string) + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-completion-auto-close-tags t + "Enable/disable autoclosing of XML tags. IMPORTANT: Turn off + editor.autoClosingTags for this to work" + :type 'boolean + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-server-vmargs ["-noverify" "-Xmx64M" "-XX:+UseG1GC" + "-XX:+UseStringDeduplication"] + "Specifies extra VM arguments used to launch the XML Language + Server. Eg. use `-noverify -Xmx1G -XX:+UseG1GC + -XX:+UseStringDeduplication` to bypass class verification, + increase the heap size to 1GB and enable String deduplication + with the G1 Garbage collector" + :type 'lsp-string-vector + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-server-work-dir (expand-file-name ".lsp4xml" "~") + "Set a custom folder path for cached XML Schemas. An absolute + path is expected, although the ~ prefix (for the user home + directory) is supported." + :type 'string + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-validation-no-grammar "hint" + "The message severity when a document has no associated + grammar." + :type '(choice (:tag "ignore" "hint" "info" "warning" "error")) + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-validation-enabled t + "Enable/disable all validation." + :type 'boolean + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-validation-resolve-external-entities nil + "Enable/disable resolution (downloading) of external entities from the internet." + :type 'boolean + :group 'lsp-xml + :package-version '(lsp-mode . "7.1")) + +(defcustom lsp-xml-validation-schema t + "Enable/disable schema based validation. Ignored if + \"xml.validation.enabled\": false." + :type 'boolean + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(lsp-register-custom-settings ' + (("xml.validation.schema" lsp-xml-validation-schema t) + ("xml.validation.resolveExternalEntities" lsp-xml-validation-resolve-external-entities) + ("xml.validation.enabled" lsp-xml-validation-enabled t) + ("xml.validation.noGrammar" lsp-xml-validation-no-grammar) + ("xml.server.workDir" lsp-xml-server-work-dir) + ("xml.server.vmargs" lsp-xml-server-vmargs) + ("xml.completion.autoCloseTags" lsp-xml-completion-auto-close-tags t) + ("xml.fileAssociations" lsp-xml-file-associations) + ("xml.format.quotations" lsp-xml-format-quotations) + ("xml.format.enabled" lsp-xml-format-enabled t) + ("xml.format.preserveEmptyContent" lsp-xml-format-preserve-empty-content t) + ("xml.format.joinContentLines" lsp-xml-format-join-content-lines t) + ("xml.format.spaceBeforeEmptyCloseTag" lsp-xml-format-space-before-empty-close-tag t) + ("xml.format.joinCommentLines" lsp-xml-format-join-comment-lines t) + ("xml.format.joinCDATALines" lsp-xml-format-join-cdata-lines t) + ("xml.format.splitAttributes" lsp-xml-format-split-attributes t) + ("xml.logs.client" lsp-xml-logs-client t) + ("xml.catalogs" lsp-xml-catalogs) + ("xml.trace.server" lsp-xml-trace-server))) + +(defconst lsp-xml-jar-version "0.13.1") + +(defconst lsp-xml-jar-name (format "org.eclipse.lemminx-%s-uber.jar" lsp-xml-jar-version)) + +(defcustom lsp-xml-jar-file (f-join lsp-server-install-dir "xmlls" lsp-xml-jar-name) + "Xml server jar command." + :type 'string + :group 'lsp-xml + :type 'file + :package-version '(lsp-mode . "6.1")) + +(defcustom lsp-xml-jar-download-url + (format + "https://repo.eclipse.org/content/repositories/lemminx-releases/org/eclipse/lemminx/org.eclipse.lemminx/%s/%s" + lsp-xml-jar-version + lsp-xml-jar-name) + "Automatic download url for lsp-xml." + :type 'string + :group 'lsp-xml + :package-version '(lsp-mode . "7.1")) + +(lsp-dependency + 'xmlls + '(:system lsp-xml-jar-file) + `(:download :url lsp-xml-jar-download-url + :store-path lsp-xml-jar-file)) + +(defcustom lsp-xml-server-command `("java" "-jar" ,lsp-xml-jar-file) + "Xml server command." + :type '(repeat string) + :group 'lsp-xml + :package-version '(lsp-mode . "6.1")) + +(defun lsp-xml--create-connection () + (lsp-stdio-connection + (lambda () lsp-xml-server-command) + (lambda () (f-exists? lsp-xml-jar-file)))) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-xml--create-connection) + :activation-fn (lsp-activate-on "xml") + :priority 0 + :server-id 'xmlls + :multi-root t + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration (lsp-configuration-section "xml")))) + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'xmlls callback error-callback)))) + +(lsp-consistency-check lsp-xml) + +(provide 'lsp-xml) +;;; lsp-xml.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-yaml.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-yaml.el new file mode 100644 index 0000000..bc7795e --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-yaml.el @@ -0,0 +1,242 @@ +;;; lsp-yaml.el --- LSP YAML server integration -*- lexical-binding: t; -*- + +;; Copyright (C) 2019 Aya Igarashi + +;; Author: Aya Igarashi <ladiclexxx@gmail.com> +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; + +;;; Code: + +(require 'lsp-mode) +(require 'dash) + +(defgroup lsp-yaml nil + "LSP support for YAML, using yaml-language-server." + :group 'lsp-mode + :link '(url-link "https://github.com/redhat-developer/yaml-language-server") + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-format-enable t + "Enable/disable default YAML formatter." + :type 'boolean + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-single-quote nil + "Use single quote instead of double quotes." + :type 'boolean + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-bracket-spacing t + "Print spaces between brackets in objects." + :type 'boolean + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-prose-wrap "preserve" + "Options for prose-wrap. + Always: wrap prose if it exceeds the print width. + Never: never wrap the prose. + Preserve: wrap prose as-is." + :type '(choice + (const "always") + (const "never") + (const "preserve")) + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-print-width 80 + "Specify the line length that the printer will wrap on." + :type 'number + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-validate t + "Enable/disable validation feature." + :type 'boolean + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-hover t + "Enable/disable hover feature." + :type 'boolean + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-completion t + "Enable/disable completion feature." + :type 'boolean + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-schemas '() + "Associate schemas to YAML files in a glob pattern." + :type '(alist :key-type (symbol :tag "schema") :value-type (lsp-string-vector :tag "files (glob)")) + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-schema-store-enable t + "Enable/disable JSON Schema store. When set to true, available YAML + schemas will be automatically pulled from the store." + :type 'boolean + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-custom-tags nil + "Custom tags for the parser to use." + :type '(lsp-repeatable-vector string) + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(defcustom lsp-yaml-schema-store-uri "https://www.schemastore.org/api/json/catalog.json" + "URL of schema store catalog to use." + :type 'string + :group 'lsp-yaml) + +(defcustom lsp-yaml-schema-store-local-db (expand-file-name + (locate-user-emacs-file + (f-join ".cache" "lsp" "lsp-yaml-schemas.json"))) + "Cached databse of schema store." + :type 'file + :group 'lsp-yaml) + +(defcustom lsp-yaml-max-items-computed 5000 + "The maximum number of outline symbols and folding regions computed. +Limited for performance reasons." + :type 'number + :group 'lsp-yaml + :package-version '(lsp-mode . "7.1")) + + +(defvar lsp-yaml--schema-store-schemas-alist nil + "A list of schemas fetched from schema stores.") + +(lsp-register-custom-settings + '(("yaml.format.enable" lsp-yaml-format-enable t) + ("yaml.format.singleQuote" lsp-yaml-single-quote t) + ("yaml.format.bracketSpacing" lsp-yaml-bracket-spacing) + ("yaml.format.proseWrap" lsp-yaml-prose-wrap) + ("yaml.format.printWidth" lsp-yaml-print-width) + ("yaml.validate" lsp-yaml-validate t) + ("yaml.hover" lsp-yaml-hover t) + ("yaml.completion" lsp-yaml-completion t) + ("yaml.schemas" lsp-yaml-schemas) + ("yaml.schemaStore.enable" lsp-yaml-schema-store-enable t) + ("yaml.schemaStore.url" lsp-yaml-schema-store-uri) + ("yaml.customTags" lsp-yaml-custom-tags) + ("yaml.maxItemsComputed" lsp-yaml-max-items-computed))) + +(defcustom lsp-yaml-server-command '("yaml-language-server" "--stdio") + "Command to start yaml-languageserver." + :type '(repeat string) + :group 'lsp-yaml + :package-version '(lsp-mode . "6.2")) + +(lsp-dependency 'yaml-language-server + '(:system "yaml-language-server") + '(:npm :package "yaml-language-server" + :path "yaml-language-server")) + +(lsp-register-client + (make-lsp-client :new-connection (lsp-stdio-connection + (lambda () + `(,(or (executable-find (cl-first lsp-yaml-server-command)) + (lsp-package-path 'yaml-language-server)) + ,@(cl-rest lsp-yaml-server-command)))) + :major-modes '(yaml-mode k8s-mode) + :priority 0 + :server-id 'yamlls + :initialized-fn (lambda (workspace) + (with-lsp-workspace workspace + (lsp--set-configuration + (lsp-configuration-section "yaml")))) + :download-server-fn (lambda (_client callback error-callback _update?) + (lsp-package-ensure 'yaml-language-server + callback error-callback)))) + +(defconst lsp-yaml--built-in-kubernetes-schema + '((name . "Kubernetes") + (description . "Built-in kubernetes manifest schema definition") + (url . "kubernetes") + (fileMatch . ["*-k8s.yaml" "*-k8s.yml"]))) + +(defun lsp-yaml-download-schema-store-db (&optional force-downloading) + "Download the remote schema store at `lsp-yaml-schema-store-uri' into local cache. +Set FORCE-DOWNLOADING to non-nil to force re-download the database." + (interactive "P") + (when (or force-downloading (not (file-exists-p lsp-yaml-schema-store-local-db))) + (unless (file-directory-p (file-name-directory lsp-yaml-schema-store-local-db)) + (mkdir (file-name-directory lsp-yaml-schema-store-local-db))) + (url-copy-file lsp-yaml-schema-store-uri lsp-yaml-schema-store-local-db force-downloading))) + +(defun lsp-yaml--get-supported-schemas () + "Get out the list of supported schemas." + (when (and lsp-yaml-schema-store-enable + (not lsp-yaml--schema-store-schemas-alist)) + (lsp-yaml-download-schema-store-db) + (setq lsp-yaml--schema-store-schemas-alist + (alist-get 'schemas (json-read-file lsp-yaml-schema-store-local-db)))) + (seq-concatenate 'list (list lsp-yaml--built-in-kubernetes-schema) lsp-yaml--schema-store-schemas-alist)) + +(defun lsp-yaml-set-buffer-schema (uri-string) + "Set yaml schema for the current buffer to URI-STRING." + (interactive "MURI: ") + (let* ((uri (intern uri-string)) + (workspace-path (file-relative-name + (lsp--uri-to-path (lsp--buffer-uri)) + (lsp-workspace-root (lsp--buffer-uri)))) + (glob (concat "/" workspace-path)) + (current-config (assoc uri lsp-yaml-schemas)) + (current-patterns (and current-config (cdr current-config)))) + (if current-config + (or (member glob (append current-patterns nil)) + (setq lsp-yaml-schemas + (cl-acons uri + (vconcat (vector glob) current-patterns) + (assq-delete-all uri + (mapcar (lambda (x) (lsp-yaml--remove-glob x glob)) + lsp-yaml-schemas))))) + (setq lsp-yaml-schemas + (cl-acons uri (vector glob) (mapcar (lambda (x) (lsp-yaml--remove-glob x glob)) + lsp-yaml-schemas)))) + (lsp--set-configuration (lsp-configuration-section "yaml")))) + +(defun lsp-yaml-select-buffer-schema () + "Select schema for the current buffer based on the list of supported schemas." + (interactive) + (let* ((schema (lsp--completing-read "Select buffer schema: " + (lsp-yaml--get-supported-schemas) + (lambda (schema) + (format "%s: %s" (alist-get 'name schema)(alist-get 'description schema))) + nil t)) + (uri (alist-get 'url schema))) + (lsp-yaml-set-buffer-schema uri))) + +(defun lsp-yaml--remove-glob (mapping glob) + (let ((patterns (cdr mapping))) + (cons (car mapping) + (vconcat (-filter (lambda (p) (not (equal p glob))) + (append patterns nil)) nil)))) + +(lsp-consistency-check lsp-yaml) + +(provide 'lsp-yaml) +;;; lsp-yaml.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp-zig.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-zig.el new file mode 100644 index 0000000..0d19acd --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp-zig.el @@ -0,0 +1,50 @@ +;;; lsp-zig.el --- lsp-mode Zig integration -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 Riccardo Binetti + +;; Author: Riccardo Binetti <rbino@gmx.com> +;; Keywords: languages,tools + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; client for zls, the Zig language server + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-zig nil + "LSP support for Zig via zls." + :group 'lsp-mode + :link '(url-link "https://github.com/zigtools/zls")) + +(defcustom lsp-zig-zls-executable "zls" + "The zls executable to use. +Leave as just the executable name to use the default behavior of +finding the executable with variable `exec-path'." + :group 'lsp-zig + :type 'string) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection (lambda () lsp-zig-zls-executable)) + :activation-fn (lsp-activate-on "zig") + :server-id 'zls)) + +(lsp-consistency-check lsp-zig) + +(provide 'lsp-zig) +;;; lsp-zig.el ends here diff --git a/emacs.d/elpa/lsp-mode-20210716.2233/lsp.el b/emacs.d/elpa/lsp-mode-20210716.2233/lsp.el new file mode 100644 index 0000000..e4f4b5d --- /dev/null +++ b/emacs.d/elpa/lsp-mode-20210716.2233/lsp.el @@ -0,0 +1,8 @@ +;; The code was moved into lsp-mode.el. This file is kept only for backward compatibility. +(require 'lsp-mode) + +;; (warn "Replace (require 'lsp) with (require 'lsp-mode)") + +(provide 'lsp) + +;;; lsp.el ends here diff --git a/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-autoloads.el b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-autoloads.el new file mode 100644 index 0000000..bf3c8cc --- /dev/null +++ b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-autoloads.el @@ -0,0 +1,80 @@ +;;; lsp-ui-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "lsp-ui" "lsp-ui.el" (0 0 0 0)) +;;; Generated autoloads from lsp-ui.el + +(autoload 'lsp-ui-mode "lsp-ui" "\ +Toggle language server UI mode on or off. +‘lsp-ui-mode’ is a minor mode that contains a series of useful UI +integrations for ‘lsp-mode’. With a prefix argument ARG, enable +language server UI mode if ARG is positive, and disable it +otherwise. If called from Lisp, enable the mode if ARG is +omitted or nil, and toggle it if ARG is ‘toggle’. + +\(fn &optional ARG)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-ui" '("lsp-ui-"))) + +;;;*** + +;;;### (autoloads nil "lsp-ui-doc" "lsp-ui-doc.el" (0 0 0 0)) +;;; Generated autoloads from lsp-ui-doc.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-ui-doc" '("lsp-ui-doc-"))) + +;;;*** + +;;;### (autoloads nil "lsp-ui-flycheck" "lsp-ui-flycheck.el" (0 0 +;;;;;; 0 0)) +;;; Generated autoloads from lsp-ui-flycheck.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-ui-flycheck" '("lsp-ui-flycheck-"))) + +;;;*** + +;;;### (autoloads nil "lsp-ui-imenu" "lsp-ui-imenu.el" (0 0 0 0)) +;;; Generated autoloads from lsp-ui-imenu.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-ui-imenu" '("lsp-ui-imenu"))) + +;;;*** + +;;;### (autoloads nil "lsp-ui-peek" "lsp-ui-peek.el" (0 0 0 0)) +;;; Generated autoloads from lsp-ui-peek.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-ui-peek" '("lsp-"))) + +;;;*** + +;;;### (autoloads nil "lsp-ui-sideline" "lsp-ui-sideline.el" (0 0 +;;;;;; 0 0)) +;;; Generated autoloads from lsp-ui-sideline.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-ui-sideline" '("lsp-ui-sideline"))) + +;;;*** + +;;;### (autoloads nil "lsp-ui-util" "lsp-ui-util.el" (0 0 0 0)) +;;; Generated autoloads from lsp-ui-util.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lsp-ui-util" '("lsp-ui-util-"))) + +;;;*** + +;;;### (autoloads nil nil ("lsp-ui-pkg.el") (0 0 0 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; lsp-ui-autoloads.el ends here diff --git a/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-doc.el b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-doc.el new file mode 100644 index 0000000..8ba7ce7 --- /dev/null +++ b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-doc.el @@ -0,0 +1,1195 @@ +;;; lsp-ui-doc.el --- Lsp-Ui-Doc -*- lexical-binding: t -*- + +;; Copyright (C) 2017 Sebastien Chapuis + +;; Author: Sebastien Chapuis <sebastien@chapu.is> +;; URL: https://github.com/emacs-lsp/lsp-ui +;; Keywords: languagues, tools +;; Version: 6.2 + +;;; License +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. + +;;; Commentary: +;; +;; Show documentation of the symbol at point in a child frame + +;;; Code: + +(require 'lsp-ui-util) + +(require 'lsp-protocol) +(require 'lsp-mode) +(require 'dash) +(require 'goto-addr) +(require 'markdown-mode) + +(require 'cl-lib) +(require 'face-remap) +(require 'subr-x) + +(when (featurep 'xwidget-internal) + (require 'xwidget)) + +(declare-function make-xwidget "ext:xwidget" (type title width height arguments &optional buffer)) +(declare-function set-xwidget-query-on-exit-flag "ext:xwidget") +(declare-function xwidget-webkit-mode "ext:xwidget") +(declare-function xwidget-webkit-goto-uri "ext:xwidget" (xwidget uri)) +(declare-function xwidget-at "ext:xwidget" (pos)) +(declare-function xwidget-webkit-execute-script "ext:xwidget" (xwidget script &optional callback)) +(declare-function xwidget-webkit-execute-script-rv "ext:xwidget" (xwidget script &optional default)) +(declare-function xwidget-resize "ext:xwidget" (xwidget new-width new-height)) + +(defgroup lsp-ui-doc nil + "Display informations of the current line." + :group 'tools + :group 'convenience + :group 'lsp-ui + :link '(custom-manual "(lsp-ui-doc) Top") + :link '(info-link "(lsp-ui-doc) Customizing")) + +(defcustom lsp-ui-doc-enable t + "Whether or not to enable lsp-ui-doc." + :type 'boolean + :group 'lsp-ui) + +(defcustom lsp-ui-doc-show-with-mouse t + "Move the mouse pointer over a symbol to show its documentation." + :type 'boolean + :group 'lsp-ui-doc) + +(defcustom lsp-ui-doc-show-with-cursor t + "Move the cursor over a symbol to show its documentation." + :type 'boolean + :group 'lsp-ui-doc) + +(defcustom lsp-ui-doc-header nil + "Whether or not to enable the header which display the symbol string." + :type 'boolean + :group 'lsp-ui-doc) + +(defcustom lsp-ui-doc-include-signature nil + "Whether or not to include the object signature/type in the frame." + :type 'boolean + :group 'lsp-ui-doc) + +(defcustom lsp-ui-doc-position 'top + "Where to display the doc when moving the point cursor. +This affect the position of the documentation when `lsp-ui-doc-show-with-cursor' +is non-nil." + :type '(choice (const :tag "Top" top) + (const :tag "Bottom" bottom) + (const :tag "At point" at-point)) + :group 'lsp-ui-doc) + +(defcustom lsp-ui-doc-alignment 'frame + "How to align the doc. +This only takes effect when `lsp-ui-doc-position' is 'top or 'bottom." + :type '(choice (const :tag "Frame" frame) + (const :tag "Window" window)) + :group 'lsp-ui-doc) + +(defcustom lsp-ui-doc-border "white" + "Border color of the frame." + :type 'color + :group 'lsp-ui-doc) + +(defcustom lsp-ui-doc-max-width 150 + "Maximum number of columns of the frame." + :type 'integer + :group 'lsp-ui-doc) + +(defcustom lsp-ui-doc-max-height 13 + "Maximum number of lines in the frame." + :type 'integer + :group 'lsp-ui-doc) + +(defcustom lsp-ui-doc-use-childframe t + "Whether to display documentation in a child-frame or the current frame. +Child frames requires GNU/Emacs version >= 26 and graphical frames." + :type 'boolean + :group 'lsp-ui-doc) + +(defcustom lsp-ui-doc-use-webkit nil + "Whether to display documentation in a WebKit widget in a child-frame. +This requires GNU/Emacs version >= 26 and built with the `--with-xwidgets` +option." + :type 'boolean + :group 'lsp-ui-doc) + +(defcustom lsp-ui-doc-delay 0.2 + "Number of seconds before showing the doc." + :type 'number + :group 'lsp-ui-doc) + +(defcustom lsp-ui-doc-winum-ignore t + "Whether to ignore lsp-ui-doc buffers in winum." + :type 'boolean + :group 'lsp-ui-doc) + +(defcustom lsp-ui-doc-text-scale-level 0 + "Text scale amount for doc buffer." + :type 'integer + :group 'lsp-ui-doc) + +(defface lsp-ui-doc-background + '((((background light)) :background "#b3b3b3") + (t :background "#272A36")) + "Background color of the documentation. +Only the `background' is used in this face." + :group 'lsp-ui-doc) + +(defface lsp-ui-doc-header + '((t :foreground "black" + :background "deep sky blue")) + "Face used on the header." + :group 'lsp-ui-doc) + +(defface lsp-ui-doc-highlight-hover + '((t :inherit region)) + "Face used to highlight the hover symbol/region when using mouse." + :group 'lsp-ui-doc) + +(defface lsp-ui-doc-url + '((t :inherit link)) + "Face used on links." + :group 'lsp-ui-doc) + +(defvar lsp-ui-doc-frame-parameters + '((left . -1) + (no-focus-on-map . t) + (min-width . 0) + (width . 0) + (min-height . 0) + (height . 0) + (internal-border-width . 1) + (vertical-scroll-bars . nil) + (horizontal-scroll-bars . nil) + (right-fringe . 0) + (menu-bar-lines . 0) + (tool-bar-lines . 0) + (line-spacing . 0) + (unsplittable . t) + (undecorated . t) + (top . -1) + (visibility . nil) + (mouse-wheel-frame . nil) + (no-other-frame . t) + (inhibit-double-buffering . t) + (drag-internal-border . t) + (no-special-glyphs . t) + (desktop-dont-save . t)) + "Frame parameters used to create the frame.") + +(defvar lsp-ui-doc-render-function nil + "Function called to format the documentation. +The function takes a string as parameter and should return a string. +If this variable is nil (the default), the documentation will be rendered +as markdown.") + +(defvar lsp-ui-doc-frame-hook nil + "Hooks run on child-frame creation. +The functions receive 2 parameters: the frame and its window.") + +(defvar lsp-ui-doc-webkit-client-path + (concat "file://" + (file-name-directory (or load-file-name buffer-file-name)) + "lsp-ui-doc.html") + "Path to the page loaded when a WebKit widget is created.") + +;; Avoid warning with emacs < 26 +(declare-function display-buffer-in-child-frame "window.el") + +(defvar-local lsp-ui-doc--parent-vars nil + "Variables from the parents frame that we want to access in the child. +Because some variables are buffer local.") + +(defvar-local lsp-ui-doc--inline-ov nil + "Overlay used to display the documentation in the buffer.") + +(defvar-local lsp-ui-doc--highlight-ov nil + "Overlay used to highlight the hover symbol.") + +(defvar-local lsp-ui-doc--bounds nil) +(defvar-local lsp-ui-doc--timer nil) +(defvar-local lsp-ui-doc--from-mouse nil + "Non nil when the doc was triggered by a mouse event.") +(defvar-local lsp-ui-doc--from-mouse-current nil + "Non nil when the current call is triggered by a mouse event") + +(defconst lsp-ui-doc--buffer-prefix " *lsp-ui-doc-") + +(defmacro lsp-ui-doc--with-buffer (&rest body) + "Execute BODY in the lsp-ui-doc buffer." + (declare (indent 0) (debug t)) + `(let ((parent-vars (list :buffer (current-buffer) + :window (get-buffer-window))) + (buffer-list-update-hook nil)) + (with-current-buffer (get-buffer-create (lsp-ui-doc--make-buffer-name)) + (setq lsp-ui-doc--parent-vars parent-vars) + (prog1 (let ((buffer-read-only nil) + (inhibit-modification-hooks t) + (inhibit-point-motion-hooks t) + (inhibit-redisplay t)) + ,@body) + (setq buffer-read-only t) + (let ((text-scale-mode-step 1.1)) + (text-scale-set lsp-ui-doc-text-scale-level)))))) + +(defmacro lsp-ui-doc--get-parent (var) + "Return VAR in `lsp-ui-doc--parent-vars'." + `(plist-get lsp-ui-doc--parent-vars ,var)) + +(defmacro lsp-ui-doc--set-frame (frame) + "Set the frame parameter ‘lsp-ui-doc-frame’ to FRAME." + `(set-frame-parameter nil 'lsp-ui-doc-frame ,frame)) + +(defun lsp-ui-doc--get-frame (&optional _) + "Return the child frame." + (let ((frame (frame-parameter nil 'lsp-ui-doc-frame))) + (and (frame-live-p frame) frame))) + +(defsubst lsp-ui-doc--frame-visible-p () + "Return child frame visibility." + (let ((frame (lsp-ui-doc--get-frame))) + (and frame (frame-visible-p frame)))) + +(defun lsp-ui-doc--make-buffer-name () + "Construct the buffer name, it should be unique for each frame." + (concat lsp-ui-doc--buffer-prefix + (or (frame-parameter nil 'window-id) + (frame-parameter nil 'name)) + "*")) + +;; ‘markdown-fontify-code-block-default-mode’ isn’t yet available in +;; Markdown 2.3. +(defvar markdown-fontify-code-block-default-mode) + +(defun lsp-ui-doc--inline-wrapped-line (string) + "Wraps a line of text (STRING) for inline display." + (cond ((string-empty-p string) "") + (t string))) + +(defun lsp-ui-doc--inline-formatted-string (string) + "Formats STRING for inline rendering." + (mapconcat (lambda (line) + (lsp-ui-doc--inline-wrapped-line (string-trim-right line))) + (split-string string "[\n\v\f\r]") + "\n")) + +(defun lsp-ui-doc--extract-marked-string (marked-string &optional language) + "Render the MARKED-STRING with LANGUAGE." + (string-trim-right + (let* ((string (if (stringp marked-string) + marked-string + (lsp:markup-content-value marked-string))) + (with-lang (lsp-marked-string? marked-string)) + (language (or (and with-lang + (or (lsp:marked-string-language marked-string) + (lsp:markup-content-kind marked-string))) + language)) + (markdown-hr-display-char nil)) + (cond + (lsp-ui-doc-use-webkit + (if (and language (not (string= "text" language))) + (format "```%s\n%s\n```" language string) + string)) + ;; For other programming languages + (language (lsp--render-string (lsp-ui-doc--inline-formatted-string string) language)) + ;; For default element content + (t (lsp--render-element (lsp-ui-doc--inline-formatted-string string))))))) + +(defun lsp-ui-doc--filter-marked-string (list-marked-string) + "Filter the LIST-MARKED-STRING." + (let ((groups (--separate (and (lsp-marked-string? it) + (lsp-get-renderer (lsp:marked-string-language it))) + (append list-marked-string nil)))) + (if lsp-ui-doc-include-signature + list-marked-string + (cadr groups)))) + +(defun lsp-ui-doc--extract (contents) + "Extract the documentation from CONTENTS. +CONTENTS can be differents type of values: +MarkedString | MarkedString[] | MarkupContent (as defined in the LSP). +We don't extract the string that `lps-line' is already displaying." + (cond + ((vectorp contents) ;; MarkedString[] + (mapconcat 'lsp-ui-doc--extract-marked-string + (lsp-ui-doc--filter-marked-string (seq-filter #'identity contents)) + "\n\n" + ;;(propertize "\n\n" 'face '(:height 0.4)) + )) + ;; when we get markdown contents, render using emacs gfm-view-mode / markdown-mode + ((and (lsp-marked-string? contents) + (lsp:marked-string-language contents)) + (lsp-ui-doc--extract-marked-string (lsp:marked-string-value contents) + (lsp:marked-string-language contents))) + ;; The specification for MarkedString also includes raw strings of + ;; markdown, which is not reflected by `lsp-marked-string?' + ((stringp contents) + (lsp-ui-doc--extract-marked-string contents lsp/markup-kind-markdown)) + ((lsp-marked-string? contents) (lsp-ui-doc--extract-marked-string contents)) + ((and (lsp-markup-content? contents) + (string= (lsp:markup-content-kind contents) lsp/markup-kind-markdown)) + (lsp-ui-doc--extract-marked-string (lsp:markup-content-value contents) lsp/markup-kind-markdown)) + ((and (lsp-markup-content? contents) + (string= (lsp:markup-content-kind contents) lsp/markup-kind-plain-text)) + (lsp:markup-content-value contents)))) + +(defun lsp-ui-doc--webkit-run-xwidget () + "Launch embedded WebKit instance." + (lsp-ui-doc--with-buffer + (let ((inhibit-read-only t)) + (insert " ") + (goto-char 1) + (let ((id (make-xwidget 'webkit nil 1 1 nil (buffer-name)))) + (set-xwidget-query-on-exit-flag id nil) + (put-text-property (point) (+ 1 (point)) + 'display (list 'xwidget ':xwidget id)) + (xwidget-webkit-mode) + (xwidget-webkit-goto-uri (xwidget-at 1) + lsp-ui-doc-webkit-client-path) + (lsp-ui-doc--webkit-set-background) + (lsp-ui-doc--webkit-set-foreground))))) + +(defun lsp-ui-doc--webkit-set-background () + "Set background color of the WebKit widget." + (lsp-ui-doc--webkit-execute-script + (format "document.body.style.background = '%s';" + "#fdfdfd" + ;; (face-attribute 'lsp-ui-doc-background :background) + ))) + +(defun lsp-ui-doc--webkit-set-foreground () + "Set foreground color of the WebKit widget." + (lsp-ui-doc--webkit-execute-script + (format "document.body.style.color = '%s';" + (face-attribute 'default :foreground)))) + +(defun lsp-ui-doc--webkit-get-xwidget () + "Return Xwidget instance." + (lsp-ui-doc--with-buffer + (xwidget-at 1))) + +(defun lsp-ui-doc--webkit-execute-script (script &optional fn) + "Execute SCRIPT in embedded Xwidget and run optional callback FN." + (-when-let* ((xw (lsp-ui-doc--webkit-get-xwidget))) + (xwidget-webkit-execute-script xw script fn))) + +(defun lsp-ui-doc--webkit-execute-script-rv (script) + "Execute SCRIPT in embedded Xwidget synchronously." + (-when-let* ((xw (lsp-ui-doc--webkit-get-xwidget))) + (xwidget-webkit-execute-script-rv xw script))) + +(defun lsp-ui-doc--hide-frame (&optional _win) + "Hide the frame." + (setq lsp-ui-doc--bounds nil + lsp-ui-doc--from-mouse nil) + (lsp-ui-util-safe-delete-overlay lsp-ui-doc--inline-ov) + (lsp-ui-util-safe-delete-overlay lsp-ui-doc--highlight-ov) + (when-let ((frame (lsp-ui-doc--get-frame))) + (unless lsp-ui-doc-use-webkit + (lsp-ui-doc--with-buffer (erase-buffer))) + (when (frame-visible-p frame) + (make-frame-invisible frame)))) + +(defun lsp-ui-doc--buffer-width () + "Calcul the max width of the buffer." + (lsp-ui-doc--with-buffer + (save-excursion + (let ((max 0)) + (goto-char (point-min)) + (while (not (eobp)) + (let* ((len (- (line-end-position) (line-beginning-position)))) + (when (> len max) + (setq max len))) + (forward-line 1)) + max)))) + +(defun lsp-ui-doc--line-height (&optional line) + "Return the pos-y of the LINE on screen, in pixel." + (or + (nth 2 (or (window-line-height line) + (and (redisplay t) + (window-line-height line)))) + 0)) + +(defun lsp-ui-doc--sideline-pos-y () + "Mark as unused function." + (-> (when (bound-and-true-p lsp-ui-sideline--occupied-lines) + (-min lsp-ui-sideline--occupied-lines)) + (line-number-at-pos) + (lsp-ui-doc--line-height))) + +(defun lsp-ui-doc--webkit-resize-callback (size) + "Callback when resizing using webkit depends on the SIZE." + (let ((offset-width (round (aref size 0))) + (offset-height (round (aref size 1)))) + (xwidget-resize (lsp-ui-doc--webkit-get-xwidget) offset-width offset-height)) + (lsp-ui-doc--move-frame (lsp-ui-doc--get-frame))) + +(defun lsp-ui-doc--resize-buffer () + "If the buffer's width is larger than the current frame, resize it." + (if lsp-ui-doc-use-webkit + (lsp-ui-doc--webkit-execute-script + "[document.querySelector('#lsp-ui-webkit').offsetWidth, document.querySelector('#lsp-ui-webkit').offsetHeight];" + 'lsp-ui-doc--webkit-resize-callback) + + (let* ((frame-width (frame-width)) + (fill-column (min lsp-ui-doc-max-width (- frame-width 5)))) + (when (> (lsp-ui-doc--buffer-width) (min lsp-ui-doc-max-width frame-width)) + (lsp-ui-doc--with-buffer + (fill-region (point-min) (point-max))))))) + +(defun lsp-ui-doc--mv-at-point (width height start-x start-y) + "Return position of FRAME to be where the point is. +WIDTH is the child frame width. +HEIGHT is the child frame height. +START-X is the position x of the current window. +START-Y is the position y of the current window. +The algorithm prefers to position FRAME just above the +symbol at point, to not obstruct the view of the code that follows. +If there's no space above in the current window, it places +FRAME just below the symbol at point." + (-let* (((x . y) (--> (or lsp-ui-doc--bounds (bounds-of-thing-at-point 'symbol)) + (or (posn-x-y (posn-at-point (car it))) + (if (< (car it) (window-start)) + (cons 0 0) + (posn-x-y (posn-at-point (1- (window-end)))))))) + (frame-relative-symbol-x (+ start-x x (* (frame-char-width) 2))) + (frame-relative-symbol-y (+ start-y y)) + (char-height (frame-char-height)) + ;; Make sure the frame is positioned horizontally such that + ;; it does not go beyond the frame boundaries. + (frame-x (or (and (<= (frame-outer-width) (+ frame-relative-symbol-x width)) + (- x (- (+ frame-relative-symbol-x width) + (frame-outer-width)))) + x)) + (frame-y (+ (or (and (<= height frame-relative-symbol-y) + (- y height)) + (+ y char-height)) + (if (fboundp 'window-tab-line-height) (window-tab-line-height) 0)))) + (cons (+ start-x frame-x) (+ start-y frame-y)))) + +(defun lsp-ui-doc--size-and-pos-changed (frame left top width height) + (-let (((prev-left . prev-top) (frame-position frame))) + (not (and (= left prev-left) + (= top prev-top) + (= height (frame-text-height frame)) + (= width (frame-text-width frame)))))) + +(defun lsp-ui-doc--move-frame (frame) + "Place our FRAME on screen." + (-let* (((left top right _bottom) (window-edges nil t nil t)) + (window (frame-root-window frame)) + (char-h (frame-char-height frame)) + (char-w (frame-char-width frame)) + ((width . height) (window-text-pixel-size window nil nil 10000 10000 t)) + (width (+ width (* char-w 1))) ;; margins + (height (min (- (* lsp-ui-doc-max-height char-h) (/ char-h 2)) height)) + (width (min width (* lsp-ui-doc-max-width char-w))) + (frame-right (pcase lsp-ui-doc-alignment + ('frame (frame-pixel-width)) + ('window right))) + ((left . top) (if (eq lsp-ui-doc-position 'at-point) + (lsp-ui-doc--mv-at-point width height left top) + (cons (max (- frame-right width char-w) 10) + (pcase lsp-ui-doc-position + ('top (+ top char-w)) + ('bottom (- (lsp-ui-doc--line-height 'mode-line) + height + 10)))))) + (frame-resize-pixelwise t) + (move-frame-functions nil) + (window-size-change-functions nil) + (window-state-change-hook nil) + (window-state-change-functions nil) + (window-configuration-change-hook nil) + (inhibit-redisplay t)) + ;; Dirty way to fix unused variable in emacs 26 + (and window-state-change-functions + window-state-change-hook) + ;; Make frame invisible before moving/resizing it to avoid flickering: + ;; We set the position and size in 1 call, modify-frame-parameters, but + ;; internally emacs makes 2 different calls, which can be visible + ;; to the user + (and (frame-visible-p frame) + (lsp-ui-doc--size-and-pos-changed frame left top width height) + (make-frame-invisible frame)) + (modify-frame-parameters + frame + `((width . (text-pixels . ,width)) + (height . (text-pixels . ,height)) + (user-size . t) + (left . (+ ,left)) + (top . (+ ,top)) + (user-position . t) + (lsp-ui-doc--window-origin . ,(selected-window)) + (lsp-ui-doc--buffer-origin . ,(current-buffer)) + (lsp-ui-doc--no-focus . t) + (right-fringe . 0) + (left-fringe . 0))) + ;; Insert hr lines after width is computed + (lsp-ui-doc--fix-hr-props) + (unless (frame-visible-p frame) + (make-frame-visible frame)))) + +(defun lsp-ui-doc--visit-file (filename) + "Visit FILENAME in the parent frame." + (-some->> (find-file-noselect filename) + (set-window-buffer (lsp-ui-doc--get-parent :window)))) + +(defun lsp-ui-doc--put-click (start end fn) + "Add text properties on text to make it clickable. +The text delimiters bound from START to END. +FN is the function to call on click." + (let ((map (make-sparse-keymap))) + (define-key map [down-mouse-1] fn) + (put-text-property start end 'keymap map) + (put-text-property start end 'mouse-face + (list :inherit 'lsp-ui-doc-url + :box (list :line-width -1 + :color (face-foreground 'lsp-ui-doc-url)))) + (add-face-text-property start end 'lsp-ui-doc-url))) + +(defun lsp-ui-doc--open-markdown-link (&rest _) + (interactive "P") + (let ((buffer-list-update-hook nil)) + (-let [(buffer point) (if-let* ((valid (and (listp last-input-event) + (eq (car last-input-event) 'mouse-2))) + (event (cadr last-input-event)) + (win (posn-window event)) + (buffer (window-buffer win))) + `(,buffer ,(posn-point event)) + `(,(current-buffer) ,(point)))] + (with-current-buffer buffer + ;; Markdown-mode puts the url in 'help-echo + (-some--> (get-text-property point 'help-echo) + (and (string-match-p goto-address-url-regexp it) + (browse-url it))))))) + +(defun lsp-ui-doc--make-clickable-link () + "Find paths and urls in the buffer and make them clickable." + (goto-char (point-min)) + (save-excursion + (goto-char (point-min)) + (let (case-fold-search) + (while (re-search-forward goto-address-url-regexp nil t) + (goto-char (1+ (match-end 0))) + (lsp-ui-doc--put-click (match-beginning 0) (match-end 0) + 'browse-url-at-mouse))))) + +(defun lsp-ui-doc--buffer-pre-command (&rest _) + (and (not (eq this-command 'mwheel-scroll)) + (frame-parameter nil 'lsp-ui-doc--no-focus) + (select-frame (frame-parent) t))) + +(defun lsp-ui-doc--fill-document () + "Better wrap the document so it fits the doc window." + (let ((fill-column (- lsp-ui-doc-max-width 5)) + start ; record start for `fill-region' + first-line) ; first line in paragraph + (save-excursion + (goto-char (point-min)) + (setq start (point) + first-line (thing-at-point 'line)) + (while (re-search-forward "^[ \t]*\n" nil t) + (setq first-line (thing-at-point 'line)) + (when (< fill-column (length first-line)) + (fill-region start (point))) + (setq start (point))) + ;; Fill the last paragraph + (when (< fill-column (length first-line)) + (fill-region start (point-max)))))) + +(defun lsp-ui-doc--make-smaller-empty-lines nil + "Make empty lines half normal lines." + (progn ; Customize line before header + (goto-char 1) + (insert (propertize "\n" 'face '(:height 0.3)))) + (progn ; Customize line after header + (forward-line 1) + (insert (propertize " " 'face '(:height 0.1)))) + (while (not (eobp)) + (when (and (eolp) (not (bobp))) + (save-excursion + (delete-region (point) (progn (forward-visible-line 1) (point)))) + (when (or (and (not (get-text-property (point) 'markdown-heading)) + (not (get-text-property (max (- (point) 2) 1) 'markdown-heading))) + (get-text-property (point) 'markdown-hr)) + (insert (propertize " " 'face `(:height 0.2)) + (propertize "\n" 'face '(:height 0.4))))) + (forward-line)) + (insert (propertize "\n\n" 'face '(:height 0.3)))) + +(defun lsp-ui-doc--fix-hr-props nil + ;; We insert the right display prop after window-text-pixel-size + (lsp-ui-doc--with-buffer + (let (next) + (while (setq next (next-single-property-change (or next 1) 'lsp-ui-doc--replace-hr)) + (when (get-text-property next 'lsp-ui-doc--replace-hr) + (put-text-property next (1+ next) 'display + '(space :align-to (- right-fringe 1) :height (1))) + (put-text-property (1+ next) (+ next 2) 'display + '(space :align-to right-fringe :height (1)))))))) + +(defun lsp-ui-doc--handle-hr-lines nil + (let (bolp next before after) + (goto-char 1) + (while (setq next (next-single-property-change (or next 1) 'markdown-hr)) + (when (get-text-property next 'markdown-hr) + (goto-char next) + (setq bolp (bolp) + before (char-before)) + (delete-region (point) (save-excursion (forward-visible-line 1) (point))) + (setq after (char-after (1+ (point)))) + (insert + (concat + (and bolp (not (equal before ?\n)) (propertize "\n" 'face '(:height 0.5))) + (propertize " " + ;; :align-to is added with lsp-ui-doc--fix-hr-props + 'display '(space :height (1)) + 'lsp-ui-doc--replace-hr t + 'face '(:background "dark grey")) + ;; :align-to is added here too + (propertize " " 'display '(space :height (1))) + (and (not (equal after ?\n)) (propertize " \n" 'face '(:height 0.2))))))))) + +(defun lsp-ui-doc--render-buffer (string symbol) + "Set the buffer with STRING and SYMBOL." + (lsp-ui-doc--with-buffer + (if lsp-ui-doc-use-webkit + (progn + (lsp-ui-doc--webkit-execute-script + (format "renderMarkdown('%s', '%s');" + symbol + (url-hexify-string string)) + 'lsp-ui-doc--webkit-resize-callback)) + (erase-buffer) + (insert (s-trim string)) + (unless (lsp-ui-doc--inline-p) + (lsp-ui-doc--fill-document) + (lsp-ui-doc--make-smaller-empty-lines) + (lsp-ui-doc--handle-hr-lines)) + (add-text-properties 1 (point) '(line-height 1)) + (lsp-ui-doc--make-clickable-link) + (add-text-properties 1 (point-max) '(pointer arrow))) + (lsp-ui-doc-frame-mode 1) + (setq wrap-prefix '(space :height (1) :width 1) + line-prefix '(space :height (1) :width 1)) + (setq-local face-remapping-alist `((header-line lsp-ui-doc-header))) + (setq-local window-min-height 1) + (setq-local show-trailing-whitespace nil) + (setq-local window-configuration-change-hook nil) + (add-hook 'pre-command-hook 'lsp-ui-doc--buffer-pre-command nil t) + (when (boundp 'window-state-change-functions) + (setq-local window-state-change-functions nil)) + (when (boundp 'window-state-change-hook) + (setq-local window-state-change-hook nil)) + (setq-local window-size-change-functions nil) + (setq header-line-format (when lsp-ui-doc-header (concat " " symbol)) + mode-line-format nil + cursor-type nil))) + +(defun lsp-ui-doc--inline-height () + (lsp-ui-doc--with-buffer + (length (split-string (buffer-string) "\n")))) + +(defun lsp-ui-doc--remove-invisibles (string) + "Remove invisible characters in STRING." + (let* ((start (text-property-not-all 0 (length string) 'invisible nil string))) + (while start + (setq string (concat (substring string 0 start) + (-some->> (next-single-property-change start 'invisible string) + (substring string)))) + (setq start (text-property-not-all 0 (length string) 'invisible nil string))) + string)) + +(defvar-local lsp-ui-doc--inline-width nil) + +(defun lsp-ui-doc--inline-window-width nil + (- (min (window-text-width) (window-body-width)) + (if (bound-and-true-p display-line-numbers-mode) + (+ 2 (line-number-display-width)) + 0) + 1)) + +(defun lsp-ui-doc--inline-zip (s1 s2) + (let* ((width (lsp-ui-doc--inline-window-width)) + (max-s1 (- width lsp-ui-doc--inline-width 2))) + (truncate-string-to-width + (concat (truncate-string-to-width s1 max-s1 nil ?\s) s2) + width nil ?\s))) + +(defun lsp-ui-doc--inline-padding (string len) + (let ((string (concat " " string (make-string (- len (string-width string)) ?\s) " "))) + (add-face-text-property 0 (length string) (list :background (face-background 'lsp-ui-doc-background nil t)) t string) + string)) + +(defun lsp-ui-doc--inline-faking-frame (doc-strings) + (let* ((len-max (-max-by '> (-map 'string-width doc-strings)))) + (setq lsp-ui-doc--inline-width len-max) + (--map (lsp-ui-doc--inline-padding it len-max) doc-strings))) + +(defun lsp-ui-doc--inline-untab (string) + (replace-regexp-in-string "\t" (make-string tab-width ?\s) string nil t)) + +(defun lsp-ui-doc--inline-merge (strings) + (let* ((buffer-strings (-> (lsp-ui-doc--inline-untab strings) + (lsp-ui-doc--remove-invisibles) + (split-string "\n"))) + (doc-strings (-> (lsp-ui-doc--with-buffer (buffer-string)) + (lsp-ui-doc--inline-untab) + (lsp-ui-doc--remove-invisibles) + (split-string "\n"))) + (merged (--> (lsp-ui-doc--inline-faking-frame doc-strings) + (-zip-with 'lsp-ui-doc--inline-zip buffer-strings it) + (string-join it "\n") + (concat it "\n")))) + merged)) + +(defun lsp-ui-doc--inline-pos-at (start lines) + "Calcul the position at START + forward n LINES." + (save-excursion (goto-char start) (forward-line lines) (point))) + +(defun lsp-ui-doc--inline-pos (height) + "Return a cons of positions where to place the doc. +HEIGHT is the documentation number of lines." + (let* ((w-start (window-start)) + (w-end (lsp-ui-doc--inline-pos-at w-start (window-body-height))) + (ov-end (lsp-ui-doc--inline-pos-at w-start height))) + (cond + ;; Display on top ? + ((< (lsp-ui-doc--inline-pos-at ov-end 1) (point)) + (cons w-start ov-end)) + ;; Display at the bottom ? + ((>= (lsp-ui-doc--inline-pos-at w-end (- height)) + (lsp-ui-doc--inline-pos-at (point) 2)) + (cons (lsp-ui-doc--inline-pos-at w-end (- height)) + w-end)) + ;; The doc is too long to display it fixed to the bottom ? + ;; Then display 2 lines after `point' + ;; The end of the documentation won't be visible in the window + (t (cons (lsp-ui-doc--inline-pos-at (point) 2) + (lsp-ui-doc--inline-pos-at (point) (+ height 2))))))) + +(defun lsp-ui-doc--inline () + "Display the doc in the buffer." + (-let* ((height (lsp-ui-doc--inline-height)) + ((start . end) (lsp-ui-doc--inline-pos height)) + (buffer-string (buffer-substring start end)) + (ov (if (overlayp lsp-ui-doc--inline-ov) lsp-ui-doc--inline-ov + (setq lsp-ui-doc--inline-ov (make-overlay start end))))) + (move-overlay ov start end) + (overlay-put ov 'face 'default) + (overlay-put ov 'display (lsp-ui-doc--inline-merge buffer-string)) + (overlay-put ov 'lsp-ui-doc-inline t) + (overlay-put ov 'window (selected-window)))) + +(defun lsp-ui-doc--inline-p () + "Return non-nil when the documentation should be display without a child frame." + (or (not lsp-ui-doc-use-childframe) + (not (display-graphic-p)) + (not (fboundp 'display-buffer-in-child-frame)))) + +(defun lsp-ui-doc--highlight-hover nil + (when lsp-ui-doc--from-mouse-current + (-let* (((start . end) lsp-ui-doc--bounds) + (ov (if (overlayp lsp-ui-doc--highlight-ov) lsp-ui-doc--highlight-ov + (setq lsp-ui-doc--highlight-ov (make-overlay start end))))) + (move-overlay ov start end) + (overlay-put ov 'face 'lsp-ui-doc-highlight-hover) + (overlay-put ov 'window (selected-window))))) + +(defun lsp-ui-doc--display (symbol string) + "Display the documentation." + (when (and lsp-ui-doc-use-webkit (not (featurep 'xwidget-internal))) + (setq lsp-ui-doc-use-webkit nil)) + (if (or (null string) (string-empty-p string)) + (lsp-ui-doc--hide-frame) + (lsp-ui-doc--highlight-hover) + (lsp-ui-doc--render-buffer string symbol) + (if (lsp-ui-doc--inline-p) + (lsp-ui-doc--inline) + (unless (lsp-ui-doc--get-frame) + (lsp-ui-doc--set-frame (lsp-ui-doc--make-frame))) + (unless lsp-ui-doc-use-webkit + (lsp-ui-doc--resize-buffer) + (lsp-ui-doc--move-frame (lsp-ui-doc--get-frame)))) + (setq lsp-ui-doc--from-mouse lsp-ui-doc--from-mouse-current))) + +(defun lsp-ui-doc--make-frame () + "Create the child frame and return it." + (lsp-ui-doc--delete-frame) + (let* ((after-make-frame-functions nil) + (before-make-frame-hook nil) + (name-buffer (lsp-ui-doc--make-buffer-name)) + (buffer (get-buffer name-buffer)) + (params (append lsp-ui-doc-frame-parameters + `((name . "") + (default-minibuffer-frame . ,(selected-frame)) + (minibuffer . ,(minibuffer-window)) + (left-fringe . 0) + (right-fringe . 0) + (cursor-type . nil) + (lsp-ui-doc--no-focus . t) + (background-color . ,(face-background 'lsp-ui-doc-background nil t))))) + (window (display-buffer-in-child-frame + buffer + `((child-frame-parameters . ,params)))) + (frame (window-frame window))) + (with-current-buffer buffer + (lsp-ui-doc-frame-mode 1)) + (set-frame-parameter nil 'lsp-ui-doc-buffer buffer) + (set-window-dedicated-p window t) + ;;(redirect-frame-focus frame (frame-parent frame)) + (set-face-background 'internal-border lsp-ui-doc-border frame) + (when (facep 'child-frame-border) + (set-face-background 'child-frame-border lsp-ui-doc-border frame)) + (set-face-background 'fringe nil frame) + (run-hook-with-args 'lsp-ui-doc-frame-hook frame window) + (when lsp-ui-doc-use-webkit + (define-key (current-global-map) [xwidget-event] + (lambda () + (interactive) + (let ((xwidget-event-type (nth 1 last-input-event))) + ;; (when (eq xwidget-event-type 'load-changed) + ;; (lsp-ui-doc--move-frame (lsp-ui-doc--get-frame))) + (when (eq xwidget-event-type 'javascript-callback) + (let ((proc (nth 3 last-input-event)) + (arg (nth 4 last-input-event))) + (funcall proc arg)))))) + (lsp-ui-doc--webkit-run-xwidget)) + frame)) + +(defconst lsp-ui-doc--ignore-commands + '(lsp-ui-doc-hide + lsp-ui-doc--handle-mouse-movement + keyboard-quit + ignore + handle-switch-frame + mwheel-scroll)) + +(defun lsp-ui-doc--make-request nil + "Request the documentation to the LS." + (and (not track-mouse) lsp-ui-doc-show-with-mouse (setq-local track-mouse t)) + (when (and lsp-ui-doc-show-with-cursor + (not (memq this-command lsp-ui-doc--ignore-commands)) + (not (bound-and-true-p lsp-ui-peek-mode)) + (lsp--capability "hoverProvider")) + (-if-let (bounds (or (and (symbol-at-point) (bounds-of-thing-at-point 'symbol)) + (and (looking-at "[[:graph:]]") (cons (point) (1+ (point)))))) + (unless (equal lsp-ui-doc--bounds bounds) + (lsp-ui-doc--hide-frame) + (lsp-ui-util-safe-kill-timer lsp-ui-doc--timer) + (setq lsp-ui-doc--timer + (run-with-idle-timer + lsp-ui-doc-delay nil + (let ((buf (current-buffer))) + (lambda nil + (when (equal buf (current-buffer)) + (lsp-request-async + "textDocument/hover" + (lsp--text-document-position-params) + (lambda (hover) + (when (equal buf (current-buffer)) + (lsp-ui-doc--callback hover bounds (current-buffer)))) + :mode 'tick + :cancel-token :lsp-ui-doc-hover))))))) + (lsp-ui-doc--hide-frame)))) + +(defun lsp-ui-doc--extract-bounds (hover) + (-when-let* ((hover hover) + (data (lsp-get hover :range)) + (start (-some-> (lsp:range-start data) lsp--position-to-point)) + (end (-some-> (lsp:range-end data) lsp--position-to-point))) + (cons start end))) + +(lsp-defun lsp-ui-doc--callback ((hover &as &Hover? :contents) bounds buffer) + "Process the received documentation. +HOVER is the doc returned by the LS. +BOUNDS are points of the symbol that have been requested. +BUFFER is the buffer where the request has been made." + (let ((bounds (or (lsp-ui-doc--extract-bounds hover) bounds))) + (if (and hover + (>= (point) (car bounds)) + (<= (point) (cdr bounds)) + (eq buffer (current-buffer))) + (progn + (setq lsp-ui-doc--bounds bounds) + (lsp-ui-doc--display + (thing-at-point 'symbol t) + (-some->> contents + lsp-ui-doc--extract + (replace-regexp-in-string "\r" "") + (replace-regexp-in-string " " " ")))) + (lsp-ui-doc--hide-frame)))) + +(defun lsp-ui-doc--delete-frame () + "Delete the child frame if it exists." + (-when-let (frame (lsp-ui-doc--get-frame)) + (delete-frame frame) + (lsp-ui-doc--set-frame nil))) + +(defun lsp-ui-doc--visible-p () + "Return whether the LSP UI doc is visible" + (or (overlayp lsp-ui-doc--inline-ov) + (and (lsp-ui-doc--get-frame) + (frame-visible-p (lsp-ui-doc--get-frame))))) + +(defun lsp-ui-doc-hide-frame-on-window-change (fun window &optional no-record) + "Delete the child frame if currently selected window changes. +Does nothing if the newly-selected window is the same window as +before, or if the new window is the minibuffer." + (let ((initial-window (selected-window))) + (prog1 (funcall fun window no-record) + (unless no-record + (when (lsp-ui-doc--visible-p) + (let* ((current-window (selected-window)) + (doc-buffer (get-buffer (lsp-ui-doc--make-buffer-name)))) + (unless (or (window-minibuffer-p current-window) + (equal current-window initial-window) + (and doc-buffer + (equal (window-buffer initial-window) doc-buffer))) + (lsp-ui-doc--hide-frame)))))))) + +(unless (boundp 'window-state-change-functions) + (advice-add #'select-window :around #'lsp-ui-doc-hide-frame-on-window-change) + (add-hook 'window-configuration-change-hook #'lsp-ui-doc--hide-frame)) + +(defvar-local lsp-ui-doc--timer-on-changes nil) + +(defun lsp-ui-doc--on-state-changed (_frame &optional on-idle) + (-when-let* ((frame (lsp-ui-doc--get-frame))) + (and (frame-live-p frame) + (frame-visible-p frame) + (not (minibufferp (window-buffer))) + (or (not (eq (selected-window) (frame-parameter frame 'lsp-ui-doc--window-origin))) + (not (eq (window-buffer) (frame-parameter frame 'lsp-ui-doc--buffer-origin)))) + (if on-idle (lsp-ui-doc--hide-frame) + (and (timerp lsp-ui-doc--timer-on-changes) + (cancel-timer lsp-ui-doc--timer-on-changes)) + (setq lsp-ui-doc--timer-on-changes + (run-with-idle-timer 0 nil (lambda nil (lsp-ui-doc--on-state-changed frame t)))))))) + +(advice-add 'load-theme :before (lambda (&rest _) (lsp-ui-doc--delete-frame))) + +(advice-add #'keyboard-quit :before #'lsp-ui-doc--hide-frame) + +(defun lsp-ui-doc--on-delete (frame) + "Function called when a FRAME is deleted." + (-some--> (frame-parameter frame 'lsp-ui-doc-buffer) + (get-buffer it) + (and (buffer-live-p it) it) + (kill-buffer it))) + +(defun lsp-ui-doc--handle-scroll (win _new-start) + "Handle scrolling to the document frame. + +This function is apply to hook `window-scroll-functions'. + +Argument WIN is current applying window." + (let ((frame (lsp-ui-doc--get-frame))) + (if (minibufferp (window-buffer)) + (lsp-ui-doc--hide-frame) + (when (and frame + (eq lsp-ui-doc-position 'at-point) + (frame-visible-p frame) + (eq win (selected-window))) ; This resolved #524 + (if (and lsp-ui-doc--bounds + (eq (window-buffer) (frame-parameter frame 'lsp-ui-doc--buffer-origin)) + (>= (point) (car lsp-ui-doc--bounds)) + (<= (point) (cdr lsp-ui-doc--bounds))) + (lsp-ui-doc--move-frame frame) + ;; The point might have changed if the window was scrolled + ;; too far + (lsp-ui-doc--hide-frame)))))) + +(defvar-local lsp-ui-doc--timer-mouse-movement nil) +(defvar-local lsp-ui-doc--last-event nil) + +(defun lsp-ui-doc--mouse-display nil + (when (and lsp-ui-doc--last-event + (lsp-feature? "textDocument/hover")) + (save-excursion + (goto-char lsp-ui-doc--last-event) + (-when-let* ((valid (not (eolp))) + (bounds (or (and (symbol-at-point) (bounds-of-thing-at-point 'symbol)) + (and (looking-at "[[:graph:]]") (cons (point) (1+ (point))))))) + (unless (equal bounds lsp-ui-doc--bounds) + (lsp-request-async + "textDocument/hover" + (lsp--text-document-position-params) + (lambda (hover) + (save-excursion + (goto-char lsp-ui-doc--last-event) + (let ((lsp-ui-doc-position 'at-point) + (lsp-ui-doc--from-mouse-current t)) + (lsp-ui-doc--callback hover bounds (current-buffer))))) + :mode 'tick + :cancel-token :lsp-ui-doc-hover)))))) + +(defun lsp-ui-doc--handle-mouse-movement (event) + "Show the documentation corresponding to the text under EVENT." + (interactive "e") + (when lsp-ui-doc-show-with-mouse + (and (timerp lsp-ui-doc--timer-mouse-movement) + (cancel-timer lsp-ui-doc--timer-mouse-movement)) + (let* ((e (cadr event)) + (point (posn-point e)) + (same-win (eq (selected-window) (posn-window e)))) + (and lsp-ui-doc--from-mouse + lsp-ui-doc--bounds + point + (or (< point (car lsp-ui-doc--bounds)) + (> point (cdr lsp-ui-doc--bounds)) + (not same-win) + (equal (char-after point) ?\n)) + (lsp-ui-doc--hide-frame)) + (when same-win + (setq lsp-ui-doc--last-event point + lsp-ui-doc--timer-mouse-movement + (run-with-idle-timer 0.5 nil 'lsp-ui-doc--mouse-display)))))) + +(defun lsp-ui-doc--disable-mouse-on-prefix nil + (and (bound-and-true-p lsp-ui-doc-mode) + (bound-and-true-p lsp-ui-doc--mouse-tracked-by-us) + track-mouse + (> (length (this-single-command-keys)) 0) + (setq-local track-mouse nil))) + +(defvar lsp-ui-doc--timer-mouse-idle nil) + +(defvar-local lsp-ui-doc--mouse-tracked-by-us nil + "Nil if `track-mouse' was set by another package. +If nil, do not prevent mouse on prefix keys.") + +(defun lsp-ui-doc--setup-mouse nil + (when lsp-ui-doc-show-with-mouse + (setq lsp-ui-doc--mouse-tracked-by-us (not track-mouse)) + (setq-local track-mouse t) + (unless lsp-ui-doc--timer-mouse-idle + ;; Set only 1 timer for all buffers + (setq lsp-ui-doc--timer-mouse-idle + (run-with-idle-timer 0 t 'lsp-ui-doc--disable-mouse-on-prefix))))) + +(defun lsp-ui-doc--prevent-focus-doc (e) + (not (frame-parameter (cadr e) 'lsp-ui-doc--no-focus))) + +(define-minor-mode lsp-ui-doc-mode + "Minor mode for showing hover information in child frame." + :init-value nil + :keymap `((,(kbd "<mouse-movement>") . lsp-ui-doc--handle-mouse-movement)) + :group lsp-ui-doc + (cond + (lsp-ui-doc-mode + (with-eval-after-load 'frameset + ;; The documentation frame can’t be properly restored. Especially + ;; ‘desktop-save’ will misbehave and save a bogus string "Unprintable + ;; entity" in the desktop file. Therefore we have to prevent + ;; ‘frameset-save’ from saving the parameter. + (unless (assq 'lsp-ui-doc-frame frameset-filter-alist) + ;; Copy the variable first. See the documentation of + ;; ‘frameset-filter-alist’ for explanation. + (cl-callf copy-tree frameset-filter-alist) + (push '(lsp-ui-doc-frame . :never) frameset-filter-alist))) + (when (boundp 'window-state-change-functions) + (add-hook 'window-state-change-functions 'lsp-ui-doc--on-state-changed)) + (lsp-ui-doc--setup-mouse) + (advice-add 'handle-switch-frame :before-while 'lsp-ui-doc--prevent-focus-doc) + (add-hook 'post-command-hook 'lsp-ui-doc--make-request nil t) + (add-hook 'window-scroll-functions 'lsp-ui-doc--handle-scroll nil t) + (add-hook 'delete-frame-functions 'lsp-ui-doc--on-delete nil t)) + (t + (lsp-ui-doc-hide) + (when (boundp 'window-state-change-functions) + (remove-hook 'window-state-change-functions 'lsp-ui-doc--on-state-changed)) + (remove-hook 'window-scroll-functions 'lsp-ui-doc--handle-scroll t) + (remove-hook 'post-command-hook 'lsp-ui-doc--make-request t) + (remove-hook 'delete-frame-functions 'lsp-ui-doc--on-delete t)))) + +(defun lsp-ui-doc-enable (enable) + "Enable/disable ‘lsp-ui-doc-mode’. +It is supposed to be called from `lsp-ui--toggle'" + (lsp-ui-doc-mode (if enable 1 -1))) + +(defun lsp-ui-doc-show () + "Trigger display hover information popup." + (interactive) + (lsp-ui-doc--callback (lsp-request "textDocument/hover" (lsp--text-document-position-params)) + (or (bounds-of-thing-at-point 'symbol) (cons (point) (1+ (point)))) + (current-buffer))) + +(defun lsp-ui-doc-hide () + "Hide hover information popup." + (interactive) + (lsp-ui-doc--hide-frame)) + +(defvar-local lsp-ui-doc--unfocus-frame-timer nil) +(defun lsp-ui-doc--glance-hide-frame () + "Hook to hide hover information popup for `lsp-ui-doc-glance'." + (when (or (overlayp lsp-ui-doc--inline-ov) + (lsp-ui-doc--frame-visible-p)) + (lsp-ui-doc--hide-frame) + (remove-hook 'post-command-hook 'lsp-ui-doc--glance-hide-frame) + ;; make sure child frame is unfocused + (setq lsp-ui-doc--unfocus-frame-timer + (run-at-time 1 nil #'lsp-ui-doc-unfocus-frame)))) + +(defun lsp-ui-doc-glance () + "Trigger display hover information popup and hide it on next typing." + (interactive) + (lsp-ui-doc--make-request) + (when lsp-ui-doc--unfocus-frame-timer + (cancel-timer lsp-ui-doc--unfocus-frame-timer)) + (add-hook 'post-command-hook 'lsp-ui-doc--glance-hide-frame)) + +(define-minor-mode lsp-ui-doc-frame-mode + "Marker mode to add additional key bind for lsp-ui-doc-frame." + :init-value nil + :lighter "" + :group lsp-ui-doc + :keymap `(([?q] . lsp-ui-doc-unfocus-frame) + ([remap markdown-follow-thing-at-point] . lsp-ui-doc--open-markdown-link) + ([remap mouse-drag-region] . ignore))) + +(defun lsp-ui-doc-focus-frame () + "Focus into lsp-ui-doc-frame." + (interactive) + (when-let* ((frame (lsp-ui-doc--get-frame)) + (visible (lsp-ui-doc--frame-visible-p))) + (set-frame-parameter frame 'lsp-ui-doc--no-focus nil) + (set-frame-parameter frame 'cursor-type t) + (lsp-ui-doc--with-buffer + (setq cursor-type 'box)) + (select-frame-set-input-focus frame))) + +(defun lsp-ui-doc-unfocus-frame () + "Unfocus from lsp-ui-doc-frame." + (interactive) + (-some-> (frame-parent) select-frame-set-input-focus) + (when-let* ((frame (lsp-ui-doc--get-frame))) + (set-frame-parameter frame 'lsp-ui-doc--no-focus t) + (set-frame-parameter frame 'cursor-type nil) + (lsp-ui-doc--with-buffer + (setq cursor-type nil)) + (when lsp-ui-doc--from-mouse + (make-frame-invisible frame)))) + +(provide 'lsp-ui-doc) +;;; lsp-ui-doc.el ends here diff --git a/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-doc.html b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-doc.html new file mode 100644 index 0000000..1895ce7 --- /dev/null +++ b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-doc.html @@ -0,0 +1,43 @@ +<html> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.0/showdown.min.js"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/highlight.min.js"></script> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/2.10.0/github-markdown.css"> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/default.min.css"> + <style> + .markdown-body { + box-sizing: border-box; + min-width: 400px; + max-width: 600px; + margin: 0 auto; + padding: 10px; + } + </style> + </head> + <body> + <div id="lsp-ui-webkit" class="markdown-body"> + </div> + <script> + var converter = new showdown.Converter({simpleLineBreaks: true}); + var lastSymbol = ""; + var elem = document.getElementById('lsp-ui-webkit'); + + function renderMarkdown(symbol, markedString) { + if (symbol == lastSymbol) return [elem.offsetWidth, elem.offsetHeight]; + decodedString = decodeURIComponent(markedString); + html = converter.makeHtml(decodedString); + elem.innerHTML = html; + lastSymbol = symbol; + + document.querySelectorAll('pre code').forEach(function(codeBlock) { + hljs.highlightBlock(codeBlock); + }); + + return [elem.offsetWidth, elem.offsetHeight]; + } + + </script> + </body> +</html> diff --git a/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-flycheck.el b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-flycheck.el new file mode 100644 index 0000000..e3ac831 --- /dev/null +++ b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-flycheck.el @@ -0,0 +1,171 @@ +;;; lsp-ui-flycheck.el --- Flycheck support for lsp-mode -*- lexical-binding: t; -*- + +;; Copyright (C) 2017 fmdkdd +;; URL: https://github.com/emacs-lsp/lsp-ui +;; Keywords: languagues, tools +;; Version: 6.2 + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Flycheck integration for lsp-mode. + +;;; Code: + +(require 'flycheck nil 'noerror) ; Temporary solution, see #514 +(require 'pcase) +(require 'dash) + +(require 'lsp-protocol) +(require 'lsp-mode) + +(defgroup lsp-ui-flycheck nil + "The LSP extension to display syntax checking." + :group 'tools + :group 'convenience + :group 'lsp-ui + :link '(custom-manual "(lsp-ui-flycheck) Top") + :link '(info-link "(lsp-ui-flycheck) Customizing")) + +(defcustom lsp-ui-flycheck-list-position 'bottom + "Position where `lsp-ui-flycheck-list' will show diagnostics for the +whole workspace." + :type '(choice (const :tag "Bottom" bottom) + (const :tag "Right" right)) + :group 'lsp-ui-flycheck) + +(defvar-local lsp-ui-flycheck-list--buffer nil) +(defvar-local lsp-ui-flycheck--save-mode nil) + +(defun lsp-ui-flycheck-list--post-command () + (when (eobp) + (forward-line -1))) + +(defun lsp-ui-flycheck-list--update (window workspace) + "Update flycheck buffer in WINDOW belonging to WORKSPACE. +Use `lsp-diagnostics' to receive diagnostics from your LSP server." + (let ((buffer-read-only nil) + (lsp--cur-workspace workspace)) + (erase-buffer) + (remove-overlays) + (maphash (lambda (file diagnostic) + (when diagnostic + (overlay-put + (make-overlay (point) (point)) + 'after-string + (concat (propertize "\n" 'face '(:height 0.2)) + (propertize (lsp-ui--workspace-path file) + 'face 'dired-directory) + (propertize "\n" 'face '(:height 0.2))))) + (dolist (diag diagnostic) + (-let* (((&Diagnostic :message :severity? :source? + :range (&Range :start (&Position :line start-line))) diag) + (formatted-message (or (if source? (format "%s: %s" source? message) message) "???")) + (severity (or severity? 1)) + (line (1+ start-line)) + (face (cond ((= severity 1) 'error) + ((= severity 2) 'warning) + (t 'success))) + (text (concat (propertize (number-to-string line) 'face face) + ": " + (car (split-string formatted-message "\n"))))) + (add-text-properties 0 (length text) `(diag ,diag file ,file window ,window) text) + (insert (concat text "\n"))))) + (lsp-diagnostics))) + (if (= (point) 1) + (overlay-put (make-overlay 1 1) + 'after-string "No diagnostic available\n") + (goto-char 1)) + (lsp-ui-flycheck-list-mode)) + +(defun lsp-ui-flycheck-list () + "List all the diagnostics in the whole workspace." + (interactive) + (let ((buffer (get-buffer-create "*lsp-diagnostics*")) + (workspace lsp--cur-workspace) + (window (selected-window))) + (with-current-buffer buffer + (lsp-ui-flycheck-list--update window workspace)) + (add-hook 'lsp-diagnostics-updated-hook 'lsp-ui-flycheck-list--refresh nil t) + (setq lsp-ui-flycheck-list--buffer buffer) + (let ((win (display-buffer-in-side-window + buffer `((side . ,lsp-ui-flycheck-list-position) (slot . 5) (window-width . 0.20))))) + (set-window-dedicated-p win t) + (select-window win) + (fit-window-to-buffer nil nil 10)))) + +(defun lsp-ui-flycheck-list--refresh () + (let ((workspace lsp--cur-workspace) + (current-window (selected-window))) + (when (and (buffer-live-p lsp-ui-flycheck-list--buffer) + (get-buffer-window lsp-ui-flycheck-list--buffer) + workspace) + (with-selected-window (get-buffer-window lsp-ui-flycheck-list--buffer) + (lsp-ui-flycheck-list--update current-window workspace) + (fit-window-to-buffer nil nil 10))))) + +(defun lsp-ui-flycheck-list--open () + (-when-let* ((diag (get-text-property (point) 'diag)) + ((&Diagnostic :range (&Range :start (&Position :line start-line + :character start-column))) diag) + (file (get-text-property (point) 'file)) + (window (get-text-property (point) 'window)) + (marker (with-current-buffer + (or (get-file-buffer file) + (find-file-noselect file)) + (save-restriction + (widen) + (save-excursion + (goto-char 1) + (forward-line start-line) + (forward-char start-column) + (point-marker)))))) + (set-window-buffer window (marker-buffer marker) t) + (with-selected-window window + (goto-char marker) + (recenter) + (pulse-momentary-highlight-one-line (marker-position marker) 'next-error)) + window)) + +(defun lsp-ui-flycheck-list--view () + (interactive) + (lsp-ui-flycheck-list--open)) + +(defun lsp-ui-flycheck-list--visit () + (interactive) + (select-window (lsp-ui-flycheck-list--open))) + +(defun lsp-ui-flycheck-list--quit () + (interactive) + (kill-buffer)) + +(defvar lsp-ui-flycheck-list-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "q") 'lsp-ui-flycheck-list--quit) + (define-key map (kbd "<return>") 'lsp-ui-flycheck-list--view) + (define-key map (kbd "<M-return>") 'lsp-ui-flycheck-list--visit) + map) + "Keymap for ‘lsp-ui-flycheck-list-mode’.") + +(define-derived-mode lsp-ui-flycheck-list-mode special-mode "lsp-ui-flycheck-list" + "Mode showing flycheck diagnostics for the whole workspace." + (setq truncate-lines t) + (setq mode-line-format nil) + (add-hook 'post-command-hook 'lsp-ui-flycheck-list--post-command nil t)) + +(declare-function lsp-ui--workspace-path "lsp-ui" (path)) + +(provide 'lsp-ui-flycheck) +;;; lsp-ui-flycheck.el ends here diff --git a/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-imenu.el b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-imenu.el new file mode 100644 index 0000000..3c628da --- /dev/null +++ b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-imenu.el @@ -0,0 +1,412 @@ +;;; lsp-ui-imenu.el --- Lsp-Ui-Imenu -*- lexical-binding: t -*- + +;; Copyright (C) 2018 Sebastien Chapuis + +;; Author: Sebastien Chapuis <sebastien@chapu.is> +;; URL: https://github.com/emacs-lsp/lsp-ui +;; Keywords: languages, tools +;; Version: 6.3 + +;;; License +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; Show imenu entries +;; Call the function `lsp-ui-imenu' +;; +;; (define-key lsp-ui-mode-map (kbd "C-c l") 'lsp-ui-imenu) + +;;; Code: + +(require 'lsp-mode) +(require 'dash) +(require 'lsp-ui-util) + +(defgroup lsp-ui-imenu nil + "Display imenu entries." + :group 'tools + :group 'convenience + :group 'lsp-ui + :link '(custom-manual "(lsp-ui-imenu) Top") + :link '(info-link "(lsp-ui-imenu) Customizing")) + +(defcustom lsp-ui-imenu-enable t + "Whether or not to enable ‘lsp-ui-imenu’." + :type 'boolean + :group 'lsp-ui) + +(defcustom lsp-ui-imenu-kind-position 'top + "Where to show the entries kind." + :type '(choice (const :tag "Top" top) + (const :tag "Left" left)) + :group 'lsp-ui-imenu) + +(defcustom lsp-ui-imenu-colors '("deep sky blue" "green3") + "Color list to cycle through for entry groups." + :type '(repeat color) + :group 'lsp-ui-imenu) + +(defcustom lsp-ui-imenu-window-width 0 + "When not 0, don't fit window to buffer and use value as window-width." + :type 'number + :group 'lsp-ui-imenu) + +(defcustom lsp-ui-imenu-auto-refresh nil + "Automatically refresh imenu when certain conditions meet." + :type '(choice (const :tag "Enable" t) + (const :tag "Active only when after save" after-save) + (const :tag "Disable" nil)) + :group 'lsp-ui-imenu) + +(defcustom lsp-ui-imenu-auto-refresh-delay 1.0 + "Delay time to refresh imenu." + :type 'float + :group 'lsp-ui-imenu) + +(defcustom lsp-ui-imenu--custom-mode-line-format nil + "Custom mode line format to be used in `lsp-ui-menu-mode'." + :type 'sexp + :group 'lsp-ui-menu) + +(defconst lsp-ui-imenu--max-bars 8) + +(declare-function imenu--make-index-alist 'imenu) +(declare-function imenu--subalist-p 'imenu) +(defvar imenu--index-alist) + +(defvar-local lsp-ui-imenu--refresh-timer nil + "Auto refresh timer for imenu.") + +(defun lsp-ui-imenu--pad (s len bars depth color-index for-title is-last) + (let ((n (- len (length s)))) + (apply #'concat + (make-string n ?\s) + (propertize s 'face `(:foreground ,(lsp-ui-imenu--get-color color-index))) + (let (bar-strings) + (dotimes (i depth) + (push + (propertize (lsp-ui-imenu--get-bar bars i depth for-title is-last) + 'face `(:foreground + ,(lsp-ui-imenu--get-color (+ color-index i)))) + bar-strings)) + (reverse bar-strings))))) + +(defun lsp-ui-imenu--get-bar (bars index depth for-title is-last) + (cond + ;; Exceeding maximum bars + ((>= index lsp-ui-imenu--max-bars) " ") + ;; No bar for this level + ((not (aref bars index)) " ") + ;; For the first level, the title is rendered differently, so leaf items are + ;; decorated with the full height bar regardless if it's the last item or + ;; not. + ((and (= depth 1) (not for-title)) " ┃ ") + ;; Full height bar for levels other than the rightmost one. + ((< (1+ index) depth) " ┃ ") + ;; The rightmost bar for the last item. + (is-last " â”— " ) + ;; The rightmost bar for the title items other than the last one. + (for-title " ┣ ") + ;; The rightmost bar for the leaf items other than the last one. + (t " ┃ "))) + +(defun lsp-ui-imenu--get-color (index) + (nth (mod index (length lsp-ui-imenu-colors)) lsp-ui-imenu-colors)) + +(defun lsp-ui-imenu--make-line (title index entry padding bars depth color-index is-last) + (let* ((prefix (if (and (= index 0) (eq lsp-ui-imenu-kind-position 'left)) title " ")) + (text (concat (lsp-ui-imenu--pad prefix padding bars depth color-index nil is-last) + (propertize (car entry) 'face 'default) + "\n")) + (len (length text))) + (add-text-properties 0 len `(index ,index title ,title marker ,(cdr entry) + padding ,padding depth, depth) + text) + text)) + +(defvar-local lsp-ui-imenu-ov nil + "Variable that holds overlay for imenu.") + +(defun lsp-ui-imenu--make-ov nil + "Make imenu overlay." + (or (and (overlayp lsp-ui-imenu-ov) lsp-ui-imenu-ov) + (setq lsp-ui-imenu-ov (make-overlay 1 1)))) + +(defun lsp-ui-imenu--post-command nil + "Post command hook for imenu." + (when (eobp) (forward-line -1)) + (lsp-ui-imenu--move-to-name-beginning) + (when (eq lsp-ui-imenu-kind-position 'left) + (save-excursion + (when (overlayp lsp-ui-imenu-ov) + (overlay-put lsp-ui-imenu-ov 'display nil)) + (redisplay) + (goto-char (window-start)) + (if (= (get-text-property (point) 'index) 0) + (when (overlayp lsp-ui-imenu-ov) (delete-overlay lsp-ui-imenu-ov)) + (let* ((ov (lsp-ui-imenu--make-ov)) + (padding (get-text-property (point) 'padding)) + (title (get-text-property (point) 'title)) + (text (buffer-substring (+ (line-beginning-position) padding) (line-end-position)))) + (move-overlay ov (line-beginning-position) (line-end-position)) + (overlay-put ov 'display `(string ,(concat (let ((n (- padding (length title)))) + (propertize (concat (make-string n ?\s) title))) + text)))))))) + +(defun lsp-ui-imenu--move-to-name-beginning () + (-when-let* ((padding (get-char-property (point) 'padding)) + (depth (get-char-property (point) 'depth))) + (goto-char (+ (* depth 3) (line-beginning-position) padding)))) + +(defvar lsp-ui-imenu--origin nil) + +(defun lsp-ui-imenu--put-separator nil + (let ((ov (make-overlay (point) (point)))) + (overlay-put ov 'after-string (propertize "\n" 'face '(:height 0.6))))) + +(defun lsp-ui-imenu--put-toplevel-title (title color-index) + (if (eq lsp-ui-imenu-kind-position 'top) + (let ((ov (make-overlay (point) (point))) + (color (lsp-ui-imenu--get-color color-index))) + (overlay-put + ov 'after-string + (concat (propertize "\n" 'face '(:height 0.6)) + (propertize title 'face `(:foreground ,color)) + "\n" + (propertize "\n" 'face '(:height 0.6))))) + ;; Left placement, title is put with the first sub item. Only put a separator here. + (lsp-ui-imenu--put-separator))) + +(defun lsp-ui-imenu--put-subtitle (title padding bars depth color-index is-last) + (let ((ov (make-overlay (point) (point))) + (title-color (lsp-ui-imenu--get-color (+ color-index depth)))) + (overlay-put + ov 'after-string + (concat (lsp-ui-imenu--pad " " padding bars depth color-index t is-last) + (propertize title 'face `(:foreground ,title-color)) + (propertize "\n" 'face '(:height 1)))))) + +(defun lsp-ui-imenu--insert-items (title items padding bars depth color-index) + "Insert ITEMS for TITLE. + +PADDING is the length of whitespaces to the left of the first bar. + +BARS is a bool vector of length `lsp-ui-imenu--max-bars'. The ith +value indicates whether the ith bar from the left is visible. + +DEPTH is the depth of the items in the index tree, starting from 0. + +COLOR-INDEX is the index of the color of the leftmost bar. + +Return the updated COLOR-INDEX." + (let ((len (length items))) + (--each-indexed items + (let ((is-last (= (1+ it-index) len))) + (if (imenu--subalist-p it) + (-let* (((sub-title . entries) it)) + (if (= depth 0) + (lsp-ui-imenu--put-toplevel-title sub-title color-index) + (lsp-ui-imenu--put-subtitle sub-title padding bars depth color-index is-last)) + (when (and is-last (> depth 0)) + (aset bars (1- depth) nil)) + (let ((lsp-ui-imenu-kind-position (if (> depth 0) 'top + lsp-ui-imenu-kind-position))) + (lsp-ui-imenu--insert-items sub-title + entries + padding + bars + (1+ depth) + color-index)) + (when (and is-last (> depth 0)) + (aset bars (1- depth) t)) + (when (= depth 0) + (setq color-index (1+ color-index)))) + (insert (lsp-ui-imenu--make-line title it-index it + padding bars depth color-index + is-last)))))) + color-index) + +(defun lsp-ui-imenu--get-padding (items) + "Get imenu padding determined by `lsp-ui-imenu-kind-position'. +ITEMS are used when the kind position is 'left." + (cl-case lsp-ui-imenu-kind-position + (top 1) + (left (--> (-filter 'imenu--subalist-p items) + (--map (length (car it)) it) + (-max (or it '(1))))) + (t (user-error "Invalid value for imenu's kind position: %s" lsp-ui-imenu-kind-position)))) + +(defun lsp-ui-imenu--put-bit (bits offset) + (logior bits (lsh 1 offset))) + +(defun lsp-ui-imenu--clear-bit (bits offset) + (logand bits (lognot (lsh 1 offset)))) + +(defvar lsp-ui-imenu-buffer-name "*lsp-ui-imenu*" + "Buffer name for imenu buffers.") + +(defun lsp-ui-imenu--refresh-content () + "Refresh imenu content menu" + (let ((imenu-auto-rescan t)) + (setq lsp-ui-imenu--origin (current-buffer)) + (imenu--make-index-alist) + (let ((imenu-buffer (get-buffer-create lsp-ui-imenu-buffer-name)) + (list imenu--index-alist)) + (with-current-buffer imenu-buffer + (let* ((padding (lsp-ui-imenu--get-padding list)) + (grouped-by-subs (-partition-by 'imenu--subalist-p list)) + (color-index 0) + (bars (make-bool-vector lsp-ui-imenu--max-bars t)) + (inhibit-read-only t)) + (remove-overlays) + (erase-buffer) + (dolist (group grouped-by-subs) + (if (imenu--subalist-p (car group)) + (setq color-index (lsp-ui-imenu--insert-items "" group padding bars 0 color-index)) + (lsp-ui-imenu--put-separator) + (lsp-ui-imenu--insert-items "" group padding bars 1 color-index) + (setq color-index (1+ color-index)))) + (lsp-ui-imenu-mode) + (when lsp-ui-imenu--custom-mode-line-format + (setq mode-line-format lsp-ui-imenu--custom-mode-line-format)) + (goto-char (point-min)) + (add-hook 'post-command-hook 'lsp-ui-imenu--post-command nil t)))))) + +(defun lsp-ui-imenu nil + "Open ui-imenu in side window." + (interactive) + (lsp-ui-imenu-buffer-mode 1) + (setq lsp-ui-imenu--origin (current-buffer)) + (imenu--make-index-alist) + (let ((imenu-buffer (get-buffer-create lsp-ui-imenu-buffer-name))) + (lsp-ui-imenu--refresh-content) + (let ((win (display-buffer-in-side-window imenu-buffer '((side . right))))) + (set-window-margins win 1) + (select-window win) + (set-window-start win 1) + (lsp-ui-imenu--move-to-name-beginning) + (set-window-dedicated-p win t) + ;; when `lsp-ui-imenu-window-width' is 0, fit window to buffer + (if (= lsp-ui-imenu-window-width 0) + (let ((fit-window-to-buffer-horizontally 'only)) + (fit-window-to-buffer win) + (window-resize win 3 t)) + (let ((x (- lsp-ui-imenu-window-width (window-width)))) + (window-resize (selected-window) x t)))))) + +(defun lsp-ui-imenu--kill nil + "Kill imenu window." + (interactive) + (lsp-ui-imenu-buffer-mode -1) + (kill-buffer-and-window)) + +(defun lsp-ui-imenu--jump (direction) + (let ((current (get-text-property (point) 'title))) + (forward-line direction) + (while (and current + (not (= (line-number-at-pos) 1)) + (equal current (get-text-property (point) 'title))) + (forward-line direction)))) + +(defun lsp-ui-imenu--next-kind nil + "Jump to next kind of imenu." + (interactive) + (lsp-ui-imenu--jump 1)) + +(defun lsp-ui-imenu--prev-kind nil + "Jump to previous kind of imenu." + (interactive) + (lsp-ui-imenu--jump -1) + (while (not (= (get-text-property (point) 'index) 0)) + (forward-line -1))) + +(defun lsp-ui-imenu--visit nil + (interactive) + (let ((marker (get-text-property (point) 'marker))) + (select-window (get-buffer-window lsp-ui-imenu--origin)) + (goto-char marker) + (pulse-momentary-highlight-one-line (point) 'next-error))) + +(defun lsp-ui-imenu--view nil + (interactive) + (let ((marker (get-text-property (point) 'marker))) + (with-selected-window (get-buffer-window lsp-ui-imenu--origin) + (goto-char marker) + (recenter) + (pulse-momentary-highlight-one-line (point) 'next-error)))) + +(defvar lsp-ui-imenu-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "q") 'lsp-ui-imenu--kill) + (define-key map (kbd "r") 'lsp-ui-imenu--refresh) + (define-key map (kbd "<right>") 'lsp-ui-imenu--next-kind) + (define-key map (kbd "<left>") 'lsp-ui-imenu--prev-kind) + (define-key map (kbd "<return>") 'lsp-ui-imenu--view) + (define-key map (kbd "<M-return>") 'lsp-ui-imenu--visit) + (define-key map (kbd "RET") 'lsp-ui-imenu--view) + (define-key map (kbd "M-RET") 'lsp-ui-imenu--visit) + map) + "Keymap for ‘lsp-ui-peek-mode’.") + +(define-derived-mode lsp-ui-imenu-mode special-mode "lsp-ui-imenu" + "Mode showing imenu entries.") + +(defun lsp-ui-imenu--refresh () + "Safe refresh imenu content." + (interactive) + (let ((imenu-buffer (get-buffer lsp-ui-imenu-buffer-name))) + (when imenu-buffer + (save-selected-window + (if (equal (current-buffer) imenu-buffer) + (select-window (get-buffer-window lsp-ui-imenu--origin)) + (setq lsp-ui-imenu--origin (current-buffer))) + (lsp-ui-imenu--refresh-content))))) + +(defun lsp-ui-imenu--start-refresh (&rest _) + "Starts the auto refresh timer." + (lsp-ui-util-safe-kill-timer lsp-ui-imenu--refresh-timer) + (setq lsp-ui-imenu--refresh-timer + (run-with-idle-timer lsp-ui-imenu-auto-refresh-delay nil #'lsp-ui-imenu--refresh))) + +(defun lsp-ui-imenu-buffer--enable () + "Enable `lsp-ui-imenu-buffer'." + (when lsp-ui-imenu-auto-refresh + (cl-case lsp-ui-imenu-auto-refresh + (after-save + (add-hook 'after-save-hook #'lsp-ui-imenu--start-refresh nil t)) + (t + (add-hook 'after-change-functions #'lsp-ui-imenu--start-refresh nil t) + (add-hook 'after-save-hook #'lsp-ui-imenu--start-refresh nil t))))) + +(defun lsp-ui-imenu-buffer--disable () + "Disable `lsp-ui-imenu-buffer'." + (when lsp-ui-imenu-auto-refresh + (cl-case lsp-ui-imenu-auto-refresh + (after-save + (remove-hook 'after-save-hook #'lsp-ui-imenu--start-refresh t)) + (t + (remove-hook 'after-change-functions #'lsp-ui-imenu--start-refresh t) + (remove-hook 'after-save-hook #'lsp-ui-imenu--start-refresh t))))) + +(define-minor-mode lsp-ui-imenu-buffer-mode + "Minor mode 'lsp-ui-imenu-buffer-mode'." + :group lsp-ui-imenu + (if lsp-ui-imenu-buffer-mode (lsp-ui-imenu-buffer--enable) (lsp-ui-imenu-buffer--disable))) + +(provide 'lsp-ui-imenu) +;;; lsp-ui-imenu.el ends here diff --git a/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-peek.el b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-peek.el new file mode 100644 index 0000000..c73028c --- /dev/null +++ b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-peek.el @@ -0,0 +1,754 @@ +;;; lsp-ui-peek.el --- Lsp-Ui-Peek -*- lexical-binding: t -*- + +;; Copyright (C) 2017 Sebastien Chapuis + +;; Author: Sebastien Chapuis <sebastien@chapu.is> +;; URL: https://github.com/emacs-lsp/lsp-ui +;; Keywords: languagues, tools +;; Version: 0.0.1 + +;;; License +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. + +;;; Commentary: +;; +;; Load this file and execute `lsp-ui-peek-find-references' +;; on a symbol to find its references +;; or `lsp-ui-peek-find-definitions'. +;; Type 'q' to close the window. +;; + +;;; Code: + +(require 'lsp-protocol) +(require 'lsp-mode) +(require 'xref) +(require 'dash) + +(defgroup lsp-ui-peek nil + "Improve version of xref with peek feature." + :group 'tools + :group 'convenience + :group 'lsp-ui + :link '(custom-manual "(lsp-ui-peek) Top") + :link '(info-link "(lsp-ui-peek) Customizing")) + +(defcustom lsp-ui-peek-enable t + "Whether or not to enable ‘lsp-ui-peek’." + :type 'boolean + :group 'lsp-ui) + +(defcustom lsp-ui-peek-show-directory t + "Whether or not to show the directory of files." + :type 'boolean + :safe t + :group 'lsp-ui-peek) + +(defcustom lsp-ui-peek-peek-height 20 + "Height of the peek code." + :type 'integer + :group 'lsp-ui-peek) + +(defcustom lsp-ui-peek-list-width 50 + "Width of the right panel." + :type 'integer + :group 'lsp-ui-peek) + +(defcustom lsp-ui-peek-fontify 'on-demand + "Whether to fontify chunks of code (use semantics colors). +WARNING: 'always can heavily slow the processing when +`lsp-ui-peek-expand-function' expands more than 1 file. +It is recommended to keep the default value of `lsp-ui-peek-expand-function' +when this variable is set to 'always." + :type '(choice (const :tag "Never" never) + (const :tag "On demand" on-demand) + (const :tag "Always" always)) + :group 'lsp-ui-peek) + +(defcustom lsp-ui-peek-always-show nil + "Show the peek view even if there is only 1 cross reference. +By default, the peek view isn't shown if there is 1 xref." + :type 'boolean + :group 'lsp-ui-peek) + +(defface lsp-ui-peek-peek + '((((background light)) :background "light gray") + (t :background "#031A25")) + "Face used for the peek." + :group 'lsp-ui-peek) + +(defface lsp-ui-peek-list + '((((background light)) :background "light gray") + (t :background "#181818")) + "Face used to list references." + :group 'lsp-ui-peek) + +(defface lsp-ui-peek-filename + '((((background light)) :foreground "red") + (t :foreground "dark orange")) + "Face used for the filename's reference in the list." + :group 'lsp-ui-peek) + +(defface lsp-ui-peek-line-number + '((t :foreground "grey25")) + "Line number face." + :group 'lsp-ui-peek) + +(defface lsp-ui-peek-highlight + '((((background light)) :background "yellow" + :box (:line-width -1 :color "red")) + (t :background "white" + :foreground "black" + :distant-foreground "white" + :box (:line-width -1 :color "red"))) + "Face used to highlight the reference/definition. +Do not use box, underline or overline prop. If you want to use +box, use a negative value for its width. Those properties deform +the whole overlay." + :group 'lsp-ui-peek) + +(defface lsp-ui-peek-header + '((((background light)) :background "grey30" :foreground "white") + (t :background "white" :foreground "black")) + "Face used for the headers." + :group 'lsp-ui-peek) + +(defface lsp-ui-peek-footer + '((t :inherit lsp-ui-peek-header)) + "Face used for the footers. Only the background of this face is used." + :group 'lsp-ui-peek) + +(defface lsp-ui-peek-selection + '((((background light)) :background "grey30" :foreground "white") + (t :background "white" :foreground "black")) + "Face used for the current selection. +Do not use box, underline or overline prop. If you want to use +box, use a negative value for its width. Those properties +deform the whole overlay." + :group 'lsp-ui-peek) + +(defvar lsp-ui-peek-expand-function 'lsp-ui-peek--expand-buffer + "A function used to determinate which file(s) to expand in the list of xrefs. +The function takes one parameter: a list of cons where the car is the +filename and the cdr is the number of references in that file. +It should returns a list of filenames to expand. +WARNING: If you change this variable and expand more than 1 file, it is +recommended to set `lsp-ui-peek-fontify' to 'never or 'on-demand, otherwise it +will cause performances issues.") + +(defvar-local lsp-ui-peek--overlay nil) +(defvar-local lsp-ui-peek--list nil) +(defvar-local lsp-ui-peek--last-xref nil) +(defvar-local lsp-ui-peek--selection 0) +(defvar-local lsp-ui-peek--offset 0) +(defvar-local lsp-ui-peek--size-list 0) +(defvar-local lsp-ui-peek--win-start nil) +(defvar-local lsp-ui-peek--method nil) +(defvar-local lsp-ui-peek--deactivate-keymap-fn nil) + +(defvar lsp--peek-save-major-mode nil + "Stores the major mode for lsp ui peek.") + +(defvar lsp-ui-peek--jumps (make-hash-table) + "Hashtable which stores all jumps on a per window basis.") + +(defvar evil--jumps-window-jumps) ; defined in evil-jumps.el + +(defmacro lsp-ui-peek--with-evil-jumps (&rest body) + "Make `evil-jumps.el' commands work on `lsp-ui-peek--jumps'." + (declare (indent 1)) + `(let ((evil--jumps-window-jumps lsp-ui-peek--jumps)) + ,@body)) + +(with-eval-after-load 'evil-jumps + ;; We need to jump through some hoops to prevent the byte-compiler from + ;; compiling this code. We can’t compile the code without requiring + ;; ‘evil-macros’. + (eval '(progn + (evil-define-motion lsp-ui-peek-jump-backward (count) + (lsp-ui-peek--with-evil-jumps + (evil--jump-backward count) + (run-hooks 'xref-after-return-hook))) + (evil-define-motion lsp-ui-peek-jump-forward (count) + (lsp-ui-peek--with-evil-jumps + (evil--jump-forward count) + (run-hooks 'xref-after-return-hook)))) + t)) + +(defmacro lsp-ui-peek--prop (prop &optional string) + `(get-text-property 0 ,prop (or ,string (lsp-ui-peek--get-text-selection) ""))) + +(defmacro lsp-ui-peek--add-prop (prop &optional string) + `(let ((obj (or ,string (lsp-ui-peek--get-text-selection)))) + (add-text-properties 0 (length obj) ,prop obj) + obj)) + +(defun lsp-ui-peek--truncate (len s) + (if (> (string-width s) len) + (concat (truncate-string-to-width s (max (- len 2) 0)) "..") + s)) + +(defun lsp-ui-peek--get-text-selection (&optional n) + (nth (or n lsp-ui-peek--selection) + (--remove (get-text-property 0 'lsp-ui-peek-hidden it) lsp-ui-peek--list))) + +(defun lsp-ui-peek--get-selection () + (get-text-property 0 'lsp-ui-peek (or (lsp-ui-peek--get-text-selection) ""))) + +(defun lsp-ui-peek--visual-index () + (- lsp-ui-peek--selection lsp-ui-peek--offset)) + +(defun lsp-ui-peek--make-line (index src) + (-let* (((s1 . s2) src) + (len-s1 (length s1)) + (len-s2 (length s2)) + (on-selection (= (1+ (lsp-ui-peek--visual-index)) index)) + (face-left (if (= index 0) 'lsp-ui-peek-header 'lsp-ui-peek-peek)) + (face-right (cond (on-selection 'lsp-ui-peek-selection) + ((= index 0) 'lsp-ui-peek-header) + (t 'lsp-ui-peek-list)))) + (when on-selection + (setq s2 (copy-sequence s2)) + (add-face-text-property 0 len-s2 face-right nil s2)) + (unless (get-text-property 0 'lsp-ui-peek-faced s2) + (add-face-text-property 0 len-s2 face-right t s2) + (add-text-properties 0 len-s2 '(lsp-ui-peek-faced t) s2) + (add-face-text-property 0 len-s2 'default t s2)) + (add-face-text-property 0 len-s1 face-left t s1) + (add-face-text-property 0 len-s1 'default t s1) + (concat + s1 + (propertize "_" 'face face-left 'display `(space :align-to (- right-fringe ,(1+ lsp-ui-peek-list-width)))) + " " + s2 + (propertize "_" 'face face-right 'display `(space :align-to (- right-fringe 1))) + (propertize "\n" 'face face-right)))) + +(defun lsp-ui-peek--adjust (width strings) + (-let* (((s1 . s2) strings)) + (cons (lsp-ui-peek--truncate (- width (1+ lsp-ui-peek-list-width)) s1) + (lsp-ui-peek--truncate (- lsp-ui-peek-list-width 2) s2)))) + +(defun lsp-ui-peek--make-footer () + ;; Character-only terminals don't support characters of different height + (when (display-graphic-p) + (list + (concat + (propertize " " + 'face `(:background ,(face-background 'lsp-ui-peek-footer nil t) :height 1) + 'display `(space :align-to (- right-fringe ,(1+ lsp-ui-peek-list-width)))) + (propertize " " 'face '(:height 1) + 'display `(space :align-to (- right-fringe ,lsp-ui-peek-list-width))) + (propertize " " + 'face `(:background ,(face-background 'lsp-ui-peek-footer nil t) :height 1) + 'display `(space :align-to (- right-fringe 0))) + (propertize "\n" 'face '(:height 1)) + (propertize "\n" 'face '(:height 0.5)))))) + +(defun lsp-ui-peek--peek-new (src1 src2) + (-let* ((win-width (- (window-text-width) + (if (bound-and-true-p display-line-numbers-mode) + (+ 2 (line-number-display-width)) + 0))) + (string (-some--> (-zip-fill "" src1 src2) + (--map (lsp-ui-peek--adjust win-width it) it) + (-map-indexed 'lsp-ui-peek--make-line it) + (-concat it (lsp-ui-peek--make-footer)))) + (next-line (line-beginning-position 2)) + (ov (or (when (overlayp lsp-ui-peek--overlay) lsp-ui-peek--overlay) + (make-overlay next-line next-line)))) + (setq lsp-ui-peek--overlay ov) + (overlay-put ov 'after-string (mapconcat 'identity string "")) + (overlay-put ov 'display-line-numbers-disable t) + (overlay-put ov 'window (get-buffer-window)))) + +(defun lsp-ui-peek--expand-buffer (files) + (if (--any? (equal (car it) buffer-file-name) files) + (list buffer-file-name) + (list (caar files)))) + +(defun lsp-ui-peek--expand (xrefs) + (let* ((to-expand (->> (--map (cons (plist-get it :file) (plist-get it :count)) xrefs) + (funcall lsp-ui-peek-expand-function))) + first) + (while (nth lsp-ui-peek--selection lsp-ui-peek--list) + (when (and (lsp-ui-peek--prop 'xrefs) + (member (lsp-ui-peek--prop 'file) to-expand)) + (unless first + (setq first (1+ lsp-ui-peek--selection))) + (lsp-ui-peek--toggle-file t)) + (setq lsp-ui-peek--selection (1+ lsp-ui-peek--selection))) + (setq lsp-ui-peek--selection (or first 0)) + (lsp-ui-peek--recenter))) + +(defun lsp-ui-peek--show (xrefs) + "Create a window to list references/defintions. +XREFS is a list of references/definitions." + (setq lsp-ui-peek--win-start (window-start) + lsp-ui-peek--selection 0 + lsp-ui-peek--offset 0 + lsp-ui-peek--size-list 0 + lsp-ui-peek--list nil) + (when (eq (logand lsp-ui-peek-peek-height 1) 1) + (setq lsp-ui-peek-peek-height (1+ lsp-ui-peek-peek-height))) + (when (< (- (line-number-at-pos (window-end)) (line-number-at-pos)) + (+ lsp-ui-peek-peek-height 3)) + (recenter 15)) + (setq xrefs (--sort (string< (plist-get it :file) (plist-get other :file)) xrefs)) + (--each xrefs + (-let* (((&plist :file filename :xrefs xrefs :count count) it) + (len-str (number-to-string count))) + (setq lsp-ui-peek--size-list (+ lsp-ui-peek--size-list count)) + (push (concat (propertize (if lsp-ui-peek-show-directory + (lsp-ui--workspace-path filename) + (file-name-nondirectory filename)) + 'face 'lsp-ui-peek-filename + 'file filename + 'xrefs xrefs) + (propertize " " 'display `(space :align-to (- right-fringe ,(1+ (length len-str))))) + (propertize len-str 'face 'lsp-ui-peek-filename)) + lsp-ui-peek--list))) + (setq lsp-ui-peek--list (nreverse lsp-ui-peek--list)) + (lsp-ui-peek--expand xrefs) + (lsp-ui-peek--peek)) + +(defun lsp-ui-peek--recenter () + (let ((half-height (/ lsp-ui-peek-peek-height 2))) + (when (> lsp-ui-peek--selection half-height) + (setq lsp-ui-peek--offset (- lsp-ui-peek--selection (1- half-height)))))) + +(defun lsp-ui-peek--fill (min-len list) + (let ((len (length list))) + (if (< len min-len) + (append list (-repeat (- min-len len) "")) + list))) + +(defun lsp-ui-peek--render (major string) + (with-temp-buffer + (insert string) + (delay-mode-hooks + (let ((inhibit-message t)) + (funcall major)) + (ignore-errors + (font-lock-ensure))) + (buffer-string))) + +(defun lsp-ui-peek--peek () + "Show reference's chunk of code." + (-let* ((xref (lsp-ui-peek--get-selection)) + ((&plist :file file :chunk chunk) (or xref lsp-ui-peek--last-xref)) + (header (concat " " (lsp-ui--workspace-path file) "\n")) + (header2 (format " %s %s" lsp-ui-peek--size-list + (string-remove-prefix "workspace/" (string-remove-prefix "textDocument/" lsp-ui-peek--method)))) + (ref-view (--> chunk + (subst-char-in-string ?\t ?\s it) + (concat header it) + (split-string it "\n"))) + (list-refs (->> lsp-ui-peek--list + (--remove (lsp-ui-peek--prop 'lsp-ui-peek-hidden it)) + (-drop lsp-ui-peek--offset) + (-take (1- lsp-ui-peek-peek-height)) + (lsp-ui-peek--fill (1- lsp-ui-peek-peek-height)) + (-concat (list header2))))) + (setq lsp-ui-peek--last-xref (or xref lsp-ui-peek--last-xref)) + (lsp-ui-peek--peek-new ref-view list-refs) + (and (fboundp 'lsp-ui-doc--hide-frame) + (lsp-ui-doc--hide-frame)))) + +(defun lsp-ui-peek--toggle-text-prop (s) + (let ((state (lsp-ui-peek--prop 'lsp-ui-peek-hidden s))) + (lsp-ui-peek--add-prop `(lsp-ui-peek-hidden ,(not state)) s))) + +(defun lsp-ui-peek--toggle-hidden (file) + (setq lsp-ui-peek--list + (--map-when (string= (plist-get (lsp-ui-peek--prop 'lsp-ui-peek it) :file) file) + (prog1 it (lsp-ui-peek--toggle-text-prop it)) + lsp-ui-peek--list))) + +(defun lsp-ui-peek--remove-hidden (file) + (setq lsp-ui-peek--list + (--map-when (string= (plist-get (lsp-ui-peek--prop 'lsp-ui-peek it) :file) file) + (prog1 it (lsp-ui-peek--add-prop '(lsp-ui-peek-hidden nil) it)) + lsp-ui-peek--list))) + +(defun lsp-ui-peek--make-ref-line (xref) + (-let* (((&plist :summary summary :line line :file file) xref) + (string (format "%-3s %s" + (propertize (number-to-string (1+ line)) + 'face 'lsp-ui-peek-line-number) + (string-trim summary)))) + (lsp-ui-peek--add-prop `(lsp-ui-peek ,xref file ,file) string))) + +(defun lsp-ui-peek--insert-xrefs (xrefs filename index) + (setq lsp-ui-peek--list (--> (lsp-ui-peek--get-xrefs-in-file (cons filename xrefs)) + (-map 'lsp-ui-peek--make-ref-line it) + (-insert-at (1+ index) it lsp-ui-peek--list) + (-flatten it))) + (lsp-ui-peek--add-prop '(xrefs nil))) + +(defun lsp-ui-peek--toggle-file (&optional no-update) + (interactive) + (-if-let* ((xrefs (lsp-ui-peek--prop 'xrefs)) + (filename (lsp-ui-peek--prop 'file)) + (index (--find-index (equal (lsp-ui-peek--prop 'file it) filename) + lsp-ui-peek--list))) + (lsp-ui-peek--insert-xrefs xrefs filename index) + (let ((file (lsp-ui-peek--prop 'file))) + (lsp-ui-peek--toggle-hidden file) + (while (not (equal file (lsp-ui-peek--prop 'file))) + (lsp-ui-peek--select-prev t)))) + (unless no-update + (lsp-ui-peek--peek))) + +(defun lsp-ui-peek--select (index) + (setq lsp-ui-peek--selection (+ lsp-ui-peek--selection index))) + +(defun lsp-ui-peek--select-next (&optional no-update) + (interactive) + (when (lsp-ui-peek--get-text-selection (1+ lsp-ui-peek--selection)) + (lsp-ui-peek--select 1) + (while (> (lsp-ui-peek--visual-index) (- lsp-ui-peek-peek-height 2)) + (setq lsp-ui-peek--offset (1+ lsp-ui-peek--offset))) + (unless no-update + (lsp-ui-peek--peek)))) + +(defun lsp-ui-peek--select-prev (&optional no-update) + (interactive) + (when (> lsp-ui-peek--selection 0) + (lsp-ui-peek--select -1) + (while (< (lsp-ui-peek--visual-index) 0) + (setq lsp-ui-peek--offset (1- lsp-ui-peek--offset)))) + (unless no-update + (lsp-ui-peek--peek))) + +(defun lsp-ui-peek--skip-refs (fn) + (let ((last-file (lsp-ui-peek--prop 'file)) + last-selection) + (when (lsp-ui-peek--get-selection) + (while (and (equal (lsp-ui-peek--prop 'file) last-file) + (not (equal last-selection lsp-ui-peek--selection))) + (setq last-selection lsp-ui-peek--selection) + (funcall fn t))))) + +(defun lsp-ui-peek--select-prev-file () + (interactive) + (if (not (lsp-ui-peek--get-selection)) + (lsp-ui-peek--select-prev) + (lsp-ui-peek--skip-refs 'lsp-ui-peek--select-prev) + (when (lsp-ui-peek--get-selection) + (lsp-ui-peek--skip-refs 'lsp-ui-peek--select-prev) + (unless (= lsp-ui-peek--selection 0) + (lsp-ui-peek--select-next t)))) + (if (lsp-ui-peek--prop 'xrefs) + (lsp-ui-peek--toggle-file) + (lsp-ui-peek--remove-hidden (lsp-ui-peek--prop 'file))) + (lsp-ui-peek--select-next t) + (lsp-ui-peek--recenter) + (lsp-ui-peek--peek)) + +(defun lsp-ui-peek--select-next-file () + (interactive) + (lsp-ui-peek--skip-refs 'lsp-ui-peek--select-next) + (if (lsp-ui-peek--prop 'xrefs) + (lsp-ui-peek--toggle-file) + (lsp-ui-peek--remove-hidden (lsp-ui-peek--prop 'file))) + (lsp-ui-peek--select-next t) + (lsp-ui-peek--recenter) + (lsp-ui-peek--peek)) + +(defun lsp-ui-peek--peek-hide () + "Hide the chunk of code and restore previous state." + (when (overlayp lsp-ui-peek--overlay) + (delete-overlay lsp-ui-peek--overlay)) + (setq lsp-ui-peek--overlay nil + lsp-ui-peek--last-xref nil) + (when lsp-ui-peek--win-start + (set-window-start (get-buffer-window) lsp-ui-peek--win-start))) + +(defun lsp-ui-peek--deactivate-keymap () + "Deactivate keymap." + (-when-let (fn lsp-ui-peek--deactivate-keymap-fn) + (setq lsp-ui-peek--deactivate-keymap-fn nil) + (funcall fn))) + +(defun lsp-ui-peek--goto-xref (&optional x other-window) + "Go to a reference/definition." + (interactive) + (-if-let (xref (or x (lsp-ui-peek--get-selection))) + (-let (((&plist :file file :line line :column column) xref) + (buffer (current-buffer))) + (if (not (file-readable-p file)) + (user-error "File not readable: %s" file) + (setq lsp-ui-peek--win-start nil) + (lsp-ui-peek--abort) + (let ((marker (with-current-buffer + (or (get-file-buffer file) + (find-file-noselect file)) + (save-restriction + (widen) + (save-excursion + ;; When we jump to a file with line/column unspecified, + ;; we do not want to move the point if the buffer exists. + ;; We interpret line=column=0 differently here. + (when (> (+ line column) 0) + (goto-char 1) + (forward-line line) + (forward-char column)) + (point-marker))))) + (cur-buffer-workspaces (and (boundp 'lsp--buffer-workspaces) lsp--buffer-workspaces))) + (if other-window + (pop-to-buffer (marker-buffer marker) t) + (switch-to-buffer (marker-buffer marker))) + (with-current-buffer buffer + (lsp-ui-peek-mode -1)) + (unless lsp--buffer-workspaces + (setq lsp--buffer-workspaces cur-buffer-workspaces) + (lsp-mode 1) + (dolist (workspace cur-buffer-workspaces) + (lsp--open-in-workspace workspace))) + (goto-char marker) + (run-hooks 'xref-after-jump-hook)))) + (lsp-ui-peek--toggle-file))) + +(defun lsp-ui-peek--goto-xref-other-window () + (interactive) + (lsp-ui-peek--goto-xref nil t)) + +(defvar lsp-ui-peek-mode-map + (let ((map (make-sparse-keymap))) + (suppress-keymap map t) + (define-key map "\e\e\e" 'lsp-ui-peek--abort) + (define-key map "\C-g" 'lsp-ui-peek--abort) + (define-key map (kbd "M-n") 'lsp-ui-peek--select-next-file) + (define-key map (kbd "<right>") 'lsp-ui-peek--select-next-file) + (define-key map (kbd "M-p") 'lsp-ui-peek--select-prev-file) + (define-key map (kbd "<left>") 'lsp-ui-peek--select-prev-file) + (define-key map (kbd "C-n") 'lsp-ui-peek--select-next) + (define-key map (kbd "n") 'lsp-ui-peek--select-next) + (define-key map (kbd "<down>") 'lsp-ui-peek--select-next) + (define-key map (kbd "C-p") 'lsp-ui-peek--select-prev) + (define-key map (kbd "p") 'lsp-ui-peek--select-prev) + (define-key map (kbd "<up>") 'lsp-ui-peek--select-prev) + (define-key map (kbd "TAB") 'lsp-ui-peek--toggle-file) + (define-key map (kbd "q") 'lsp-ui-peek--abort) + (define-key map (kbd "RET") 'lsp-ui-peek--goto-xref) + (define-key map (kbd "M-RET") 'lsp-ui-peek--goto-xref-other-window) + map) + "Keymap for ‘lsp-ui-peek-mode’.") + +(defun lsp-ui-peek--disable () + "Do not call this function, call `lsp-ui-peek--abort' instead." + (when (bound-and-true-p lsp-ui-peek-mode) + (lsp-ui-peek-mode -1) + (lsp-ui-peek--peek-hide))) + +(defun lsp-ui-peek--abort () + "Abort peek." + (interactive) + ;; The timer fixes https://github.com/emacs-lsp/lsp-ui/issues/33 + (run-with-idle-timer 0 nil 'lsp-ui-peek--disable)) + +(define-minor-mode lsp-ui-peek-mode + "Mode for lsp-ui-peek." + :init-value nil + (if lsp-ui-peek-mode + (setq lsp-ui-peek--deactivate-keymap-fn (set-transient-map lsp-ui-peek-mode-map t 'lsp-ui-peek--abort)) + (lsp-ui-peek--deactivate-keymap) + (lsp-ui-peek--peek-hide))) + +(defun lsp-ui-peek--find-xrefs (input method param) + "Find INPUT references. +METHOD is ‘references’, ‘definitions’, `implementation` or a custom kind. +PARAM is the request params." + (setq lsp-ui-peek--method method) + (let ((xrefs (lsp-ui-peek--get-references method param))) + (unless xrefs + (user-error "Not found for: %s" input)) + (xref-push-marker-stack) + (when (featurep 'evil-jumps) + (lsp-ui-peek--with-evil-jumps (evil-set-jump))) + (if (and (not lsp-ui-peek-always-show) + (not (cdr xrefs)) + (= (length (plist-get (car xrefs) :xrefs)) 1)) + (let ((x (car (plist-get (car xrefs) :xrefs)))) + (-if-let (uri (lsp:location-uri x)) + (-let (((&Range :start (&Position :line :character)) (lsp:location-range x))) + (lsp-ui-peek--goto-xref `(:file ,(lsp--uri-to-path uri) :line ,line :column ,character))) + (-let (((&Range :start (&Position :line :character)) (or (lsp:location-link-target-selection-range x) + (lsp:location-link-target-range x)))) + (lsp-ui-peek--goto-xref `(:file ,(lsp--uri-to-path (lsp:location-link-target-uri x)) :line ,line :column ,character))))) + (lsp-ui-peek-mode) + (lsp-ui-peek--show xrefs)))) + +(defun lsp-ui-peek-find-references (&optional include-declaration extra) + "Find references to the IDENTIFIER at point." + (interactive) + (lsp-ui-peek--find-xrefs (symbol-at-point) "textDocument/references" + (append extra (lsp--make-reference-params nil include-declaration)))) + +(defun lsp-ui-peek-find-definitions (&optional extra) + "Find definitions to the IDENTIFIER at point." + (interactive) + (lsp-ui-peek--find-xrefs (symbol-at-point) "textDocument/definition" + (append extra (lsp--text-document-position-params)))) + +(defun lsp-ui-peek-find-implementation (&optional extra) + "Find implementation locations of the symbol at point." + (interactive) + (lsp-ui-peek--find-xrefs (symbol-at-point) "textDocument/implementation" + (append extra (lsp--text-document-position-params)))) + +(defun lsp-ui-peek-find-workspace-symbol (pattern &optional extra) + "Find symbols in the worskpace. +The symbols are found matching PATTERN." + (interactive (list (read-string "workspace/symbol: " + nil 'xref--read-pattern-history))) + (lsp-ui-peek--find-xrefs pattern "workspace/symbol" + (append extra (lsp-make-workspace-symbol-params :query pattern)))) + +(defun lsp-ui-peek-find-custom (method &optional extra) + "Find custom references. +KIND is a symbol to name the references (definition, reference, ..). +REQUEST is the method string to send the the language server. +EXTRA is a plist of extra parameters." + (lsp-ui-peek--find-xrefs (symbol-at-point) method + (append extra (lsp--text-document-position-params)))) + +(defun lsp-ui-peek--extract-chunk-from-buffer (pos start end) + "Return the chunk of code pointed to by POS (a Position object) in the current buffer. +START and END are delimiters." + (let* ((point (lsp--position-to-point pos)) + (inhibit-field-text-motion t) + (line-start (1+ (- 1 (/ lsp-ui-peek-peek-height 2)))) + (line-end (/ lsp-ui-peek-peek-height 2))) + (save-excursion + (goto-char point) + (let* ((before (buffer-substring (line-beginning-position line-start) (line-beginning-position))) + (line (buffer-substring (line-beginning-position) (line-end-position))) + (after (buffer-substring (line-end-position) (line-end-position line-end))) + (len (length line)) + (chunk (concat before line after)) + (start-in-chunk (length before))) + + (when (eq lsp-ui-peek-fontify 'on-demand) + (setq chunk (lsp-ui-peek--render lsp--peek-save-major-mode chunk))) + + (remove-text-properties (+ (min start len) start-in-chunk) + (+ (if (null end) len (min end len)) start-in-chunk) '(face nil) + chunk) + + (add-face-text-property (+ (min start len) start-in-chunk) + (+ (if (null end) len (min end len)) start-in-chunk) + 'lsp-ui-peek-highlight t chunk) + + `(,(substring chunk start-in-chunk (+ start-in-chunk len)) . ,chunk))))) + +(defun lsp-ui-peek--xref-make-item (filename loc) + "Return an item from FILENAME given a LOC. +LOCATION can be either a LSP Location or SymbolInformation." + ;; TODO: Read more informations from SymbolInformation. + ;; For now, only the location is used. + (-let* ((loc (or (lsp:symbol-information-location loc) loc)) + (range (or (lsp:location-range loc) + (lsp:location-link-target-selection-range loc) + (lsp:location-link-target-range loc))) + ((&Range :start pos-start :end pos-end) range) + ((&Position :line start-line :character start-col) pos-start) + ((&Position :line end-line :character end-col) pos-end) + ((line . chunk) (lsp-ui-peek--extract-chunk-from-buffer pos-start start-col + (when (= start-line end-line) end-col)))) + (list :summary (or line filename) + :chunk (or chunk filename) + :file filename + :line start-line + :column start-col))) + +(defun lsp-ui-peek--fontify-buffer (filename) + (when (eq lsp-ui-peek-fontify 'always) + (unless buffer-file-name + (make-local-variable 'delay-mode-hooks) + (let ((buffer-file-name filename) + (enable-local-variables nil) + (inhibit-message t) + (delay-mode-hooks t)) + (set-auto-mode))) + (font-lock-ensure))) + +(defun lsp-ui-peek--get-xrefs-in-file (file) + "Return all references that contain a file. +FILE is a cons where its car is the filename and the cdr is a list of Locations +within the file. We open and/or create the file/buffer only once for all +references. The function returns a list of `ls-xref-item'." + (let* ((filename (car file)) + (visiting (find-buffer-visiting filename)) + (fn (lambda (loc) (lsp-ui-peek--xref-make-item filename loc)))) + (setq lsp--peek-save-major-mode major-mode) + (cond + (visiting + (with-temp-buffer + (insert-buffer-substring-no-properties visiting) + (lsp-ui-peek--fontify-buffer filename) + (mapcar fn (cdr file)))) + ((file-readable-p filename) + (with-temp-buffer + (insert-file-contents-literally filename) + (lsp-ui-peek--fontify-buffer filename) + (mapcar fn (cdr file)))) + (t (user-error "Cannot read %s" filename))))) + +(defun lsp-ui-peek--get-xrefs-list (file) + "Return a list of xrefs in FILE." + (-let* (((filename . xrefs) file)) + `(:file ,filename :xrefs ,xrefs :count ,(length xrefs)))) + +(defun lsp-ui-peek--get-references (method params) + "Get all references/definitions for the symbol under point. +Returns item(s)." + (-when-let* ((locs (lsp-request method params)) + (locs (if (listp locs) + locs + (if (vectorp locs) + (append locs nil) + (list locs))))) + (-filter + (-lambda ((&plist :file)) + (or (f-file? file) + (ignore + (lsp-log "The following file %s is missing, ignoring from the results." + file)))) + (mapcar #'lsp-ui-peek--get-xrefs-list + (if (lsp:location-uri (car locs)) + ;; Location[] + (--group-by (lsp--uri-to-path (lsp:location-uri it)) locs) + ;; LocationLink[] + (--group-by (lsp--uri-to-path (lsp:location-link-target-uri it)) locs)))))) + +(defvar lsp-ui-mode-map) + +(defun lsp-ui-peek-enable (_enable) + (interactive) + (unless (bound-and-true-p lsp-ui-mode-map) + (user-error "Please load lsp-ui before trying to enable lsp-ui-peek"))) + +;; lsp-ui.el loads lsp-ui-peek.el, so we can’t ‘require’ lsp-ui. +;; FIXME: Remove this cyclic dependency. +(declare-function lsp-ui--workspace-path "lsp-ui" (path)) + +(declare-function evil-set-jump "ext:evil-jumps.el" (&optional pos)) + +(provide 'lsp-ui-peek) +;;; lsp-ui-peek.el ends here diff --git a/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-pkg.el b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-pkg.el new file mode 100644 index 0000000..4b3ae0a --- /dev/null +++ b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-pkg.el @@ -0,0 +1,15 @@ +(define-package "lsp-ui" "20210718.445" "UI modules for lsp-mode" + '((emacs "26.1") + (dash "2.18.0") + (lsp-mode "6.0") + (markdown-mode "2.3")) + :commit "f0e1bb9668da952e62e7a81058b0ebc8e0700a17" :authors + '(("Sebastien Chapuis <sebastien@chapu.is>, Fangrui Song" . "i@maskray.me")) + :maintainer + '("Sebastien Chapuis <sebastien@chapu.is>, Fangrui Song" . "i@maskray.me") + :keywords + '("languages" "tools") + :url "https://github.com/emacs-lsp/lsp-ui") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-sideline.el b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-sideline.el new file mode 100644 index 0000000..d348f02 --- /dev/null +++ b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-sideline.el @@ -0,0 +1,768 @@ +;;; lsp-ui-sideline.el --- Lsp-Ui-Sideline -*- lexical-binding: t -*- + +;; Copyright (C) 2017 Sebastien Chapuis + +;; Author: Sebastien Chapuis <sebastien@chapu.is> +;; URL: https://github.com/emacs-lsp/lsp-ui +;; Keywords: languages, tools +;; Version: 6.2 + +;;; License +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. + +;;; Commentary: +;; +;; Utility to show information for the current line + +;;; Code: + +(require 'lsp-ui-util) +(require 'lsp-protocol) +(require 'lsp-mode) +(require 'flycheck nil 'noerror) +(require 'dash) +(require 'seq) +(require 'subr-x) +(require 'face-remap) + +(defvar flycheck-display-errors-function) +(declare-function flycheck-overlay-errors-in "ext:flycheck.el") +(declare-function flycheck-error-format-message-and-id "ext:flycheck.el") +(declare-function flycheck-error-level "ext:flycheck.el") + +(defgroup lsp-ui-sideline nil + "Display information for the current line." + :group 'tools + :group 'convenience + :group 'lsp-ui + :link '(custom-manual "(lsp-ui-sideline) Top") + :link '(info-link "(lsp-ui-sideline) Customizing")) + +(defcustom lsp-ui-sideline-enable t + "Whether or not to enable ‘lsp-ui-sideline’." + :type 'boolean + :group 'lsp-ui) + +(defcustom lsp-ui-sideline-ignore-duplicate nil + "Ignore duplicates when there is a same symbol with the same contents." + :type 'boolean + :group 'lsp-ui-sideline) + +(defcustom lsp-ui-sideline-show-symbol t + "When t, show the symbol name on the right of the information." + :type 'boolean + :group 'lsp-ui-sideline) + +(defcustom lsp-ui-sideline-show-hover nil + "Whether to show hover messages in sideline." + :type 'boolean + :group 'lsp-ui-sideline) + +(defcustom lsp-ui-sideline-show-diagnostics t + "Whether to show diagnostics messages in sideline." + :type 'boolean + :group 'lsp-ui-sideline) + +(defcustom lsp-ui-sideline-show-code-actions t + "Whether to show code actions in sideline." + :type 'boolean + :group 'lsp-ui-sideline) + +(defcustom lsp-ui-sideline-update-mode 'point + "Define the mode for updating sideline actions. + +When set to `line' the actions will be updated when user +changes current line otherwise the actions will be updated +when user changes current point." + :type '(choice (const line) + (const point)) + :group 'lsp-ui-sideline) + +(defcustom lsp-ui-sideline-delay 0.2 + "Number of seconds to wait before showing sideline." + :type 'number + :group 'lsp-ui-sideline) + +(defcustom lsp-ui-sideline-diagnostic-max-lines 1 + "Maximum number of lines to show of diagnostics in sideline." + :type 'integer + :group 'lsp-ui-sideline) + +(defcustom lsp-ui-sideline-diagnostic-max-line-length 100 + "Maximum line length of diagnostics in sideline." + :type 'integer + :group 'lsp-ui-sideline) + +(defconst lsp-ui-sideline-actions-icon-default + (and (bound-and-true-p lsp-ui-resources-dir) + (image-type-available-p 'png) + (expand-file-name "lightbulb.png" lsp-ui-resources-dir))) + +;; TODO: Set the default actions to `nil' temporarily due to image +;; scale issue on Emacs version 26.3 or below. +;; +;; See #573 +(defcustom lsp-ui-sideline-actions-icon nil + "Image file for actions. It must be a png file." + :type '(choice file (const :tag "Disable" nil)) + :group 'lsp-ui-sideline) + +(defcustom lsp-ui-sideline-wait-for-all-symbols t + "Wait for all symbols before displaying info in sideline." + :type 'boolean + :group 'lsp-ui-sideline) + +(defcustom lsp-ui-sideline-actions-kind-regex "quickfix.*\\|refactor.*" + "Regex for the code actions kinds to show in the sideline." + :type 'string + :group 'lsp-ui-sideline) + +(defvar lsp-ui-sideline-code-actions-prefix "" + "Prefix to insert before the code action title. +This can be used to insert, for example, an unicode character: 💡") + +(defvar-local lsp-ui-sideline--ovs nil + "Overlays used by `lsp-ui-sideline'.") + +(defvar-local lsp-ui-sideline--occupied-lines nil + "List of lines occupied by an overlay of `lsp-ui-sideline'.") + +(defvar-local lsp-ui-sideline--first-line-pushed nil + "Record weather if we display sideline in the first line. + +If we do, then sideline will always look downward instead of the upward +direction. + +This prevent sideline displays below than the first line, which it will cause +weird looking user interface.") + +(defvar-local lsp-ui-sideline--tag nil + "Tag marking where the last operation was based. +It is used to know when the cursor has changed its line or point.") + +(defvar-local lsp-ui-sideline--last-width nil + "Value of window's width on the last operation. +It is used to know when the window has changed of width.") + +(defvar-local lsp-ui-sideline--last-line-number nil + "Line number on the last operation. +Used to avoid calling `line-number-at-pos' when we're on the same line.") + +(defvar-local lsp-ui-sideline--timer nil) + +(defvar-local lsp-ui-sideline--code-actions nil + "Holds the latest code actions.") + +(defvar-local lsp-ui-sideline--cached-infos nil + "Cache of rendered line when `lsp-ui-sideline-wait-for-all-symbols' +is nil. Used to not re-render the same line multiple times.") + +(defface lsp-ui-sideline-symbol + '((t :foreground "grey" + :box (:line-width -1 :color "grey") + :height 0.99)) + "Face used to highlight symbols." + :group 'lsp-ui-sideline) + +(defface lsp-ui-sideline-current-symbol + '((((background light)) + :foreground "black" + :weight ultra-bold + :box (:line-width -1 :color "black") + :height 0.99) + (t :foreground "white" + :weight ultra-bold + :box (:line-width -1 :color "white") + :height 0.99)) + "Face used to highlight the symbol on point." + :group 'lsp-ui-sideline) + +(defface lsp-ui-sideline-code-action + '((((background light)) :foreground "DarkOrange") + (t :foreground "yellow")) + "Face used to highlight code action text." + :group 'lsp-ui-sideline) + +(defface lsp-ui-sideline-symbol-info + '((t :slant italic :height 0.99)) + "Face used to highlight the symbols informations (LSP hover)." + :group 'lsp-ui-sideline) + +(defface lsp-ui-sideline-global + '((t)) + "Face which apply to all overlays. +This face have a low priority over the others." + :group 'lsp-ui-sideline) + +(defun lsp-ui-sideline--first-line-p (pos) + "Return non-nil if POS is on the first line." + (when (integerp pos) + (save-excursion (goto-char 1) (forward-line 1) (> (point) pos)))) + +(defun lsp-ui-sideline--calc-space (win-width str-len index) + "Calculate whether there is enough space on line. +If there is enough space, it returns the point of the last +character on the line. + +WIN-WIDTH is the window width. +STR-LEN is the string size. +INDEX is the line number (relative to the current line)." + (let ((eol (line-end-position index))) + (unless (member eol lsp-ui-sideline--occupied-lines) + (save-excursion + (goto-char eol) + (end-of-line) + (when (>= (- win-width (current-column)) str-len) + eol))))) + +(defun lsp-ui-sideline--find-line (str-len bol eol &optional up offset) + "Find a line where the string can be inserted. + +It loops on the nexts lines to find enough space. Returns the point +of the last character on the line. + +Argument STR-LEN is the string size. +Argument BOL and EOL are beginning and ending of the user point line. +If optional argument UP is non-nil, it loops on the previous lines. +If optional argument OFFSET is non-nil, it starts search OFFSET lines +from user point line." + (let ((win-width (lsp-ui-sideline--window-width)) + (inhibit-field-text-motion t) + (index (if (null offset) 1 offset)) + pos) + (while (and (null pos) (<= (abs index) 30)) + (setq index (if up (1- index) (1+ index))) + (setq pos (lsp-ui-sideline--calc-space win-width str-len index))) + (if (and up (or (null pos) (and (<= pos 1) lsp-ui-sideline--first-line-pushed))) + (lsp-ui-sideline--find-line str-len bol eol nil offset) + (when (and (null lsp-ui-sideline--first-line-pushed) + (lsp-ui-sideline--first-line-p pos)) + (setq lsp-ui-sideline--first-line-pushed t)) ; mark first line push + (and pos (or (> pos eol) (< pos bol)) + (push pos lsp-ui-sideline--occupied-lines) + (list pos (1- index)))))) + +(defun lsp-ui-sideline--delete-ov () + "Delete overlays." + (seq-do 'delete-overlay lsp-ui-sideline--ovs) + (setq lsp-ui-sideline--tag nil + lsp-ui-sideline--cached-infos nil + lsp-ui-sideline--occupied-lines nil + lsp-ui-sideline--first-line-pushed (lsp-ui-sideline--first-line-p (point)) + lsp-ui-sideline--ovs nil)) + +(defun lsp-ui-sideline--extract-info (contents) + "Extract the line to print from CONTENTS. +CONTENTS can be differents type of values: +MarkedString | MarkedString[] | MarkupContent (as defined in the LSP). +We prioritize string with a language (which is probably a type or a +function signature)." + (when contents + (cond + ((lsp-marked-string? contents) contents) + ((vectorp contents) + (seq-find (lambda (it) (and (lsp-marked-string? it) + (lsp-get-renderer (lsp:marked-string-language it)))) + contents)) + ((lsp-markup-content? contents) contents)))) + +(defun lsp-ui-sideline--format-info (marked-string win-width) + "Format MARKED-STRING. +If the string has a language, we fontify it with the function provided +by `lsp-mode'. +MARKED-STRING is the string returned by `lsp-ui-sideline--extract-info'." + (when (and marked-string (or (lsp-marked-string? marked-string) (lsp-markup-content? marked-string))) + (setq marked-string (lsp--render-element marked-string)) + (add-face-text-property 0 (length marked-string) 'lsp-ui-sideline-symbol-info nil marked-string) + (add-face-text-property 0 (length marked-string) 'default t marked-string) + (->> (if (> (length marked-string) (/ win-width 2)) + (car (split-string (string-trim-left marked-string) "[\r\n]+")) + marked-string) + (replace-regexp-in-string "[\n\r\t ]+" " ")))) + +(defun lsp-ui-sideline--align (&rest lengths) + "Align sideline string by LENGTHS from the right of the window." + (+ (apply '+ lengths) + (if (display-graphic-p) 1 2))) + +(defun lsp-ui-sideline--compute-height nil + "Return a fixed size for text in sideline." + (if (null text-scale-mode-remapping) + '(height 1) + ;; Readjust height when text-scale-mode is used + (list 'height + (/ 1 (or (plist-get (cdr text-scale-mode-remapping) :height) + 1))))) + +(defun lsp-ui-sideline--make-display-string (info symbol current) + "Make final string to display in buffer. +INFO is the information to display. +SYMBOL is the symbol associated with the info. +CURRENT is non-nil when the point is on the symbol." + (let* ((face (if current 'lsp-ui-sideline-current-symbol 'lsp-ui-sideline-symbol)) + (str (if lsp-ui-sideline-show-symbol + (concat info " " (propertize (concat " " symbol " ") 'face face)) + info)) + (len (length str)) + (margin (lsp-ui-sideline--margin-width))) + (add-face-text-property 0 len 'lsp-ui-sideline-global nil str) + (concat + (propertize " " 'display `(space :align-to (- right-fringe ,(lsp-ui-sideline--align len margin)))) + (propertize str 'display (lsp-ui-sideline--compute-height))))) + +(defun lsp-ui-sideline--check-duplicate (symbol info) + "Check if there's already a SYMBOL containing INFO, unless `lsp-ui-sideline-ignore-duplicate' +is set to t." + (not (when lsp-ui-sideline-ignore-duplicate + (--any (and (string= (overlay-get it 'symbol) symbol) + (string= (overlay-get it 'info) info)) + lsp-ui-sideline--ovs)))) + +(defun lsp-ui-sideline--margin-width () + (+ (if fringes-outside-margins right-margin-width 0) + (or (and (boundp 'fringe-mode) + (consp fringe-mode) + (or (equal (car fringe-mode) 0) + (equal (cdr fringe-mode) 0)) + 1) + (and (boundp 'fringe-mode) (equal fringe-mode 0) 1) + 0) + (let ((win-fringes (window-fringes))) + (if (or (equal (car win-fringes) 0) + (equal (cadr win-fringes) 0)) + 2 + 0)) + (if (< emacs-major-version 27) + ;; This was necessary with emacs < 27, recent versions take + ;; into account the display-line width with :align-to + (lsp-ui-util-line-number-display-width) + 0) + (if (or + (bound-and-true-p whitespace-mode) + (bound-and-true-p global-whitespace-mode)) + 1 + 0))) + +(defun lsp-ui-sideline--window-width () + (- (min (window-text-width) (window-body-width)) + (lsp-ui-sideline--margin-width) + (or (and (>= emacs-major-version 27) + ;; We still need this number when calculating available space + ;; even with emacs >= 27 + (lsp-ui-util-line-number-display-width)) + 0))) + +(defun lsp-ui-sideline--valid-tag-p (tag mode) + (when tag + (-let ((inhibit-field-text-motion t) + ((p bol _eol buffer) tag)) + (when (and (= bol (line-beginning-position)) + (eq buffer (current-buffer))) + (pcase mode + ('point (eq p (point))) + ('line t) ;; For 'line only bol is relevant + (_ (error "Wrong tag mode"))))))) + +(defun lsp-ui-sideline--display-all-info (list-infos tag bol eol) + (when (and (lsp-ui-sideline--valid-tag-p tag 'line) + (not (lsp-ui-sideline--stop-p))) + (let ((inhibit-modification-hooks t) + (win-width (window-body-width)) + ;; sort by bounds + (list-infos (--sort (< (caadr it) (caadr other)) list-infos))) + (lsp-ui-sideline--delete-kind 'info) + (--each list-infos + (-let (((symbol bounds info) it)) + (lsp-ui-sideline--push-info win-width symbol bounds info bol eol)))))) + +(defun lsp-ui-sideline--push-info (win-width symbol bounds info bol eol) + (let* ((markdown-hr-display-char nil) + (info (or (alist-get info lsp-ui-sideline--cached-infos) + (-some--> (lsp:hover-contents info) + (lsp-ui-sideline--extract-info it) + (lsp-ui-sideline--format-info it win-width) + (progn (push (cons info it) lsp-ui-sideline--cached-infos) it)))) + (current (and (>= (point) (car bounds)) (<= (point) (cdr bounds))))) + (when (and (> (length info) 0) + (lsp-ui-sideline--check-duplicate symbol info)) + (let* ((final-string (lsp-ui-sideline--make-display-string info symbol current)) + (pos-ov (lsp-ui-sideline--find-line (length final-string) bol eol)) + (ov (when pos-ov (make-overlay (car pos-ov) (car pos-ov))))) + (when pos-ov + (overlay-put ov 'info info) + (overlay-put ov 'symbol symbol) + (overlay-put ov 'bounds bounds) + (overlay-put ov 'current current) + (overlay-put ov 'after-string final-string) + (overlay-put ov 'before-string " ") + (overlay-put ov 'window (get-buffer-window)) + (overlay-put ov 'kind 'info) + (overlay-put ov 'position (car pos-ov)) + (push ov lsp-ui-sideline--ovs)))))) + +(defun lsp-ui-sideline--toggle-current (ov current) + "Toggle the OV face according to CURRENT." + (let* ((info (overlay-get ov 'info)) + (symbol (overlay-get ov 'symbol)) + (string (lsp-ui-sideline--make-display-string info symbol current))) + (overlay-put ov 'current current) + (overlay-put ov 'after-string string))) + +(defun lsp-ui-sideline--highlight-current (point) + "Update the symbol's face according to POINT." + (dolist (ov lsp-ui-sideline--ovs) + (let* ((bounds (overlay-get ov 'bounds)) + (start (car bounds)) + (end (cdr bounds))) + (if (and bounds (>= point start) (<= point end)) + (unless (overlay-get ov 'current) + (lsp-ui-sideline--toggle-current ov t)) + (when (overlay-get ov 'current) + (lsp-ui-sideline--toggle-current ov nil)))))) + +(defun lsp-ui-sideline--split-long-lines (lines) + "Fill LINES so that they are not longer than `lsp-ui-sideline-diagnostic-max-line-length' characters." + (cl-mapcan (lambda (line) + (if (< (length line) lsp-ui-sideline-diagnostic-max-line-length) + (list line) + (with-temp-buffer + (let ((fill-column lsp-ui-sideline-diagnostic-max-line-length)) + (insert line) + (fill-region (point-min) (point-max)) + (split-string (buffer-string) "\n"))))) + lines)) + +(defun lsp-ui-sideline--diagnostics (buffer bol eol) + "Show diagnostics belonging to the current line. +Loop over flycheck errors with `flycheck-overlay-errors-in'. +Find appropriate position for sideline overlays with `lsp-ui-sideline--find-line'. +Push sideline overlays on `lsp-ui-sideline--ovs'." + (when (and (bound-and-true-p flycheck-mode) + (bound-and-true-p lsp-ui-sideline-mode) + lsp-ui-sideline-show-diagnostics + (eq (current-buffer) buffer)) + (lsp-ui-sideline--delete-kind 'diagnostics) + (dolist (e (flycheck-overlay-errors-in bol (1+ eol))) + (let* ((lines (--> (flycheck-error-format-message-and-id e) + (split-string it "\n") + (lsp-ui-sideline--split-long-lines it))) + (display-lines (butlast lines (- (length lines) lsp-ui-sideline-diagnostic-max-lines))) + (offset 1)) + (dolist (line (nreverse display-lines)) + (let* ((msg (string-trim (replace-regexp-in-string "[\t ]+" " " line))) + (msg (replace-regexp-in-string " " " " msg)) + (len (length msg)) + (level (flycheck-error-level e)) + (face (if (eq level 'info) 'success level)) + (margin (lsp-ui-sideline--margin-width)) + (msg (progn (add-face-text-property 0 len 'lsp-ui-sideline-global nil msg) + (add-face-text-property 0 len face nil msg) + msg)) + (string (concat (propertize " " 'display `(space :align-to (- right-fringe ,(lsp-ui-sideline--align len margin)))) + (propertize msg 'display (lsp-ui-sideline--compute-height)))) + (pos-ov (lsp-ui-sideline--find-line len bol eol t offset)) + (ov (and pos-ov (make-overlay (car pos-ov) (car pos-ov))))) + (when pos-ov + (setq offset (1+ (car (cdr pos-ov)))) + (overlay-put ov 'after-string string) + (overlay-put ov 'kind 'diagnostics) + (overlay-put ov 'before-string " ") + (overlay-put ov 'position (car pos-ov)) + (push ov lsp-ui-sideline--ovs)))))))) + +(defun lsp-ui-sideline-apply-code-actions nil + "Choose and apply code action(s) on the current line." + (interactive) + (unless lsp-ui-sideline--code-actions + (user-error "No code actions on the current line")) + (lsp-execute-code-action (lsp--select-action lsp-ui-sideline--code-actions))) + +(defun lsp-ui-sideline-set-default-icon () + "Set default icon for sideline actions." + (setq lsp-ui-sideline-actions-icon lsp-ui-sideline-actions-icon-default)) + +(defun lsp-ui-sideline--scale-lightbulb (height) + "Scale the lightbulb image to character height. + +Argument HEIGHT is an actual image height in pixel." + (--> (- (frame-char-height) 1) + (/ (float it) height))) + +(defun lsp-ui-sideline--code-actions-make-image nil + (let ((is-default (equal lsp-ui-sideline-actions-icon lsp-ui-sideline-actions-icon-default))) + (--> `(image :type png :file ,lsp-ui-sideline-actions-icon :ascent center) + (append it `(:scale ,(->> (cond (is-default 128) + ((fboundp 'image-size) (cdr (image-size it t))) + (t (error "Function image-size undefined. Use default icon"))) + (lsp-ui-sideline--scale-lightbulb))))))) + +(defun lsp-ui-sideline--code-actions-image nil + (when lsp-ui-sideline-actions-icon + (with-demoted-errors "[lsp-ui-sideline]: Error with actions icon: %s" + (concat + (propertize " " 'display (lsp-ui-sideline--code-actions-make-image)) + (propertize " " 'display '(space :width 0.3)))))) + +(defun lsp-ui-sideline--code-actions (actions bol eol) + "Show code ACTIONS." + (let ((inhibit-modification-hooks t)) + (when lsp-ui-sideline-actions-kind-regex + (setq actions (seq-filter (-lambda ((&CodeAction :kind?)) + (or (not kind?) + (s-match lsp-ui-sideline-actions-kind-regex kind?))) + actions))) + (setq lsp-ui-sideline--code-actions actions) + (lsp-ui-sideline--delete-kind 'actions) + (seq-doseq (action actions) + (-let* ((title (->> (lsp:code-action-title action) + (replace-regexp-in-string "[\n\t ]+" " ") + (replace-regexp-in-string " " " ") + (concat (unless lsp-ui-sideline-actions-icon + lsp-ui-sideline-code-actions-prefix)))) + (image (lsp-ui-sideline--code-actions-image)) + (margin (lsp-ui-sideline--margin-width)) + (keymap (let ((map (make-sparse-keymap))) + (define-key map [down-mouse-1] (lambda () (interactive) + (save-excursion + (lsp-execute-code-action action)))) + map)) + (len (length title)) + (title (progn (add-face-text-property 0 len 'lsp-ui-sideline-global nil title) + (add-face-text-property 0 len 'lsp-ui-sideline-code-action nil title) + (add-text-properties 0 len `(keymap ,keymap mouse-face highlight) title) + title)) + (string (concat (propertize " " 'display `(space :align-to (- right-fringe ,(lsp-ui-sideline--align (+ len (length image)) margin)))) + image + (propertize title 'display (lsp-ui-sideline--compute-height)))) + (pos-ov (lsp-ui-sideline--find-line (+ 1 (length title) (length image)) bol eol t)) + (ov (and pos-ov (make-overlay (car pos-ov) (car pos-ov))))) + (when pos-ov + (overlay-put ov 'after-string string) + (overlay-put ov 'before-string " ") + (overlay-put ov 'kind 'actions) + (overlay-put ov 'position (car pos-ov)) + (push ov lsp-ui-sideline--ovs)))))) + +(defun lsp-ui-sideline--calculate-tag nil + "Calculate the tag used to determine whether to update sideline information." + (let ((inhibit-field-text-motion t)) + (list (point) (line-beginning-position) (line-end-position) (current-buffer)))) + +(defun lsp-ui-sideline--delete-kind (kind) + (->> (--remove + (when (eq (overlay-get it 'kind) kind) + (--> (overlay-get it 'position) + (remq it lsp-ui-sideline--occupied-lines) + (setq lsp-ui-sideline--occupied-lines it)) + (delete-overlay it) + t) + lsp-ui-sideline--ovs) + (setq lsp-ui-sideline--ovs))) + +(defvar-local lsp-ui-sideline--last-tick-info nil) +(defvar-local lsp-ui-sideline--previous-line nil) + +(defun lsp-ui-sideline--get-line (bol eol) + (buffer-substring-no-properties bol eol)) + +(defun lsp-ui-sideline--line-diags (line) + (->> (--filter + (let ((range (lsp-get it :range))) + (or (-some-> range (lsp-get :start) (lsp-get :line) (= line)) + (-some-> range (lsp-get :end) (lsp-get :line) (= line)))) + (lsp--get-buffer-diagnostics)) + (apply 'vector))) + +(defun lsp-ui-sideline--run (&optional buffer bol eol this-line) + "Show information (flycheck + lsp). +It loops on the symbols of the current line and requests information +from the language server." + (when buffer-file-name + (let* ((inhibit-field-text-motion t) + (tag (lsp-ui-sideline--calculate-tag)) + (eol (or eol (nth 2 tag))) + (bol (or bol (nth 1 tag))) + (this-tick (buffer-modified-tick)) + (line-changed (not (lsp-ui-sideline--valid-tag-p lsp-ui-sideline--tag 'line))) + (line-widen (or (and (not line-changed) lsp-ui-sideline--last-line-number) + (and (buffer-narrowed-p) (save-restriction (widen) (line-number-at-pos))) + (line-number-at-pos))) + (new-tick (unless line-changed (not (equal this-tick lsp-ui-sideline--last-tick-info)))) + (this-line (or this-line (lsp-ui-sideline--get-line bol eol))) + (line-modified (and new-tick (not (equal this-line lsp-ui-sideline--previous-line)))) + (doc-id (lsp--text-document-identifier)) + (inhibit-modification-hooks t) + symbols) + (setq lsp-ui-sideline--tag tag + lsp-ui-sideline--last-line-number line-widen + lsp-ui-sideline--last-width (window-text-width)) + (when (and line-changed lsp-ui-sideline-show-diagnostics) + (lsp-ui-sideline--diagnostics buffer bol eol)) + (when (and lsp-ui-sideline-show-code-actions + (or (lsp--capability "codeActionProvider") + (lsp--registered-capability "textDocument/codeAction"))) + (lsp-request-async + "textDocument/codeAction" + (-let (((start . end) (if (eq lsp-ui-sideline-update-mode 'line) + (cons 0 (- eol bol)) + (--> (- (point) bol) (cons it it))))) + (list :textDocument doc-id + :range (list :start (list :line (1- line-widen) :character start) + :end (list :line (1- line-widen) :character end)) + :context (list :diagnostics (lsp-ui-sideline--line-diags (1- line-widen))))) + (lambda (actions) + (when (eq (current-buffer) buffer) + (lsp-ui-sideline--code-actions actions bol eol))) + :mode 'tick + :error-handler + (lambda (&rest _) + (lsp-ui-sideline--delete-kind 'actions)) + :cancel-token :lsp-ui-code-actions)) + ;; Go through all symbols and request hover information. Note that the symbols are + ;; traversed backwards as `forward-symbol' with a positive argument will jump just past the + ;; current symbol. By going from the end of the line towards the front, point will be placed + ;; at the beginning of each symbol. As the requests are first collected in a list before + ;; being processed they are still sent in order from left to right. + (when (and lsp-ui-sideline-show-hover (or line-changed line-modified) (lsp--capability "hoverProvider")) + (setq lsp-ui-sideline--last-tick-info this-tick + lsp-ui-sideline--previous-line this-line) + (save-excursion + (goto-char eol) + (while (and (> (point) bol) + (progn (forward-symbol -1) + (>= (point) bol))) + (let* ((symbol (thing-at-point 'symbol t)) + (bounds (bounds-of-thing-at-point 'symbol)) + (parsing-state (syntax-ppss)) + (in-string (nth 3 parsing-state)) + (outside-comment (eq (nth 4 parsing-state) nil))) + ;; Skip strings and comments + (when (and symbol (not in-string) outside-comment) + (push (list symbol bounds (list :line (1- line-widen) :character (- (point) bol))) symbols)))) + (if (null symbols) + (lsp-ui-sideline--delete-kind 'info) + (let ((length-symbols (length symbols)) + (current-index 0) + list-infos) + (--each symbols + (-let (((symbol bounds position) it)) + (lsp-request-async + "textDocument/hover" + (lsp-make-hover-params :text-document doc-id :position position) + (lambda (info) + (cl-incf current-index) + (and info (push (list symbol bounds info) list-infos)) + (when (or (= current-index length-symbols) (not lsp-ui-sideline-wait-for-all-symbols)) + (lsp-ui-sideline--display-all-info list-infos tag bol eol))) + :error-handler + (lambda (&rest _) + (cl-incf current-index) + (when (or (= current-index length-symbols) (not lsp-ui-sideline-wait-for-all-symbols)) + (lsp-ui-sideline--display-all-info list-infos tag bol eol))) + :mode 'tick)))))))))) + +(defun lsp-ui-sideline--stop-p () + "Return non-nil if the sideline should not be display." + (or (region-active-p) + (bound-and-true-p company-pseudo-tooltip-overlay) + (bound-and-true-p lsp-ui-peek--overlay))) + +(defun lsp-ui-sideline--hide-before-company (command) + "Disable the sideline before company's overlay appears. +COMMAND is `company-pseudo-tooltip-frontend' parameter." + (when (memq command '(post-command update)) + (lsp-ui-sideline--delete-ov))) + +(defun lsp-ui-sideline () + "Show information for the current line." + (if (lsp-ui-sideline--stop-p) + (lsp-ui-sideline--delete-ov) + (let* ((inhibit-field-text-motion t) + (same-line (lsp-ui-sideline--valid-tag-p lsp-ui-sideline--tag 'line)) + (same-width (equal (window-text-width) lsp-ui-sideline--last-width)) + (new-tick (and same-line (not (equal (buffer-modified-tick) lsp-ui-sideline--last-tick-info)))) + (bol (and new-tick (line-beginning-position))) + (eol (and new-tick (line-end-position))) + (this-line (and new-tick (lsp-ui-sideline--get-line bol eol))) + (unmodified (if new-tick (equal this-line lsp-ui-sideline--previous-line) t)) + (buffer (current-buffer)) + (point (point))) + (cond ((and unmodified same-line same-width) + (lsp-ui-sideline--highlight-current (point))) + ((not (and same-line same-width)) + (lsp-ui-sideline--delete-ov))) + (when lsp-ui-sideline--timer + (cancel-timer lsp-ui-sideline--timer)) + (setq lsp-ui-sideline--timer + (run-with-idle-timer + lsp-ui-sideline-delay nil + (lambda nil + ;; run lsp-ui only if current-buffer is the same. + (and (eq buffer (current-buffer)) + (= point (point)) + (lsp-ui-sideline--run buffer bol eol this-line)))))))) + +(defun lsp-ui-sideline-toggle-symbols-info () + "Toggle display of symbols information. +This does not toggle display of flycheck diagnostics or code actions." + (interactive) + (when (bound-and-true-p lsp-ui-sideline-mode) + (setq lsp-ui-sideline-show-hover (not lsp-ui-sideline-show-hover)) + (lsp-ui-sideline--run (current-buffer)))) + +(defun lsp-ui-sideline--diagnostics-changed () + "Handler for flycheck notifications." + (when lsp-ui-sideline-show-diagnostics + (let* ((buffer (current-buffer)) + (inhibit-field-text-motion t) + (eol (line-end-position)) + (bol (line-beginning-position))) + (lsp-ui-sideline--diagnostics buffer bol eol)))) + +(defun lsp-ui-sideline--erase (&rest _) + "Remove all sideline overlays and delete last tag." + (when (bound-and-true-p lsp-ui-sideline-mode) + (ignore-errors (lsp-ui-sideline--delete-ov)))) + +(define-minor-mode lsp-ui-sideline-mode + "Minor mode for showing information for current line." + :init-value nil + :group lsp-ui-sideline + (cond + (lsp-ui-sideline-mode + (add-hook 'post-command-hook 'lsp-ui-sideline nil t) + (advice-add 'company-pseudo-tooltip-frontend :before 'lsp-ui-sideline--hide-before-company) + (add-hook 'flycheck-after-syntax-check-hook 'lsp-ui-sideline--diagnostics-changed nil t) + (when lsp-ui-sideline-show-diagnostics + (setq-local flycheck-display-errors-function nil))) + (t + (advice-remove 'company-pseudo-tooltip-frontend 'lsp-ui-sideline--hide-before-company) + (lsp-ui-sideline--delete-ov) + (remove-hook 'flycheck-after-syntax-check-hook 'lsp-ui-sideline--diagnostics-changed t) + (remove-hook 'post-command-hook 'lsp-ui-sideline t) + (when lsp-ui-sideline-show-diagnostics + (kill-local-variable 'flycheck-display-errors-function))))) + +(defun lsp-ui-sideline-enable (enable) + "Enable/disable `lsp-ui-sideline-mode'." + (lsp-ui-sideline-mode (if enable 1 -1)) + (if enable + (add-hook 'before-revert-hook 'lsp-ui-sideline--delete-ov nil t) + (remove-hook 'before-revert-hook 'lsp-ui-sideline--delete-ov t))) + +(provide 'lsp-ui-sideline) +;;; lsp-ui-sideline.el ends here diff --git a/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-util.el b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-util.el new file mode 100644 index 0000000..a5d92f2 --- /dev/null +++ b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui-util.el @@ -0,0 +1,71 @@ +;;; lsp-ui-util.el --- Utility module for Lsp-Ui -*- lexical-binding: t -*- + +;; Copyright (C) 2020 Shen, Jen-Chieh + +;; Author: Jen-Chieh Shen <jcs090218@gmail.com> +;; URL: https://github.com/emacs-lsp/lsp-ui +;; Keywords: languages, tools +;; Version: 6.2 + +;;; License +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; +;; Utility module for Lsp-Ui. +;; + +;;; Code: + +(require 'face-remap) + +(defun lsp-ui-util-safe-kill-timer (timer) + "Safely kill the TIMER." + (when (timerp timer) (cancel-timer timer))) + +(defun lsp-ui-util-safe-delete-overlay (overlay) + "Safely delete the OVERLAY." + (when (overlayp overlay) (delete-overlay overlay))) + +(defun lsp-ui-util-line-number-display-width () + "Safe way to get value from function `line-number-display-width'." + (if (bound-and-true-p display-line-numbers-mode) + ;; For some reason, function `line-number-display-width' gave + ;; us error `args-out-of-range' even we do not pass anything towards + ;; to it function. See the following links, + ;; + ;; - https://github.com/emacs-lsp/lsp-ui/issues/294 + ;; - https://github.com/emacs-lsp/lsp-ui/issues/533 (duplicate) + (+ (or (ignore-errors (line-number-display-width)) 0) 2) + 0)) + +(defun lsp-ui-util-line-string (pos) + "Return string at POS." + (when (integerp pos) (save-excursion (goto-char pos) (thing-at-point 'line)))) + +(defun lsp-ui-util-column (&optional pos) + "Return column at POS." + (setq pos (or pos (point))) + (save-excursion (goto-char pos) (current-column))) + +(defun lsp-ui-util-text-scale-factor () + "Return the factor effect by `text-scale-mode'." + (or (plist-get (cdr text-scale-mode-remapping) :height) 1)) + +(provide 'lsp-ui-util) +;;; lsp-ui-util.el ends here diff --git a/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui.el b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui.el new file mode 100644 index 0000000..cbaf923 --- /dev/null +++ b/emacs.d/elpa/lsp-ui-20210718.445/lsp-ui.el @@ -0,0 +1,177 @@ +;;; lsp-ui.el --- UI modules for lsp-mode -*- lexical-binding: t; -*- + +;; Copyright (C) 2017 Tobias Pisani +;; Copyright (C) 2018 Sebastien Chapuis, Fangrui Song + +;; Author: Sebastien Chapuis <sebastien@chapu.is>, Fangrui Song <i@maskray.me> +;; Keywords: languages, tools +;; URL: https://github.com/emacs-lsp/lsp-ui +;; Package-Requires: ((emacs "26.1") (dash "2.18.0") (lsp-mode "6.0") (markdown-mode "2.3")) +;; Version: 7.0.1 + +;;; License +;; +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. + +;;; Commentary: + +;; lsp-ui contains a series of useful UI integrations for lsp-mode, like +;; flycheck support and code lenses. + +;;; Code: + +(require 'dash) +(require 'lsp-protocol) +(require 'find-func) + +(defconst lsp-ui-resources-dir + (--> (find-library-name "lsp-ui") + (file-name-directory it) + (expand-file-name "resources" it) + (file-name-as-directory it) + (and (file-directory-p it) it)) + "Resource folder for package `lsp-ui'.") + +(require 'lsp-ui-sideline) +(require 'lsp-ui-peek) +(require 'lsp-ui-imenu) +(require 'lsp-ui-doc) + +(defgroup lsp-ui nil + "‘lsp-ui’ contains a series of useful UI integrations for ‘lsp-mode’." + :group 'tools + :group 'convenience + :link '(custom-manual "(lsp-ui) Top") + :link '(info-link "(lsp-ui) Customizing")) + +(with-eval-after-load 'flycheck + (require 'lsp-ui-flycheck)) + +(with-eval-after-load 'winum + (when (and (boundp 'winum-ignored-buffers-regexp) lsp-ui-doc-winum-ignore) + (add-to-list 'winum-ignored-buffers-regexp lsp-ui-doc--buffer-prefix))) + +(defun lsp-ui-peek--render (major string) + (with-temp-buffer + (insert string) + (delay-mode-hooks + (let ((inhibit-message t)) (funcall major)) + (ignore-errors (font-lock-ensure))) + (buffer-string))) + +(defun lsp-ui--workspace-path (path) + "Return the PATH relative to the workspace. +If the PATH is not in the workspace, it returns the original PATH." + (let* ((path (file-truename path)) + (root (lsp-workspace-root path)) + (in-workspace (and root (string-prefix-p root path)))) + (if in-workspace + (substring path (length root)) + path))) + +(defun lsp-ui--toggle (enable) + (dolist (feature '(lsp-ui-peek lsp-ui-sideline lsp-ui-doc lsp-ui-imenu)) + (let* ((sym (--> (intern-soft (concat (symbol-name feature) "-enable")) + (and (boundp it) it))) + (value (symbol-value sym)) + (fn (symbol-function sym))) + (and (or value (not enable)) + (functionp fn) + (funcall fn enable))))) + +(defvar lsp-ui-mode-map (make-sparse-keymap)) + +;;;###autoload +(define-minor-mode lsp-ui-mode + "Toggle language server UI mode on or off. +‘lsp-ui-mode’ is a minor mode that contains a series of useful UI +integrations for ‘lsp-mode’. With a prefix argument ARG, enable +language server UI mode if ARG is positive, and disable it +otherwise. If called from Lisp, enable the mode if ARG is +omitted or nil, and toggle it if ARG is ‘toggle’." + :init-value nil + :group lsp-ui + :keymap lsp-ui-mode-map + (lsp-ui--toggle lsp-ui-mode)) + +;; The request is delegated to xref-backend-apropos defined in lsp-mode. +;; xref-find-apropos does similar job but is less appealing because it splits and +;; regex quotes the pattern. The language server likely knows more about how +;; to do fuzzy matching. +(defun lsp-ui-find-workspace-symbol (pattern) + "List project-wide symbols matching the query string PATTERN." + (interactive (list (read-string + "workspace/symbol: " + nil 'xref--read-pattern-history))) + (xref--find-xrefs pattern 'apropos pattern nil)) + +(defun lsp-ui--location< (x y) + "Compares two triples X and Y. +Both should have the form (FILENAME LINE COLUMN)." + (if (not (string= (car x) (car y))) + (string< (car x) (car y)) + (if (not (= (cadr x) (cadr y))) + (< (cadr x) (cadr y)) + (< (caddr x) (caddr y))))) + +(defun lsp-ui--reference-triples (extra) + "Return references as a list of (FILENAME LINE COLUMN) triples given EXTRA." + (let ((refs (lsp-request "textDocument/references" + (append (lsp--text-document-position-params) extra)))) + (sort + (mapcar + (-lambda ((&Location :uri :range (&Range :start (&Position :line :character)))) + (list (lsp--uri-to-path uri) line character)) + refs) + #'lsp-ui--location<))) + +;; TODO Make it efficient +(defun lsp-ui-find-next-reference (&optional extra) + "Find next reference of the symbol at point." + (interactive) + (let* ((cur (list buffer-file-name (1- (line-number-at-pos)) (- (point) (line-beginning-position)))) + (refs (lsp-ui--reference-triples extra)) + (idx -1) + (res (-first (lambda (ref) (cl-incf idx) (lsp-ui--location< cur ref)) refs))) + (if res + (progn + (find-file (car res)) + (goto-char 1) + (forward-line (cadr res)) + (forward-char (caddr res)) + (cons idx (length refs))) + (cons 0 0)))) + +;; TODO Make it efficient +(defun lsp-ui-find-prev-reference (&optional extra) + "Find previous reference of the symbol at point." + (interactive) + (let* ((cur (list buffer-file-name (1- (line-number-at-pos)) (- (point) (line-beginning-position)))) + (refs (lsp-ui--reference-triples extra)) + (idx -1) + (res (-last (lambda (ref) (and (lsp-ui--location< ref cur) (cl-incf idx))) refs))) + (if res + (progn + (find-file (car res)) + (goto-char 1) + (forward-line (cadr res)) + (forward-char (caddr res)) + (cons idx (length refs))) + (cons 0 0)))) + + +(provide 'lsp-ui) +;;; lsp-ui.el ends here diff --git a/emacs.d/elpa/lsp-ui-20210718.445/resources/lightbulb.png b/emacs.d/elpa/lsp-ui-20210718.445/resources/lightbulb.png Binary files differnew file mode 100644 index 0000000..7c1ad08 --- /dev/null +++ b/emacs.d/elpa/lsp-ui-20210718.445/resources/lightbulb.png diff --git a/emacs.d/elpa/lv-20200507.1518/lv-autoloads.el b/emacs.d/elpa/lv-20200507.1518/lv-autoloads.el new file mode 100644 index 0000000..61b1079 --- /dev/null +++ b/emacs.d/elpa/lv-20200507.1518/lv-autoloads.el @@ -0,0 +1,22 @@ +;;; lv-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "lv" "lv.el" (0 0 0 0)) +;;; Generated autoloads from lv.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "lv" '("lv-"))) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; lv-autoloads.el ends here diff --git a/emacs.d/elpa/lv-20200507.1518/lv-pkg.el b/emacs.d/elpa/lv-20200507.1518/lv-pkg.el new file mode 100644 index 0000000..0ef0d4b --- /dev/null +++ b/emacs.d/elpa/lv-20200507.1518/lv-pkg.el @@ -0,0 +1,2 @@ +;;; Generated package description from lv-20200507.1518/lv.el -*- no-byte-compile: t -*- +(define-package "lv" "20200507.1518" "Other echo area" 'nil :commit "2d553787aca1aceb3e6927e426200e9bb9f056f1" :authors '(("Oleh Krehel")) :maintainer '("Oleh Krehel")) diff --git a/emacs.d/elpa/lv-20200507.1518/lv.el b/emacs.d/elpa/lv-20200507.1518/lv.el new file mode 100644 index 0000000..cafcbb1 --- /dev/null +++ b/emacs.d/elpa/lv-20200507.1518/lv.el @@ -0,0 +1,150 @@ +;;; lv.el --- Other echo area +;; Package-Version: 20200507.1518 +;; Package-Commit: 2d553787aca1aceb3e6927e426200e9bb9f056f1 + +;; Copyright (C) 2015 Free Software Foundation, Inc. + +;; Author: Oleh Krehel + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: +;; +;; This package provides `lv-message' intended to be used in place of +;; `message' when semi-permanent hints are needed, in order to not +;; interfere with Echo Area. +;; +;; "Я тихо-тихо пiдглÑдаю, +;; І Ñ‚iшуÑÑ Ñобi, Ñк бачу то, +;; Шо Ñтрашить i не пiдпуÑкає, +;; Ð iншi п’ють тебе, Ñк воду пiÑок." +;; -- Ðндрій Кузьменко, L.V. + +;;; Code: + +(require 'cl-lib) + +(defgroup lv nil + "The other echo area." + :group 'minibuffer + :group 'hydra) + +(defcustom lv-use-separator nil + "Whether to draw a line between the LV window and the Echo Area." + :group 'lv + :type 'boolean) + +(defcustom lv-use-padding nil + "Whether to use horizontal padding in the LV window." + :group 'lv + :type 'boolean) + +(defface lv-separator + '((((class color) (background light)) :background "grey80") + (((class color) (background dark)) :background "grey30")) + "Face used to draw line between the lv window and the echo area. +This is only used if option `lv-use-separator' is non-nil. +Only the background color is significant." + :group 'lv) + +(defvar lv-wnd nil + "Holds the current LV window.") + +(defvar display-line-numbers) +(defvar display-fill-column-indicator) +(defvar tab-line-format) + +(defvar lv-window-hook nil + "Hook to run by `lv-window' when a new window is created.") + +(defun lv-window () + "Ensure that LV window is live and return it." + (if (window-live-p lv-wnd) + lv-wnd + (let ((ori (selected-window)) + buf) + (prog1 (setq lv-wnd + (select-window + (let ((ignore-window-parameters t)) + (split-window + (frame-root-window) -1 'below)) + 'norecord)) + (if (setq buf (get-buffer " *LV*")) + (switch-to-buffer buf 'norecord) + (switch-to-buffer " *LV*" 'norecord) + (fundamental-mode) + (set-window-hscroll lv-wnd 0) + (setq window-size-fixed t) + (setq mode-line-format nil) + (setq header-line-format nil) + (setq tab-line-format nil) + (setq cursor-type nil) + (setq display-line-numbers nil) + (setq display-fill-column-indicator nil) + (set-window-dedicated-p lv-wnd t) + (set-window-parameter lv-wnd 'no-other-window t) + (run-hooks 'lv-window-hook)) + (select-window ori 'norecord))))) + +(defvar golden-ratio-mode) + +(defvar lv-force-update nil + "When non-nil, `lv-message' will refresh even for the same string.") + +(defun lv--pad-to-center (str width) + "Pad STR with spaces on the left to be centered to WIDTH." + (let* ((strs (split-string str "\n")) + (padding (make-string + (/ (- width (length (car strs))) 2) + ?\ ))) + (mapconcat (lambda (s) (concat padding s)) strs "\n"))) + +(defun lv-message (format-string &rest args) + "Set LV window contents to (`format' FORMAT-STRING ARGS)." + (let* ((str (apply #'format format-string args)) + (n-lines (cl-count ?\n str)) + deactivate-mark + golden-ratio-mode) + (with-selected-window (lv-window) + (when lv-use-padding + (setq str (lv--pad-to-center str (window-width)))) + (unless (and (string= (buffer-string) str) + (null lv-force-update)) + (delete-region (point-min) (point-max)) + (insert str) + (when (and (window-system) lv-use-separator) + (unless (looking-back "\n" nil) + (insert "\n")) + (insert + (propertize "__" 'face 'lv-separator 'display '(space :height (1))) + (propertize "\n" 'face 'lv-separator 'line-height t))) + (set (make-local-variable 'window-min-height) n-lines) + (setq truncate-lines (> n-lines 1)) + (let ((window-resize-pixelwise t) + (window-size-fixed nil)) + (fit-window-to-buffer nil nil 1))) + (goto-char (point-min))))) + +(defun lv-delete-window () + "Delete LV window and kill its buffer." + (when (window-live-p lv-wnd) + (let ((buf (window-buffer lv-wnd))) + (delete-window lv-wnd) + (kill-buffer buf)))) + +(provide 'lv) + +;;; lv.el ends here diff --git a/emacs.d/elpa/project-0.6.0.signed b/emacs.d/elpa/project-0.6.0.signed new file mode 100644 index 0000000..f4efdd2 --- /dev/null +++ b/emacs.d/elpa/project-0.6.0.signed @@ -0,0 +1 @@ +Good signature from 066DAFCB81E42C40 GNU ELPA Signing Agent (2019) <elpasign@elpa.gnu.org> (trust undefined) created at 2021-04-29T12:05:02+0300 using RSA
\ No newline at end of file diff --git a/emacs.d/elpa/project-0.6.0/project-autoloads.el b/emacs.d/elpa/project-0.6.0/project-autoloads.el new file mode 100644 index 0000000..4010bb1 --- /dev/null +++ b/emacs.d/elpa/project-0.6.0/project-autoloads.el @@ -0,0 +1,234 @@ +;;; project-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "project" "project.el" (0 0 0 0)) +;;; Generated autoloads from project.el + +(autoload 'project-current "project" "\ +Return the project instance in DIRECTORY, defaulting to `default-directory'. + +When no project is found in that directory, the result depends on +the value of MAYBE-PROMPT: if it is nil or omitted, return nil, +else ask the user for a directory in which to look for the +project, and if no project is found there, return a \"transient\" +project instance. + +The \"transient\" project instance is a special kind of value +which denotes a project rooted in that directory and includes all +the files under the directory except for those that should be +ignored (per `project-ignores'). + +See the doc string of `project-find-functions' for the general form +of the project instance object. + +\(fn &optional MAYBE-PROMPT DIRECTORY)" nil nil) + +(defvar project-prefix-map (let ((map (make-sparse-keymap))) (define-key map "!" 'project-shell-command) (define-key map "&" 'project-async-shell-command) (define-key map "f" 'project-find-file) (define-key map "F" 'project-or-external-find-file) (define-key map "b" 'project-switch-to-buffer) (define-key map "s" 'project-shell) (define-key map "d" 'project-dired) (define-key map "v" 'project-vc-dir) (define-key map "c" 'project-compile) (define-key map "e" 'project-eshell) (define-key map "k" 'project-kill-buffers) (define-key map "p" 'project-switch-project) (define-key map "g" 'project-find-regexp) (define-key map "G" 'project-or-external-find-regexp) (define-key map "r" 'project-query-replace-regexp) (define-key map "x" 'project-execute-extended-command) map) "\ +Keymap for project commands.") + (define-key ctl-x-map "p" project-prefix-map) + +(autoload 'project-other-window-command "project" "\ +Run project command, displaying resultant buffer in another window. + +The following commands are available: + +\\{project-prefix-map} +\\{project-other-window-map}" t nil) + (define-key ctl-x-4-map "p" #'project-other-window-command) + +(autoload 'project-other-frame-command "project" "\ +Run project command, displaying resultant buffer in another frame. + +The following commands are available: + +\\{project-prefix-map} +\\{project-other-frame-map}" t nil) + (define-key ctl-x-5-map "p" #'project-other-frame-command) + +(autoload 'project-other-tab-command "project" "\ +Run project command, displaying resultant buffer in a new tab. + +The following commands are available: + +\\{project-prefix-map}" t nil) + +(when (bound-and-true-p tab-prefix-map) (define-key tab-prefix-map "p" #'project-other-tab-command)) + +(autoload 'project-find-regexp "project" "\ +Find all matches for REGEXP in the current project's roots. +With \\[universal-argument] prefix, you can specify the directory +to search in, and the file name pattern to search for. The +pattern may use abbreviations defined in `grep-files-aliases', +e.g. entering `ch' is equivalent to `*.[ch]'. As whitespace +triggers completion when entering a pattern, including it +requires quoting, e.g. `\\[quoted-insert]<space>'. + +\(fn REGEXP)" t nil) + +(autoload 'project-or-external-find-regexp "project" "\ +Find all matches for REGEXP in the project roots or external roots. +With \\[universal-argument] prefix, you can specify the file name +pattern to search for. + +\(fn REGEXP)" t nil) + +(autoload 'project-find-file "project" "\ +Visit a file (with completion) in the current project. + +The completion default is the filename at point, determined by +`thing-at-point' (whether such file exists or not)." t nil) + +(autoload 'project-or-external-find-file "project" "\ +Visit a file (with completion) in the current project or external roots. + +The completion default is the filename at point, determined by +`thing-at-point' (whether such file exists or not)." t nil) + +(autoload 'project-dired "project" "\ +Start Dired in the current project's root." t nil) + +(autoload 'project-vc-dir "project" "\ +Run VC-Dir in the current project's root." t nil) + +(autoload 'project-shell "project" "\ +Start an inferior shell in the current project's root directory. +If a buffer already exists for running a shell in the project's root, +switch to it. Otherwise, create a new shell buffer. +With \\[universal-argument] prefix arg, create a new inferior shell buffer even +if one already exists." t nil) + +(autoload 'project-eshell "project" "\ +Start Eshell in the current project's root directory. +If a buffer already exists for running Eshell in the project's root, +switch to it. Otherwise, create a new Eshell buffer. +With \\[universal-argument] prefix arg, create a new Eshell buffer even +if one already exists." t nil) + +(autoload 'project-async-shell-command "project" "\ +Run `async-shell-command' in the current project's root directory." t nil) + +(function-put 'project-async-shell-command 'interactive-only 'async-shell-command) + +(autoload 'project-shell-command "project" "\ +Run `shell-command' in the current project's root directory." t nil) + +(function-put 'project-shell-command 'interactive-only 'shell-command) + +(autoload 'project-search "project" "\ +Search for REGEXP in all the files of the project. +Stops when a match is found. +To continue searching for the next match, use the +command \\[fileloop-continue]. + +\(fn REGEXP)" t nil) + +(autoload 'project-query-replace-regexp "project" "\ +Query-replace REGEXP in all the files of the project. +Stops when a match is found and prompts for whether to replace it. +If you exit the query-replace, you can later continue the query-replace +loop using the command \\[fileloop-continue]. + +\(fn FROM TO)" t nil) + +(autoload 'project-compile "project" "\ +Run `compile' in the project root." t nil) + +(function-put 'project-compile 'interactive-only 'compile) + +(autoload 'project-switch-to-buffer "project" "\ +Display buffer BUFFER-OR-NAME in the selected window. +When called interactively, prompts for a buffer belonging to the +current project. Two buffers belong to the same project if their +project instances, as reported by `project-current' in each +buffer, are identical. + +\(fn BUFFER-OR-NAME)" t nil) + +(autoload 'project-display-buffer "project" "\ +Display BUFFER-OR-NAME in some window, without selecting it. +When called interactively, prompts for a buffer belonging to the +current project. Two buffers belong to the same project if their +project instances, as reported by `project-current' in each +buffer, are identical. + +This function uses `display-buffer' as a subroutine, which see +for how it is determined where the buffer will be displayed. + +\(fn BUFFER-OR-NAME)" t nil) + +(autoload 'project-display-buffer-other-frame "project" "\ +Display BUFFER-OR-NAME preferably in another frame. +When called interactively, prompts for a buffer belonging to the +current project. Two buffers belong to the same project if their +project instances, as reported by `project-current' in each +buffer, are identical. + +This function uses `display-buffer-other-frame' as a subroutine, +which see for how it is determined where the buffer will be +displayed. + +\(fn BUFFER-OR-NAME)" t nil) + +(autoload 'project-kill-buffers "project" "\ +Kill the buffers belonging to the current project. +Two buffers belong to the same project if their project +instances, as reported by `project-current' in each buffer, are +identical. Only the buffers that match a condition in +`project-kill-buffer-conditions' will be killed. If NO-CONFIRM +is non-nil, the command will not ask the user for confirmation. +NO-CONFIRM is always nil when the command is invoked +interactively. + +\(fn &optional NO-CONFIRM)" t nil) + +(autoload 'project-remember-project "project" "\ +Add project PR to the front of the project list. +Save the result in `project-list-file' if the list of projects has changed. + +\(fn PR)" nil nil) + +(autoload 'project-remove-known-project "project" "\ +Remove directory PROJECT-ROOT from the project list. +PROJECT-ROOT is the root directory of a known project listed in +the project list. + +\(fn PROJECT-ROOT)" t nil) + +(autoload 'project-known-project-roots "project" "\ +Return the list of root directories of all known projects." nil nil) + +(autoload 'project-execute-extended-command "project" "\ +Execute an extended command in project root." t nil) + +(function-put 'project-execute-extended-command 'interactive-only 'command-execute) + +(autoload 'project-switch-project "project" "\ +\"Switch\" to another project by running an Emacs command. +The available commands are presented as a dispatch menu +made from `project-switch-commands'. + +When called in a program, it will use the project corresponding +to directory DIR. + +\(fn DIR)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "project" '("project-"))) + +;;;*** + +;;;### (autoloads nil nil ("project-pkg.el") (0 0 0 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; project-autoloads.el ends here diff --git a/emacs.d/elpa/project-0.6.0/project-pkg.el b/emacs.d/elpa/project-0.6.0/project-pkg.el new file mode 100644 index 0000000..47bac26 --- /dev/null +++ b/emacs.d/elpa/project-0.6.0/project-pkg.el @@ -0,0 +1,2 @@ +;; Generated package description from project.el -*- no-byte-compile: t -*- +(define-package "project" "0.6.0" "Operations on the current project" '((emacs "26.1") (xref "1.0.2")) :url "https://elpa.gnu.org/packages/project.html") diff --git a/emacs.d/elpa/project-0.6.0/project.el b/emacs.d/elpa/project-0.6.0/project.el new file mode 100644 index 0000000..d47d9d7 --- /dev/null +++ b/emacs.d/elpa/project-0.6.0/project.el @@ -0,0 +1,1401 @@ +;;; project.el --- Operations on the current project -*- lexical-binding: t; -*- + +;; Copyright (C) 2015-2021 Free Software Foundation, Inc. +;; Version: 0.6.0 +;; Package-Requires: ((emacs "26.1") (xref "1.0.2")) + +;; This is a GNU ELPA :core package. Avoid using functionality that +;; not compatible with the version of Emacs recorded above. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; NOTE: The project API is still experimental and can change in major, +;; backward-incompatible ways. Everyone is encouraged to try it, and +;; report to us any problems or use cases we hadn't anticipated, by +;; sending an email to emacs-devel, or `M-x report-emacs-bug'. +;; +;; This file contains generic infrastructure for dealing with +;; projects, some utility functions, and commands using that +;; infrastructure. +;; +;; The goal is to make it easier for Lisp programs to operate on the +;; current project, without having to know which package handles +;; detection of that project type, parsing its config files, etc. +;; +;; This file consists of following parts: +;; +;; Infrastructure (the public API): +;; +;; Function `project-current' that returns the current project +;; instance based on the value of the hook `project-find-functions', +;; and several generic functions that act on it. +;; +;; `project-root' must be defined for every project. +;; `project-files' can be overridden for performance purposes. +;; `project-ignores' and `project-external-roots' describe the project +;; files and its relations to external directories. `project-files' +;; should be consistent with `project-ignores'. +;; +;; This list can change in future versions. +;; +;; VC project: +;; +;; Originally conceived as an example implementation, now it's a +;; relatively fast backend that delegates to 'git ls-files' or 'hg +;; status' to list the project's files. It honors the VC ignore +;; files, but supports additions to the list using the user option +;; `project-vc-ignores' (usually through .dir-locals.el). +;; +;; Utils: +;; +;; `project-combine-directories' and `project-subtract-directories', +;; mainly for use in the abovementioned generics' implementations. +;; +;; `project-known-project-roots' and `project-remember-project' to +;; interact with the "known projects" list. +;; +;; Commands: +;; +;; `project-prefix-map' contains the full list of commands defined in +;; this package. This map uses the prefix `C-x p' by default. +;; Type `C-x p f' to find file in the current project. +;; Type `C-x p C-h' to see all available commands and bindings. +;; +;; All commands defined in this package are implemented using the +;; public API only. As a result, they will work with any project +;; backend that follows the protocol. +;; +;; Any third-party code that wants to use this package should likewise +;; target the public API. Use any of the built-in commands as the +;; example. +;; +;; How to create a new backend: +;; +;; - Consider whether you really should, or whether there are other +;; ways to reach your goals. If the backend's performance is +;; significantly lower than that of the built-in one, and it's first +;; in the list, it will affect all commands that use it. Unless you +;; are going to be using it only yourself or in special circumstances, +;; you will probably want it to be fast, and it's unlikely to be a +;; trivial endeavor. `project-files' is the method to optimize (the +;; default implementation gets slower the more files the directory +;; has, and the longer the list of ignores is). +;; +;; - Choose the format of the value that represents a project for your +;; backend (we call it project instance). Don't use any of the +;; formats from other backends. The format can be arbitrary, as long +;; as the datatype is something `cl-defmethod' can dispatch on. The +;; value should be stable (when compared with `equal') across +;; invocations, meaning calls to that function from buffers belonging +;; to the same project should return equal values. +;; +;; - Write a new function that will determine the current project +;; based on the directory and add it to `project-find-functions' +;; (which see) using `add-hook'. It is a good idea to depend on the +;; directory only, and not on the current major mode, for example. +;; Because the usual expectation is that all files in the directory +;; belong to the same project (even if some/most of them are ignored). +;; +;; - Define new methods for some or all generic functions for this +;; backend using `cl-defmethod'. A `project-root' method is +;; mandatory, `project-files' is recommended, the rest are optional. + +;;; TODO: + +;; * Reliably cache the list of files in the project, probably using +;; filenotify.el (if supported) to invalidate. And avoiding caching +;; if it's not available (manual cache invalidation is not nice). +;; +;; * Build tool related functionality. Start with a `project-build' +;; command, which should provide completions on tasks to run, and +;; maybe allow entering some additional arguments. This might +;; be handled better with a separate API, though. Then we won't +;; force every project backend to be aware of the build tool(s) the +;; project is using. +;; +;; * Command to (re)build the tag files in all project roots. To that +;; end, we might need to add a way to provide file whitelist +;; wildcards for each root to limit etags to certain files (in +;; addition to the blacklist provided by ignores), and/or allow +;; specifying additional tag regexps. +;; +;; * UI for the user to be able to pick the current project for the +;; whole Emacs session, independent of the current directory. Or, +;; in the more advanced case, open a set of projects, and have some +;; project-related commands to use them all. E.g., have a command +;; to search for a regexp across all open projects. +;; +;; * Support for project-local variables: a UI to edit them, and a +;; utility function to retrieve a value. Probably useless without +;; support in various built-in commands. In the API, we might get +;; away with only adding a `project-configuration-directory' method, +;; defaulting to the project root the current file/buffer is in. +;; And prompting otherwise. How to best mix that with backends that +;; want to set/provide certain variables themselves, is up for +;; discussion. + +;;; Code: + +(require 'cl-generic) +(require 'seq) +(eval-when-compile (require 'subr-x)) + +(defgroup project nil + "Operations on the current project." + :version "28.1" + :group 'tools) + +(defvar project-find-functions (list #'project-try-vc) + "Special hook to find the project containing a given directory. +Each functions on this hook is called in turn with one +argument, the directory in which to look, and should return +either nil to mean that it is not applicable, or a project instance. +The exact form of the project instance is up to each respective +function; the only practical limitation is to use values that +`cl-defmethod' can dispatch on, like a cons cell, or a list, or a +CL struct.") + +(defvar project-current-inhibit-prompt nil + "Non-nil to skip prompting the user in `project-current'.") + +;;;###autoload +(defun project-current (&optional maybe-prompt directory) + "Return the project instance in DIRECTORY, defaulting to `default-directory'. + +When no project is found in that directory, the result depends on +the value of MAYBE-PROMPT: if it is nil or omitted, return nil, +else ask the user for a directory in which to look for the +project, and if no project is found there, return a \"transient\" +project instance. + +The \"transient\" project instance is a special kind of value +which denotes a project rooted in that directory and includes all +the files under the directory except for those that should be +ignored (per `project-ignores'). + +See the doc string of `project-find-functions' for the general form +of the project instance object." + (unless directory (setq directory default-directory)) + (let ((pr (project--find-in-directory directory))) + (cond + (pr) + ((unless project-current-inhibit-prompt + maybe-prompt) + (setq directory (project-prompt-project-dir) + pr (project--find-in-directory directory)))) + (when maybe-prompt + (if pr + (project-remember-project pr) + (project--remove-from-project-list + directory "Project `%s' not found; removed from list") + (setq pr (cons 'transient directory)))) + pr)) + +(defun project--find-in-directory (dir) + (run-hook-with-args-until-success 'project-find-functions dir)) + +(defvar project--within-roots-fallback nil) + +(cl-defgeneric project-root (project) + "Return root directory of the current project. + +It usually contains the main build file, dependencies +configuration file, etc. Though neither is mandatory. + +The directory name must be absolute.") + +(cl-defmethod project-root (project + &context (project--within-roots-fallback + (eql nil))) + (car (project-roots project))) + +(cl-defgeneric project-roots (project) + "Return the list containing the current project root. + +The function is obsolete, all projects have one main root anyway, +and the rest should be possible to express through +`project-external-roots'." + ;; FIXME: Can we specify project's version here? + ;; FIXME: Could we make this affect cl-defmethod calls too? + (declare (obsolete project-root "0.3.0")) + (let ((project--within-roots-fallback t)) + (list (project-root project)))) + +;; FIXME: Add MODE argument, like in `ede-source-paths'? +(cl-defgeneric project-external-roots (_project) + "Return the list of external roots for PROJECT. + +It's the list of directories outside of the project that are +still related to it. If the project deals with source code then, +depending on the languages used, this list should include the +headers search path, load path, class path, and so on." + nil) + +(cl-defgeneric project-ignores (_project _dir) + "Return the list of glob patterns to ignore inside DIR. +Patterns can match both regular files and directories. +To root an entry, start it with `./'. To match directories only, +end it with `/'. DIR must be either `project-root' or one of +`project-external-roots'." + ;; TODO: Document and support regexp ignores as used by Hg. + ;; TODO: Support whitelist entries. + (require 'grep) + (defvar grep-find-ignored-files) + (nconc + (mapcar + (lambda (dir) + (concat dir "/")) + vc-directory-exclusion-list) + grep-find-ignored-files)) + +(defun project--file-completion-table (all-files) + (lambda (string pred action) + (cond + ((eq action 'metadata) + '(metadata . ((category . project-file)))) + (t + (complete-with-action action all-files string pred))))) + +(cl-defmethod project-root ((project (head transient))) + (cdr project)) + +(cl-defgeneric project-files (project &optional dirs) + "Return a list of files in directories DIRS in PROJECT. +DIRS is a list of absolute directories; it should be some +subset of the project root and external roots. + +The default implementation uses `find-program'. PROJECT is used +to find the list of ignores for each directory." + (mapcan + (lambda (dir) + (project--files-in-directory dir + (project--dir-ignores project dir))) + (or dirs + (list (project-root project))))) + +(defun project--files-in-directory (dir ignores &optional files) + (require 'find-dired) + (require 'xref) + (defvar find-name-arg) + (let* ((default-directory dir) + ;; Make sure ~/ etc. in local directory name is + ;; expanded and not left for the shell command + ;; to interpret. + (localdir (file-name-unquote (file-local-name (expand-file-name dir)))) + (command (format "%s %s %s -type f %s -print0" + find-program + ;; In case DIR is a symlink. + (file-name-as-directory localdir) + (xref--find-ignores-arguments ignores localdir) + (if files + (concat (shell-quote-argument "(") + " " find-name-arg " " + (mapconcat + #'shell-quote-argument + (split-string files) + (concat " -o " find-name-arg " ")) + " " + (shell-quote-argument ")")) + ""))) + (output (with-output-to-string + (with-current-buffer standard-output + (let ((status + (process-file-shell-command command nil t))) + (unless (zerop status) + (error "File listing failed: %s" (buffer-string)))))))) + (project--remote-file-names + (sort (split-string output "\0" t) + #'string<)))) + +(defun project--remote-file-names (local-files) + "Return LOCAL-FILES as if they were on the system of `default-directory'. +Also quote LOCAL-FILES if `default-directory' is quoted." + (let ((remote-id (file-remote-p default-directory))) + (if (not remote-id) + (if (file-name-quoted-p default-directory) + (mapcar #'file-name-quote local-files) + local-files) + (mapcar (lambda (file) + (concat remote-id file)) + local-files)))) + +(defgroup project-vc nil + "Project implementation based on the VC package." + :version "25.1" + :group 'project) + +(defcustom project-vc-ignores nil + "List of patterns to add to `project-ignores'." + :type '(repeat string) + :safe #'listp) + +(defcustom project-vc-merge-submodules t + "Non-nil to consider submodules part of the parent project. + +After changing this variable (using Customize or .dir-locals.el) +you might have to restart Emacs to see the effect." + :type 'boolean + :version "28.1" + :package-version '(project . "0.2.0") + :safe #'booleanp) + +;; FIXME: Using the current approach, major modes are supposed to set +;; this variable to a buffer-local value. So we don't have access to +;; the "external roots" of language A from buffers of language B, which +;; seems desirable in multi-language projects, at least for some +;; potential uses, like "jump to a file in project or external dirs". +;; +;; We could add a second argument to this function: a file extension, +;; or a language name. Some projects will know the set of languages +;; used in them; for others, like VC-based projects, we'll need +;; auto-detection. I see two options: +;; +;; - That could be implemented as a separate second hook, with a +;; list of functions that return file extensions. +;; +;; - This variable will be turned into a hook with "append" semantics, +;; and each function in it will perform auto-detection when passed +;; nil instead of an actual file extension. Then this hook will, in +;; general, be modified globally, and not from major mode functions. +;; +;; The second option seems simpler, but the first one has the +;; advantage that the user could override the list of languages used +;; in a project via a directory-local variable, thus skipping +;; languages they're not working on personally (in a big project), or +;; working around problems in language detection (the detection logic +;; might be imperfect for the project in question, or it might work +;; too slowly for the user's taste). +(defvar project-vc-external-roots-function (lambda () tags-table-list) + "Function that returns a list of external roots. + +It should return a list of directory roots that contain source +files related to the current buffer. + +The directory names should be absolute. Used in the VC project +backend implementation of `project-external-roots'.") + +(defun project-try-vc (dir) + (let* ((backend + ;; FIXME: This is slow. Cache it. + (ignore-errors (vc-responsible-backend dir))) + (root + (pcase backend + ('Git + ;; Don't stop at submodule boundary. + ;; FIXME: Cache for a shorter time. + (or (vc-file-getprop dir 'project-git-root) + (let ((root (vc-call-backend backend 'root dir))) + (vc-file-setprop + dir 'project-git-root + (if (and + ;; FIXME: Invalidate the cache when the value + ;; of this variable changes. + (project--vc-merge-submodules-p root) + (project--submodule-p root)) + (let* ((parent (file-name-directory + (directory-file-name root)))) + (vc-call-backend backend 'root parent)) + root))))) + ('nil nil) + (_ (ignore-errors (vc-call-backend backend 'root dir)))))) + (and root (cons 'vc root)))) + +(defun project--submodule-p (root) + ;; XXX: We only support Git submodules for now. + ;; + ;; For submodules, at least, we expect the users to prefer them to + ;; be considered part of the parent project. For those who don't, + ;; there is the custom var now. + ;; + ;; Some users may also set up things equivalent to Git submodules + ;; using "git worktree" (for example). However, we expect that most + ;; of them would prefer to treat those as separate projects anyway. + (let* ((gitfile (expand-file-name ".git" root))) + (cond + ((file-directory-p gitfile) + nil) + ((with-temp-buffer + (insert-file-contents gitfile) + (goto-char (point-min)) + ;; Kind of a hack to distinguish a submodule from + ;; other cases of .git files pointing elsewhere. + (looking-at "gitdir: [./]+/\\.git/modules/")) + t) + (t nil)))) + +(cl-defmethod project-root ((project (head vc))) + (cdr project)) + +(cl-defmethod project-external-roots ((project (head vc))) + (project-subtract-directories + (project-combine-directories + (mapcar + #'file-name-as-directory + (funcall project-vc-external-roots-function))) + (list (project-root project)))) + +(cl-defmethod project-files ((project (head vc)) &optional dirs) + (mapcan + (lambda (dir) + (let ((ignores (project--value-in-dir 'project-vc-ignores dir)) + backend) + (if (and (file-equal-p dir (cdr project)) + (setq backend (vc-responsible-backend dir)) + (cond + ((eq backend 'Hg)) + ((and (eq backend 'Git) + (or + (not ignores) + (version<= "1.9" (vc-git--program-version))))))) + (project--vc-list-files dir backend ignores) + (project--files-in-directory + dir + (project--dir-ignores project dir))))) + (or dirs + (list (project-root project))))) + +(declare-function vc-git--program-version "vc-git") +(declare-function vc-git--run-command-string "vc-git") +(declare-function vc-hg-command "vc-hg") + +(defun project--vc-list-files (dir backend extra-ignores) + (pcase backend + (`Git + (let ((default-directory (expand-file-name (file-name-as-directory dir))) + (args '("-z")) + files) + ;; Include unregistered. + (setq args (append args '("-c" "-o" "--exclude-standard"))) + (when extra-ignores + (setq args (append args + (cons "--" + (mapcar + (lambda (i) + (format + ":(exclude,glob,top)%s" + (if (string-match "\\*\\*" i) + ;; Looks like pathspec glob + ;; format already. + i + (if (string-match "\\./" i) + ;; ./abc -> abc + (setq i (substring i 2)) + ;; abc -> **/abc + (setq i (concat "**/" i)) + ;; FIXME: '**/abc' should also + ;; match a directory with that + ;; name, but doesn't (git 2.25.1). + ;; Maybe we should replace + ;; such entries with two. + (if (string-match "/\\'" i) + ;; abc/ -> abc/** + (setq i (concat i "**")))) + i))) + extra-ignores))))) + (setq files + (mapcar + (lambda (file) (concat default-directory file)) + (split-string + (apply #'vc-git--run-command-string nil "ls-files" args) + "\0" t))) + (when (project--vc-merge-submodules-p default-directory) + ;; Unfortunately, 'ls-files --recurse-submodules' conflicts with '-o'. + (let* ((submodules (project--git-submodules)) + (sub-files + (mapcar + (lambda (module) + (when (file-directory-p module) + (project--vc-list-files + (concat default-directory module) + backend + extra-ignores))) + submodules))) + (setq files + (apply #'nconc files sub-files)))) + ;; 'git ls-files' returns duplicate entries for merge conflicts. + ;; XXX: Better solutions welcome, but this seems cheap enough. + (delete-consecutive-dups files))) + (`Hg + (let ((default-directory (expand-file-name (file-name-as-directory dir))) + args) + ;; Include unregistered. + (setq args (nconc args '("-mcardu" "--no-status" "-0"))) + (when extra-ignores + (setq args (nconc args + (mapcan + (lambda (i) + (list "--exclude" i)) + extra-ignores)))) + (with-temp-buffer + (apply #'vc-hg-command t 0 "." "status" args) + (mapcar + (lambda (s) (concat default-directory s)) + (split-string (buffer-string) "\0" t))))))) + +(defun project--vc-merge-submodules-p (dir) + (project--value-in-dir + 'project-vc-merge-submodules + dir)) + +(defun project--git-submodules () + ;; 'git submodule foreach' is much slower. + (condition-case nil + (with-temp-buffer + (insert-file-contents ".gitmodules") + (let (res) + (goto-char (point-min)) + (while (re-search-forward "path *= *\\(.+\\)" nil t) + (push (match-string 1) res)) + (nreverse res))) + (file-missing nil))) + +(cl-defmethod project-ignores ((project (head vc)) dir) + (let* ((root (cdr project)) + backend) + (append + (when (file-equal-p dir root) + (setq backend (vc-responsible-backend root)) + (delq + nil + (mapcar + (lambda (entry) + (cond + ((eq ?! (aref entry 0)) + ;; No support for whitelisting (yet). + nil) + ((string-match "\\(/\\)[^/]" entry) + ;; FIXME: This seems to be Git-specific. + ;; And / in the entry (start or even the middle) means + ;; the pattern is "rooted". Or actually it is then + ;; relative to its respective .gitignore (of which there + ;; could be several), but we only support .gitignore at + ;; the root. + (if (= (match-beginning 0) 0) + (replace-match "./" t t entry 1) + (concat "./" entry))) + (t entry))) + (vc-call-backend backend 'ignore-completion-table root)))) + (project--value-in-dir 'project-vc-ignores root) + (mapcar + (lambda (dir) + (concat dir "/")) + vc-directory-exclusion-list)))) + +(defun project-combine-directories (&rest lists-of-dirs) + "Return a sorted and culled list of directory names. +Appends the elements of LISTS-OF-DIRS together, removes +non-existing directories, as well as directories a parent of +whose is already in the list." + (let* ((dirs (sort + (mapcar + (lambda (dir) + (file-name-as-directory (expand-file-name dir))) + (apply #'append lists-of-dirs)) + #'string<)) + (ref dirs)) + ;; Delete subdirectories from the list. + (while (cdr ref) + (if (string-prefix-p (car ref) (cadr ref)) + (setcdr ref (cddr ref)) + (setq ref (cdr ref)))) + (cl-delete-if-not #'file-exists-p dirs))) + +(defun project-subtract-directories (files dirs) + "Return a list of elements from FILES that are outside of DIRS. +DIRS must contain directory names." + ;; Sidestep the issue of expanded/abbreviated file names here. + (cl-set-difference files dirs :test #'file-in-directory-p)) + +(defun project--value-in-dir (var dir) + (with-temp-buffer + (setq default-directory dir) + (let ((enable-local-variables :all)) + (hack-dir-local-variables-non-file-buffer)) + (symbol-value var))) + + +;;; Project commands + +;;;###autoload +(defvar project-prefix-map + (let ((map (make-sparse-keymap))) + (define-key map "!" 'project-shell-command) + (define-key map "&" 'project-async-shell-command) + (define-key map "f" 'project-find-file) + (define-key map "F" 'project-or-external-find-file) + (define-key map "b" 'project-switch-to-buffer) + (define-key map "s" 'project-shell) + (define-key map "d" 'project-dired) + (define-key map "v" 'project-vc-dir) + (define-key map "c" 'project-compile) + (define-key map "e" 'project-eshell) + (define-key map "k" 'project-kill-buffers) + (define-key map "p" 'project-switch-project) + (define-key map "g" 'project-find-regexp) + (define-key map "G" 'project-or-external-find-regexp) + (define-key map "r" 'project-query-replace-regexp) + (define-key map "x" 'project-execute-extended-command) + map) + "Keymap for project commands.") + +;;;###autoload (define-key ctl-x-map "p" project-prefix-map) + +;; We can't have these place-specific maps inherit from +;; project-prefix-map because project--other-place-command needs to +;; know which map the key binding came from, as if it came from one of +;; these maps, we don't want to set display-buffer-overriding-action + +(defvar project-other-window-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-o" #'project-display-buffer) + map) + "Keymap for project commands that display buffers in other windows.") + +(defvar project-other-frame-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-o" #'project-display-buffer-other-frame) + map) + "Keymap for project commands that display buffers in other frames.") + +(defun project--other-place-command (action &optional map) + (let* ((key (read-key-sequence-vector nil t)) + (place-cmd (lookup-key map key)) + (generic-cmd (lookup-key project-prefix-map key)) + (switch-to-buffer-obey-display-actions t) + (display-buffer-overriding-action (unless place-cmd action))) + (if-let ((cmd (or place-cmd generic-cmd))) + (call-interactively cmd) + (user-error "%s is undefined" (key-description key))))) + +;;;###autoload +(defun project-other-window-command () + "Run project command, displaying resultant buffer in another window. + +The following commands are available: + +\\{project-prefix-map} +\\{project-other-window-map}" + (interactive) + (project--other-place-command '((display-buffer-pop-up-window) + (inhibit-same-window . t)) + project-other-window-map)) + +;;;###autoload (define-key ctl-x-4-map "p" #'project-other-window-command) + +;;;###autoload +(defun project-other-frame-command () + "Run project command, displaying resultant buffer in another frame. + +The following commands are available: + +\\{project-prefix-map} +\\{project-other-frame-map}" + (interactive) + (project--other-place-command '((display-buffer-pop-up-frame)) + project-other-frame-map)) + +;;;###autoload (define-key ctl-x-5-map "p" #'project-other-frame-command) + +;;;###autoload +(defun project-other-tab-command () + "Run project command, displaying resultant buffer in a new tab. + +The following commands are available: + +\\{project-prefix-map}" + (interactive) + (project--other-place-command '((display-buffer-in-new-tab)))) + +;;;###autoload +(when (bound-and-true-p tab-prefix-map) + (define-key tab-prefix-map "p" #'project-other-tab-command)) + +(declare-function grep-read-files "grep") +(declare-function xref--show-xrefs "xref") +(declare-function xref--find-ignores-arguments "xref") + +;;;###autoload +(defun project-find-regexp (regexp) + "Find all matches for REGEXP in the current project's roots. +With \\[universal-argument] prefix, you can specify the directory +to search in, and the file name pattern to search for. The +pattern may use abbreviations defined in `grep-files-aliases', +e.g. entering `ch' is equivalent to `*.[ch]'. As whitespace +triggers completion when entering a pattern, including it +requires quoting, e.g. `\\[quoted-insert]<space>'." + (interactive (list (project--read-regexp))) + (require 'xref) + (require 'grep) + (let* ((caller-dir default-directory) + (pr (project-current t)) + (default-directory (project-root pr)) + (files + (if (not current-prefix-arg) + (project-files pr) + (let ((dir (read-directory-name "Base directory: " + caller-dir nil t))) + (project--files-in-directory dir + nil + (grep-read-files regexp)))))) + (xref--show-xrefs + (apply-partially #'project--find-regexp-in-files regexp files) + nil))) + +(defun project--dir-ignores (project dir) + (let ((root (project-root project))) + (if (not (file-in-directory-p dir root)) + (project-ignores nil nil) ;The defaults. + (let ((ignores (project-ignores project root))) + (if (file-equal-p root dir) + ignores + ;; FIXME: Update the "rooted" ignores to relate to DIR instead. + (cl-delete-if (lambda (str) (string-prefix-p "./" str)) + ignores)))))) + +;;;###autoload +(defun project-or-external-find-regexp (regexp) + "Find all matches for REGEXP in the project roots or external roots. +With \\[universal-argument] prefix, you can specify the file name +pattern to search for." + (interactive (list (project--read-regexp))) + (require 'xref) + (let* ((pr (project-current t)) + (default-directory (project-root pr)) + (files + (project-files pr (cons + (project-root pr) + (project-external-roots pr))))) + (xref--show-xrefs + (apply-partially #'project--find-regexp-in-files regexp files) + nil))) + +(defun project--find-regexp-in-files (regexp files) + (unless files + (user-error "Empty file list")) + (let ((xrefs (xref-matches-in-files regexp files))) + (unless xrefs + (user-error "No matches for: %s" regexp)) + xrefs)) + +(defvar project-regexp-history-variable 'grep-regexp-history) + +(defun project--read-regexp () + (let ((sym (thing-at-point 'symbol t))) + (read-regexp "Find regexp" (and sym (regexp-quote sym)) + project-regexp-history-variable))) + +;;;###autoload +(defun project-find-file () + "Visit a file (with completion) in the current project. + +The completion default is the filename at point, determined by +`thing-at-point' (whether such file exists or not)." + (interactive) + (let* ((pr (project-current t)) + (dirs (list (project-root pr)))) + (project-find-file-in (thing-at-point 'filename) dirs pr))) + +;;;###autoload +(defun project-or-external-find-file () + "Visit a file (with completion) in the current project or external roots. + +The completion default is the filename at point, determined by +`thing-at-point' (whether such file exists or not)." + (interactive) + (let* ((pr (project-current t)) + (dirs (cons + (project-root pr) + (project-external-roots pr)))) + (project-find-file-in (thing-at-point 'filename) dirs pr))) + +(defcustom project-read-file-name-function #'project--read-file-cpd-relative + "Function to call to read a file name from a list. +For the arguments list, see `project--read-file-cpd-relative'." + :type '(choice (const :tag "Read with completion from relative names" + project--read-file-cpd-relative) + (const :tag "Read with completion from absolute names" + project--read-file-absolute) + (function :tag "Custom function" nil)) + :group 'project + :version "27.1") + +(defun project--read-file-cpd-relative (prompt + all-files &optional predicate + hist default) + "Read a file name, prompting with PROMPT. +ALL-FILES is a list of possible file name completions. +PREDICATE, HIST, and DEFAULT have the same meaning as in +`completing-read'." + (let* ((common-parent-directory + (let ((common-prefix (try-completion "" all-files))) + (if (> (length common-prefix) 0) + (file-name-directory common-prefix)))) + (cpd-length (length common-parent-directory)) + (prompt (if (zerop cpd-length) + prompt + (concat prompt (format " in %s" common-parent-directory)))) + (substrings (mapcar (lambda (s) (substring s cpd-length)) all-files)) + (new-collection (project--file-completion-table substrings)) + (res (project--completing-read-strict prompt + new-collection + predicate + hist default))) + (concat common-parent-directory res))) + +(defun project--read-file-absolute (prompt + all-files &optional predicate + hist default) + (project--completing-read-strict prompt + (project--file-completion-table all-files) + predicate + hist default)) + +(defun project-find-file-in (filename dirs project) + "Complete FILENAME in DIRS in PROJECT and visit the result." + (let* ((all-files (project-files project dirs)) + (completion-ignore-case read-file-name-completion-ignore-case) + (file (funcall project-read-file-name-function + "Find file" all-files nil nil + filename))) + (if (string= file "") + (user-error "You didn't specify the file") + (find-file file)))) + +(defun project--completing-read-strict (prompt + collection &optional predicate + hist default) + ;; Tried both expanding the default before showing the prompt, and + ;; removing it when it has no matches. Neither seems natural + ;; enough. Removal is confusing; early expansion makes the prompt + ;; too long. + (let* ((new-prompt (if (and default (not (string-equal default ""))) + (format "%s (default %s): " prompt default) + (format "%s: " prompt))) + (res (completing-read new-prompt + collection predicate t + nil ;; initial-input + hist default))) + (when (and (equal res default) + (not (test-completion res collection predicate))) + (setq res + (completing-read (format "%s: " prompt) + collection predicate t res hist nil))) + res)) + +;;;###autoload +(defun project-dired () + "Start Dired in the current project's root." + (interactive) + (dired (project-root (project-current t)))) + +;;;###autoload +(defun project-vc-dir () + "Run VC-Dir in the current project's root." + (interactive) + (vc-dir (project-root (project-current t)))) + +;;;###autoload +(defun project-shell () + "Start an inferior shell in the current project's root directory. +If a buffer already exists for running a shell in the project's root, +switch to it. Otherwise, create a new shell buffer. +With \\[universal-argument] prefix arg, create a new inferior shell buffer even +if one already exists." + (interactive) + (let* ((default-directory (project-root (project-current t))) + (default-project-shell-name (project-prefixed-buffer-name "shell")) + (shell-buffer (get-buffer default-project-shell-name))) + (if (and shell-buffer (not current-prefix-arg)) + (pop-to-buffer-same-window shell-buffer) + (shell (generate-new-buffer-name default-project-shell-name))))) + +;;;###autoload +(defun project-eshell () + "Start Eshell in the current project's root directory. +If a buffer already exists for running Eshell in the project's root, +switch to it. Otherwise, create a new Eshell buffer. +With \\[universal-argument] prefix arg, create a new Eshell buffer even +if one already exists." + (interactive) + (defvar eshell-buffer-name) + (let* ((default-directory (project-root (project-current t))) + (eshell-buffer-name (project-prefixed-buffer-name "eshell")) + (eshell-buffer (get-buffer eshell-buffer-name))) + (if (and eshell-buffer (not current-prefix-arg)) + (pop-to-buffer-same-window eshell-buffer) + (eshell t)))) + +;;;###autoload +(defun project-async-shell-command () + "Run `async-shell-command' in the current project's root directory." + (declare (interactive-only async-shell-command)) + (interactive) + (let ((default-directory (project-root (project-current t)))) + (call-interactively #'async-shell-command))) + +;;;###autoload +(defun project-shell-command () + "Run `shell-command' in the current project's root directory." + (declare (interactive-only shell-command)) + (interactive) + (let ((default-directory (project-root (project-current t)))) + (call-interactively #'shell-command))) + +(declare-function fileloop-continue "fileloop" ()) + +;;;###autoload +(defun project-search (regexp) + "Search for REGEXP in all the files of the project. +Stops when a match is found. +To continue searching for the next match, use the +command \\[fileloop-continue]." + (interactive "sSearch (regexp): ") + (fileloop-initialize-search + regexp (project-files (project-current t)) 'default) + (fileloop-continue)) + +;;;###autoload +(defun project-query-replace-regexp (from to) + "Query-replace REGEXP in all the files of the project. +Stops when a match is found and prompts for whether to replace it. +If you exit the query-replace, you can later continue the query-replace +loop using the command \\[fileloop-continue]." + (interactive + (pcase-let ((`(,from ,to) + (query-replace-read-args "Query replace (regexp)" t t))) + (list from to))) + (fileloop-initialize-replace + from to (project-files (project-current t)) 'default) + (fileloop-continue)) + +(defvar compilation-read-command) +(declare-function compilation-read-command "compile") + +(defun project-prefixed-buffer-name (mode) + (concat "*" + (file-name-nondirectory + (directory-file-name default-directory)) + "-" + (downcase mode) + "*")) + +(defcustom project-compilation-buffer-name-function nil + "Function to compute the name of a project compilation buffer. +If non-nil, it overrides `compilation-buffer-name-function' for +`project-compile'." + :version "28.1" + :group 'project + :type '(choice (const :tag "Default" nil) + (const :tag "Prefixed with root directory name" + project-prefixed-buffer-name) + (function :tag "Custom function"))) + +;;;###autoload +(defun project-compile () + "Run `compile' in the project root." + (declare (interactive-only compile)) + (interactive) + (let ((default-directory (project-root (project-current t))) + (compilation-buffer-name-function + (or project-compilation-buffer-name-function + compilation-buffer-name-function))) + (call-interactively #'compile))) + +(defun project--read-project-buffer () + (let* ((pr (project-current t)) + (current-buffer (current-buffer)) + (other-buffer (other-buffer current-buffer)) + (other-name (buffer-name other-buffer)) + (predicate + (lambda (buffer) + ;; BUFFER is an entry (BUF-NAME . BUF-OBJ) of Vbuffer_alist. + (and (cdr buffer) + (equal pr + (with-current-buffer (cdr buffer) + (project-current))))))) + (read-buffer + "Switch to buffer: " + (when (funcall predicate (cons other-name other-buffer)) + other-name) + nil + predicate))) + +;;;###autoload +(defun project-switch-to-buffer (buffer-or-name) + "Display buffer BUFFER-OR-NAME in the selected window. +When called interactively, prompts for a buffer belonging to the +current project. Two buffers belong to the same project if their +project instances, as reported by `project-current' in each +buffer, are identical." + (interactive (list (project--read-project-buffer))) + (switch-to-buffer buffer-or-name)) + +;;;###autoload +(defun project-display-buffer (buffer-or-name) + "Display BUFFER-OR-NAME in some window, without selecting it. +When called interactively, prompts for a buffer belonging to the +current project. Two buffers belong to the same project if their +project instances, as reported by `project-current' in each +buffer, are identical. + +This function uses `display-buffer' as a subroutine, which see +for how it is determined where the buffer will be displayed." + (interactive (list (project--read-project-buffer))) + (display-buffer buffer-or-name)) + +;;;###autoload +(defun project-display-buffer-other-frame (buffer-or-name) + "Display BUFFER-OR-NAME preferably in another frame. +When called interactively, prompts for a buffer belonging to the +current project. Two buffers belong to the same project if their +project instances, as reported by `project-current' in each +buffer, are identical. + +This function uses `display-buffer-other-frame' as a subroutine, +which see for how it is determined where the buffer will be +displayed." + (interactive (list (project--read-project-buffer))) + (display-buffer-other-frame buffer-or-name)) + +(defcustom project-kill-buffer-conditions + '(buffer-file-name ; All file-visiting buffers are included. + ;; Most of the temp buffers in the background: + (major-mode . fundamental-mode) + ;; non-text buffer such as xref, occur, vc, log, ... + (and (derived-mode . special-mode) + (not (major-mode . help-mode))) + (derived-mode . compilation-mode) + (derived-mode . dired-mode) + (derived-mode . diff-mode)) + "List of conditions to kill buffers related to a project. +This list is used by `project-kill-buffers'. +Each condition is either: +- a regular expression, to match a buffer name, +- a predicate function that takes a buffer object as argument + and returns non-nil if the buffer should be killed, +- a cons-cell, where the car describes how to interpret the cdr. + The car can be one of the following: + * `major-mode': the buffer is killed if the buffer's major + mode is eq to the cons-cell's cdr + * `derived-mode': the buffer is killed if the buffer's major + mode is derived from the major mode denoted by the cons-cell's + cdr + * `not': the cdr is interpreted as a negation of a condition. + * `and': the cdr is a list of recursive conditions, that all have + to be met. + * `or': the cdr is a list of recursive conditions, of which at + least one has to be met. + +If any of these conditions are satisfied for a buffer in the +current project, it will be killed." + :type '(repeat (choice regexp function symbol + (cons :tag "Major mode" + (const major-mode) symbol) + (cons :tag "Derived mode" + (const derived-mode) symbol) + (cons :tag "Negation" + (const not) sexp) + (cons :tag "Conjunction" + (const and) sexp) + (cons :tag "Disjunction" + (const or) sexp))) + :version "28.1" + :group 'project + :package-version '(project . "0.6.0")) + +(defun project--buffer-list (pr) + "Return the list of all buffers in project PR." + (let (bufs) + (dolist (buf (buffer-list)) + (when (equal pr + (with-current-buffer buf + (project-current))) + (push buf bufs))) + (nreverse bufs))) + +(defun project--kill-buffer-check (buf conditions) + "Check if buffer BUF matches any element of the list CONDITIONS. +See `project-kill-buffer-conditions' for more details on the form +of CONDITIONS." + (catch 'kill + (dolist (c conditions) + (when (cond + ((stringp c) + (string-match-p c (buffer-name buf))) + ((symbolp c) + (funcall c buf)) + ((eq (car-safe c) 'major-mode) + (eq (buffer-local-value 'major-mode buf) + (cdr c))) + ((eq (car-safe c) 'derived-mode) + (provided-mode-derived-p + (buffer-local-value 'major-mode buf) + (cdr c))) + ((eq (car-safe c) 'not) + (not (project--kill-buffer-check buf (cdr c)))) + ((eq (car-safe c) 'or) + (project--kill-buffer-check buf (cdr c))) + ((eq (car-safe c) 'and) + (seq-every-p + (apply-partially #'project--kill-buffer-check + buf) + (mapcar #'list (cdr c))))) + (throw 'kill t))))) + +(defun project--buffers-to-kill (pr) + "Return list of buffers in project PR to kill. +What buffers should or should not be killed is described +in `project-kill-buffer-conditions'." + (let (bufs) + (dolist (buf (project--buffer-list pr)) + (when (project--kill-buffer-check buf project-kill-buffer-conditions) + (push buf bufs))) + bufs)) + +;;;###autoload +(defun project-kill-buffers (&optional no-confirm) + "Kill the buffers belonging to the current project. +Two buffers belong to the same project if their project +instances, as reported by `project-current' in each buffer, are +identical. Only the buffers that match a condition in +`project-kill-buffer-conditions' will be killed. If NO-CONFIRM +is non-nil, the command will not ask the user for confirmation. +NO-CONFIRM is always nil when the command is invoked +interactively." + (interactive) + (let* ((pr (project-current t)) + (bufs (project--buffers-to-kill pr))) + (cond (no-confirm + (mapc #'kill-buffer bufs)) + ((null bufs) + (message "No buffers to kill")) + ((yes-or-no-p (format "Kill %d buffers in %s? " + (length bufs) + (project-root pr))) + (mapc #'kill-buffer bufs))))) + + +;;; Project list + +(defcustom project-list-file (locate-user-emacs-file "projects") + "File in which to save the list of known projects." + :type 'file + :version "28.1" + :group 'project) + +(defvar project--list 'unset + "List structure containing root directories of known projects. +With some possible metadata (to be decided).") + +(defun project--read-project-list () + "Initialize `project--list' using contents of `project-list-file'." + (let ((filename project-list-file)) + (setq project--list + (when (file-exists-p filename) + (with-temp-buffer + (insert-file-contents filename) + (read (current-buffer))))) + (unless (seq-every-p + (lambda (elt) (stringp (car-safe elt))) + project--list) + (warn "Contents of %s are in wrong format, resetting" + project-list-file) + (setq project--list nil)))) + +(defun project--ensure-read-project-list () + "Initialize `project--list' if it isn't already initialized." + (when (eq project--list 'unset) + (project--read-project-list))) + +(defun project--write-project-list () + "Save `project--list' in `project-list-file'." + (let ((filename project-list-file)) + (with-temp-buffer + (insert ";;; -*- lisp-data -*-\n") + (let ((print-length nil) + (print-level nil)) + (pp project--list (current-buffer))) + (write-region nil nil filename nil 'silent)))) + +;;;###autoload +(defun project-remember-project (pr) + "Add project PR to the front of the project list. +Save the result in `project-list-file' if the list of projects has changed." + (project--ensure-read-project-list) + (let ((dir (project-root pr))) + (unless (equal (caar project--list) dir) + (dolist (ent project--list) + (when (equal dir (car ent)) + (setq project--list (delq ent project--list)))) + (push (list dir) project--list) + (project--write-project-list)))) + +(defun project--remove-from-project-list (project-root report-message) + "Remove directory PROJECT-ROOT of a missing project from the project list. +If the directory was in the list before the removal, save the +result in `project-list-file'. Announce the project's removal +from the list using REPORT-MESSAGE, which is a format string +passed to `message' as its first argument." + (project--ensure-read-project-list) + (when-let ((ent (assoc project-root project--list))) + (setq project--list (delq ent project--list)) + (message report-message project-root) + (project--write-project-list))) + +;;;###autoload +(defun project-remove-known-project (project-root) + "Remove directory PROJECT-ROOT from the project list. +PROJECT-ROOT is the root directory of a known project listed in +the project list." + (interactive (list (project-prompt-project-dir))) + (project--remove-from-project-list + project-root "Project `%s' removed from known projects")) + +(defun project-prompt-project-dir () + "Prompt the user for a directory that is one of the known project roots. +The project is chosen among projects known from the project list, +see `project-list-file'. +It's also possible to enter an arbitrary directory not in the list." + (project--ensure-read-project-list) + (let* ((dir-choice "... (choose a dir)") + (choices + ;; XXX: Just using this for the category (for the substring + ;; completion style). + (project--file-completion-table + (append project--list `(,dir-choice)))) + (pr-dir (completing-read "Select project: " choices nil t))) + (if (equal pr-dir dir-choice) + (read-directory-name "Select directory: " default-directory nil t) + pr-dir))) + +;;;###autoload +(defun project-known-project-roots () + "Return the list of root directories of all known projects." + (project--ensure-read-project-list) + (mapcar #'car project--list)) + +;;;###autoload +(defun project-execute-extended-command () + "Execute an extended command in project root." + (declare (interactive-only command-execute)) + (interactive) + (let ((default-directory (project-root (project-current t)))) + (call-interactively #'execute-extended-command))) + + +;;; Project switching + +(defcustom project-switch-commands + '((project-find-file "Find file") + (project-find-regexp "Find regexp") + (project-dired "Dired") + (project-vc-dir "VC-Dir") + (project-eshell "Eshell")) + "Alist mapping commands to descriptions. +Used by `project-switch-project' to construct a dispatch menu of +commands available upon \"switching\" to another project. + +Each element is of the form (COMMAND LABEL &optional KEY) where +COMMAND is the command to run when KEY is pressed. LABEL is used +to distinguish the menu entries in the dispatch menu. If KEY is +absent, COMMAND must be bound in `project-prefix-map', and the +key is looked up in that map." + :version "28.1" + :group 'project + :package-version '(project . "0.6.0") + :type '(repeat + (list + (symbol :tag "Command") + (string :tag "Label") + (choice :tag "Key to press" + (const :tag "Infer from the keymap" nil) + (character :tag "Explicit key"))))) + +(defcustom project-switch-use-entire-map nil + "Make `project-switch-project' use entire `project-prefix-map'. +If nil, `project-switch-project' will only recognize commands +listed in `project-switch-commands' and signal an error when +others are invoked. Otherwise, all keys in `project-prefix-map' +are legal even if they aren't listed in the dispatch menu." + :type 'boolean + :group 'project + :version "28.1") + +(defun project--keymap-prompt () + "Return a prompt for the project switching dispatch menu." + (mapconcat + (pcase-lambda (`(,cmd ,label ,key)) + (when (characterp cmd) ; Old format, apparently user-customized. + (let ((tmp cmd)) + ;; TODO: Add a deprecation warning, probably. + (setq cmd key + key tmp))) + (let ((key (if key + (vector key) + (where-is-internal cmd (list project-prefix-map) t)))) + (format "[%s] %s" + (propertize (key-description key) 'face 'bold) + label))) + project-switch-commands + " ")) + +;;;###autoload +(defun project-switch-project (dir) + "\"Switch\" to another project by running an Emacs command. +The available commands are presented as a dispatch menu +made from `project-switch-commands'. + +When called in a program, it will use the project corresponding +to directory DIR." + (interactive (list (project-prompt-project-dir))) + (let* ((commands-menu + (mapcar + (lambda (row) + (if (characterp (car row)) + ;; Deprecated format. + ;; XXX: Add a warning about it? + (reverse row) + row)) + project-switch-commands)) + (commands-map + (let ((temp-map (make-sparse-keymap))) + (set-keymap-parent temp-map project-prefix-map) + (dolist (row commands-menu temp-map) + (when-let ((cmd (nth 0 row)) + (keychar (nth 2 row))) + (define-key temp-map (vector keychar) cmd))))) + command) + (while (not command) + (let ((overriding-local-map commands-map) + (choice (read-key-sequence (project--keymap-prompt)))) + (when (setq command (lookup-key commands-map choice)) + (unless (or project-switch-use-entire-map + (assq command commands-menu)) + ;; TODO: Add some hint to the prompt, like "key not + ;; recognized" or something. + (setq command nil))) + (let ((global-command (lookup-key (current-global-map) choice))) + (when (memq global-command + '(keyboard-quit keyboard-escape-quit)) + (call-interactively global-command))))) + (let ((default-directory dir) + (project-current-inhibit-prompt t)) + (call-interactively command)))) + +(provide 'project) +;;; project.el ends here diff --git a/emacs.d/elpa/rustic-20210609.1900/rustic-autoloads.el b/emacs.d/elpa/rustic-20210609.1900/rustic-autoloads.el new file mode 100644 index 0000000..97b6ec1 --- /dev/null +++ b/emacs.d/elpa/rustic-20210609.1900/rustic-autoloads.el @@ -0,0 +1,382 @@ +;;; rustic-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "rustic" "rustic.el" (0 0 0 0)) +;;; Generated autoloads from rustic.el + +(autoload 'rustic-mode "rustic" "\ +Major mode for Rust code. + +\\{rustic-mode-map} + +\(fn)" t nil) + +(add-to-list 'auto-mode-alist '("\\.rs\\'" . rustic-mode)) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rustic" '("rustic-"))) + +;;;*** + +;;;### (autoloads nil "rustic-babel" "rustic-babel.el" (0 0 0 0)) +;;; Generated autoloads from rustic-babel.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rustic-babel" '("cargo-toml-dependencies" "crate-dependencies" "org-babel-execute:rust" "rustic-"))) + +;;;*** + +;;;### (autoloads nil "rustic-cargo" "rustic-cargo.el" (0 0 0 0)) +;;; Generated autoloads from rustic-cargo.el + +(autoload 'rustic-cargo-clippy-run "rustic-cargo" "\ +Run `cargo clippy' with optional ARGS. + +\(fn &optional ARGS)" t nil) + +(autoload 'rustic-cargo-clippy "rustic-cargo" "\ +Run 'cargo clippy'. + +If ARG is not nil, use value as argument and store it in `rustic-clippy-arguments'. +When calling this function from `rustic-popup-mode', always use the value of +`rustic-clippy-arguments'. + +\(fn &optional ARG)" t nil) + +(autoload 'rustic-cargo-clippy-rerun "rustic-cargo" "\ +Run 'cargo clippy' with `rustic-clippy-arguments'." t nil) + +(autoload 'rustic-cargo-test-run "rustic-cargo" "\ +Start compilation process for 'cargo test' with optional TEST-ARGS. + +\(fn &optional TEST-ARGS)" t nil) + +(autoload 'rustic-cargo-test "rustic-cargo" "\ +Run 'cargo test'. + +If ARG is not nil, use value as argument and store it in `rustic-test-arguments'. +When calling this function from `rustic-popup-mode', always use the value of +`rustic-test-arguments'. + +\(fn &optional ARG)" t nil) + +(autoload 'rustic-cargo-test-rerun "rustic-cargo" "\ +Run 'cargo test' with `rustic-test-arguments'." t nil) + +(autoload 'rustic-cargo-current-test "rustic-cargo" "\ +Run 'cargo test' for the test near point." t nil) + +(autoload 'rustic-cargo-outdated "rustic-cargo" "\ +Use 'cargo outdated' to list outdated packages in `tabulated-list-mode'. +Execute process in PATH. + +\(fn &optional PATH)" t nil) + +(autoload 'rustic-cargo-reload-outdated "rustic-cargo" "\ +Update list of outdated packages." t nil) + +(autoload 'rustic-cargo-mark-upgrade "rustic-cargo" "\ +Mark an upgradable package." t nil) + +(autoload 'rustic-cargo-mark-all-upgrades "rustic-cargo" "\ +Mark all upgradable packages in the Package Menu." t nil) + +(autoload 'rustic-cargo-menu-mark-unmark "rustic-cargo" "\ +Clear any marks on a package." t nil) + +(autoload 'rustic-cargo-upgrade-execute "rustic-cargo" "\ +Perform marked menu actions." t nil) + +(autoload 'rustic-cargo-new "rustic-cargo" "\ +Run 'cargo new' to start a new package in the path specified by PROJECT-PATH. +If BIN is not nil, create a binary application, otherwise a library. + +\(fn PROJECT-PATH &optional BIN)" t nil) + +(autoload 'rustic-cargo-init "rustic-cargo" "\ +Run 'cargo init' to initialize a directory in the path specified by PROJECT-PATH. +If BIN is not nil, create a binary application, otherwise a library. + +\(fn PROJECT-PATH &optional BIN)" t nil) + +(autoload 'rustic-cargo-build "rustic-cargo" "\ +Run 'cargo build' for the current project." t nil) + +(autoload 'rustic-cargo-run "rustic-cargo" "\ +Run 'cargo run' for the current project. +If running with prefix command `C-u', read whole command from minibuffer. + +\(fn &optional ARG)" t nil) + +(autoload 'rustic-cargo-clean "rustic-cargo" "\ +Run 'cargo clean' for the current project." t nil) + +(autoload 'rustic-cargo-check "rustic-cargo" "\ +Run 'cargo check' for the current project." t nil) + +(autoload 'rustic-cargo-bench "rustic-cargo" "\ +Run 'cargo bench' for the current project." t nil) + +(autoload 'rustic-cargo-build-doc "rustic-cargo" "\ +Build the documentation for the current project." t nil) + +(autoload 'rustic-cargo-doc "rustic-cargo" "\ +Open the documentation for the current project in a browser. +The documentation is built if necessary." t nil) + +(autoload 'rustic-cargo-add "rustic-cargo" "\ +Add crate to Cargo.toml using 'cargo add'. +If running with prefix command `C-u', read whole command from minibuffer. + +\(fn &optional ARG)" t nil) + +(autoload 'rustic-cargo-rm "rustic-cargo" "\ +Remove crate from Cargo.toml using 'cargo rm'. +If running with prefix command `C-u', read whole command from minibuffer. + +\(fn &optional ARG)" t nil) + +(autoload 'rustic-cargo-upgrade "rustic-cargo" "\ +Upgrade dependencies as specified in the local manifest file using 'cargo upgrade'. +If running with prefix command `C-u', read whole command from minibuffer. + +\(fn &optional ARG)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rustic-cargo" '("rustic-"))) + +;;;*** + +;;;### (autoloads nil "rustic-compile" "rustic-compile.el" (0 0 0 +;;;;;; 0)) +;;; Generated autoloads from rustic-compile.el + +(autoload 'rustic-compile "rustic-compile" "\ +Compile rust project. + +If `compilation-read-command' is non-nil or if called with prefix +argument ARG then read the command in the minibuffer. Otherwise +use `rustic-compile-command'. + +In either store the used command in `compilation-arguments'. + +\(fn &optional ARG)" t nil) + +(autoload 'rustic-recompile "rustic-compile" "\ +Re-compile the program using `compilation-arguments'." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rustic-compile" '("rust"))) + +;;;*** + +;;;### (autoloads nil "rustic-doc" "rustic-doc.el" (0 0 0 0)) +;;; Generated autoloads from rustic-doc.el + +(autoload 'rustic-doc-dumb-search "rustic-doc" "\ +Search all projects and std for SEARCH-TERM. +Use this when `rustic-doc-search' does not find what you're looking for. +Add `universal-argument' to only search level 1 headers. +See `rustic-doc-search' for more information. + +\(fn SEARCH-TERM)" t nil) + +(autoload 'rustic-doc-search "rustic-doc" "\ +Search the rust documentation for SEARCH-TERM. +Only searches in headers (structs, functions, traits, enums, etc) +to limit the number of results. +To limit search results to only level 1 headers, add `universal-argument' +Level 1 headers are things like struct or enum names. +if ROOT is non-nil the search is performed from the root dir. +This function tries to be smart and limits the search results +as much as possible. If it ends up being so smart that +it doesn't manage to find what you're looking for, try `rustic-doc-dumb-search'. + +\(fn SEARCH-TERM &optional ROOT)" t nil) + +(autoload 'rustic-doc-convert-current-package "rustic-doc" "\ +Convert the documentation for a project and its dependencies." t nil) + +(autoload 'rustic-doc-setup "rustic-doc" "\ +Setup or update rustic-doc filter and convert script. Convert std." t nil) + +(autoload 'rustic-doc-mode "rustic-doc" "\ +Convert rust html docs to .org, and browse the converted docs. + +If called interactively, enable Rustic-Doc mode if ARG is +positive, and disable it if ARG is zero or negative. If called +from Lisp, also enable the mode if ARG is omitted or nil, and +toggle it if ARG is `toggle'; disable the mode otherwise. + +\(fn &optional ARG)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rustic-doc" '("rustic-doc-"))) + +;;;*** + +;;;### (autoloads nil "rustic-flycheck" "rustic-flycheck.el" (0 0 +;;;;;; 0 0)) +;;; Generated autoloads from rustic-flycheck.el + +(autoload 'rustic-flycheck-setup "rustic-flycheck" "\ +Setup Rust in Flycheck. + +If the current file is part of a Cargo project, configure +Flycheck according to the Cargo project layout." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rustic-flycheck" '("rustic-flycheck-"))) + +;;;*** + +;;;### (autoloads nil "rustic-interaction" "rustic-interaction.el" +;;;;;; (0 0 0 0)) +;;; Generated autoloads from rustic-interaction.el + +(autoload 'rustic-indent-line "rustic-interaction" nil t nil) + +(autoload 'rustic-promote-module-into-dir "rustic-interaction" "\ +Promote the module file visited by the current buffer into its own directory. + +For example, if the current buffer is visiting the file `foo.rs', +then this function creates the directory `foo' and renames the +file to `foo/mod.rs'. The current buffer will be updated to +visit the new file." t nil) + +(autoload 'rustic-open-dependency-file "rustic-interaction" "\ +Open the 'Cargo.toml' file at the project root if the current buffer is +visiting a project." t nil) + +(autoload 'rustic-beginning-of-defun "rustic-interaction" "\ +Move backward to the beginning of the current defun. + +With ARG, move backward multiple defuns. Negative ARG means +move forward. + +This is written mainly to be used as `beginning-of-defun-function' for Rust. +Don't move to the beginning of the line. `beginning-of-defun', +which calls this, does that afterwards. + +\(fn &optional ARG REGEX)" t nil) + +(autoload 'rustic-end-of-defun "rustic-interaction" "\ +Move forward to the next end of defun. + +With argument, do it that many times. +Negative argument -N means move back to Nth preceding end of defun. + +Assume that this is called after beginning-of-defun. So point is +at the beginning of the defun body. + +This is written mainly to be used as `end-of-defun-function' for Rust." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rustic-interaction" '("rustic-"))) + +;;;*** + +;;;### (autoloads nil "rustic-lsp" "rustic-lsp.el" (0 0 0 0)) +;;; Generated autoloads from rustic-lsp.el + +(autoload 'rustic-analyzer-macro-expand "rustic-lsp" "\ +Default method for displaying macro expansion results. + +\(fn RESULT)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rustic-lsp" '("rustic-"))) + +;;;*** + +;;;### (autoloads nil "rustic-playpen" "rustic-playpen.el" (0 0 0 +;;;;;; 0)) +;;; Generated autoloads from rustic-playpen.el + +(autoload 'rustic-playpen "rustic-playpen" "\ +Create a shareable URL for the contents of the current region, +src-block or buffer on the Rust playpen. + +\(fn BEGIN END)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rustic-playpen" '("rustic-"))) + +;;;*** + +;;;### (autoloads nil "rustic-popup" "rustic-popup.el" (0 0 0 0)) +;;; Generated autoloads from rustic-popup.el + +(autoload 'rustic-popup "rustic-popup" "\ +Setup popup. +If directory is not in a rust project call `read-directory-name'." t nil) + +(autoload 'rustic-popup-invoke-popup-action "rustic-popup" "\ +Execute commands which are listed in `rustic-popup-commands'. + +\(fn EVENT)" t nil) + +(autoload 'rustic-popup-default-action "rustic-popup" "\ +Change backtrace and `compilation-arguments' when executed on +corresponding line." t nil) + +(autoload 'rustic-popup-cargo-command-help "rustic-popup" "\ +Display help buffer for cargo command at point." t nil) + +(autoload 'rustic-popup-kill-help-buffer "rustic-popup" "\ +Kill popup help buffer and switch to popup buffer." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rustic-popup" '("rustic-popup-"))) + +;;;*** + +;;;### (autoloads nil "rustic-racer" "rustic-racer.el" (0 0 0 0)) +;;; Generated autoloads from rustic-racer.el + +(autoload 'rustic-racer-describe "rustic-racer" "\ +Show a *Racer Help* buffer for the function or type at point." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rustic-racer" '("racer-src-button" "rustic-racer-"))) + +;;;*** + +;;;### (autoloads nil "rustic-rustfix" "rustic-rustfix.el" (0 0 0 +;;;;;; 0)) +;;; Generated autoloads from rustic-rustfix.el + +(autoload 'rustic-rustfix "rustic-rustfix" "\ +Run 'cargo fix'." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rustic-rustfix" '("rustic-rustfix-"))) + +;;;*** + +;;;### (autoloads nil "rustic-rustfmt" "rustic-rustfmt.el" (0 0 0 +;;;;;; 0)) +;;; Generated autoloads from rustic-rustfmt.el + +(autoload 'rustic-cargo-fmt "rustic-rustfmt" "\ +Use rustfmt via cargo." t nil) + +(autoload 'rustic-format-buffer "rustic-rustfmt" "\ +Format the current buffer using rustfmt. + +Provide optional argument NO-STDIN for `rustic-before-save-hook' since there +were issues when using stdin for formatting." t nil) + +(autoload 'rustic-format-file "rustic-rustfmt" "\ +Unlike `rustic-format-buffer' format file directly and revert the buffer. + +\(fn &optional FILE)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "rustic-rustfmt" '("rustic-"))) + +;;;*** + +;;;### (autoloads nil nil ("rustic-pkg.el") (0 0 0 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; rustic-autoloads.el ends here diff --git a/emacs.d/elpa/rustic-20210609.1900/rustic-babel.el b/emacs.d/elpa/rustic-20210609.1900/rustic-babel.el new file mode 100644 index 0000000..2a6dbb0 --- /dev/null +++ b/emacs.d/elpa/rustic-20210609.1900/rustic-babel.el @@ -0,0 +1,288 @@ +;;; rustic-babel.el --- Org babel facilities for cargo -*-lexical-binding: t-*- + +;;; Code: + +(require 'org) +(require 'org-element) +(require 'ob) +(require 'ob-eval) +(require 'ob-ref) +(require 'ob-core) + +(require 'rustic-rustfmt) + +;; FIXME This variable doesn't exist in noninteractive emacs sessions, +;; which probably means that it is internal and we shouldn't use it. +(defvar org-babel-temporary-directory) + +(defvar rustic-info nil) + +(add-to-list 'org-src-lang-modes '("rust" . rustic)) +(add-to-list 'org-babel-tangle-lang-exts '("rustic" . "rs")) +(defalias 'org-babel-execute:rust #'org-babel-execute:rustic) + +(defcustom rustic-babel-display-compilation-buffer nil + "Whether to display compilation buffer." + :type 'boolean + :group 'rustic-babel) + +(defcustom rustic-babel-format-src-block t + "Whether to format a src block automatically after successful execution." + :type 'boolean + :group 'rustic-babel) + +(defvar rustic-babel-buffer-name '((:default . "*rust-babel*"))) + +(defvar rustic-babel-process-name "rustic-babel-process" + "Process name for org-babel rust compilation processes.") + +(defvar rustic-babel-compilation-buffer-name "*rustic-babel-compilation-buffer*" + "Buffer name for org-babel rust compilation process buffers.") + +(defvar rustic-babel-dir nil + "Holds the latest rust babel project directory.") + +(defvar rustic-babel-src-location nil + "Marker, holding location of last evaluated src block.") + +(defvar rustic-babel-params nil + "Babel parameters.") + +(defvar rustic-babel-spinner nil) + +(defun rustic-babel-eval (dir) + "Start a rust babel compilation process in directory DIR." + (let* ((err-buff (get-buffer-create rustic-babel-compilation-buffer-name)) + (default-directory dir) + (params '("cargo" "build" "--quiet")) + (inhibit-read-only t)) + (rustic-compilation-setup-buffer err-buff dir 'rustic-compilation-mode) + (when rustic-babel-display-compilation-buffer + (display-buffer err-buff)) + (rustic-make-process + :name rustic-babel-process-name + :buffer err-buff + :command params + :filter #'rustic-compilation-filter + :sentinel #'rustic-babel-build-sentinel))) + +(defun rustic-babel-build-sentinel (proc _output) + "Sentinel for rust babel compilation process PROC. +If `rustic-babel-format-src-block' is t, format src-block after successful +execution with rustfmt." + (let ((proc-buffer (process-buffer proc)) + (inhibit-read-only t)) + (if (zerop (process-exit-status proc)) + (let* ((default-directory rustic-babel-dir)) + ;; format babel block + (when rustic-babel-format-src-block + (let ((babel-body + (org-element-property :value (org-element-at-point))) + (proc + (make-process :name "rustic-babel-format" + :buffer "rustic-babel-format-buffer" + :command `(,rustic-rustfmt-bin + ,@(rustic-compute-rustfmt-args)) + :filter #'rustic-compilation-filter + :sentinel #'rustic-babel-format-sentinel))) + (while (not (process-live-p proc)) + (sleep-for 0.01)) + (process-send-string proc babel-body) + (process-send-eof proc) + (while (eq (process-status proc) 'run) + (sit-for 0.1)))) + + ;; run project + (let* ((err-buff (get-buffer-create rustic-babel-compilation-buffer-name)) + (params '("cargo" "run" "--quiet")) + (inhibit-read-only t)) + (rustic-make-process + :name rustic-babel-process-name + :buffer err-buff + :command params + :filter #'rustic-compilation-filter + :sentinel #'rustic-babel-run-sentinel))) + + (let* ((project (car (reverse (split-string rustic-babel-dir "/")))) + (result (format "error: Could not compile `%s`." project))) + (rustic-babel-build-update-result-block result)) + (rustic-with-spinner rustic-babel-spinner nil nil) + (if (= (length (with-current-buffer proc-buffer (buffer-string))) 0) + (kill-buffer proc-buffer) + (pop-to-buffer proc-buffer))))) + +(defun rustic-babel-run-sentinel (proc _output) + "Sentinel for babel project execution." + (let ((proc-buffer (process-buffer proc)) + result) + (if (zerop (process-exit-status proc)) + (progn + (with-current-buffer proc-buffer + (setq result (buffer-string))) + (rustic-babel-run-update-result-block result) + (rustic-with-spinner rustic-babel-spinner nil nil) + (unless rustic-babel-display-compilation-buffer + (kill-buffer proc-buffer))) + (progn + (with-current-buffer proc-buffer + (save-excursion + (save-match-data + (goto-char (point-min)) + (when (re-search-forward "^thread '[^']+' panicked at '[^']+', ") + (goto-char (match-beginning 0)) + (setq result (buffer-substring-no-properties (point) (line-end-position))))))) + (rustic-babel-run-update-result-block result) + (rustic-with-spinner rustic-babel-spinner nil nil) + (pop-to-buffer proc-buffer))))) + +(defun rustic-babel-build-update-result-block (result) + "Update result block with RESULT." + (let ((marker rustic-babel-src-location)) + (with-current-buffer (marker-buffer marker) + (goto-char marker) + (org-babel-remove-result) + (org-babel-insert-result result)))) + +(defun rustic-babel-run-update-result-block (result) + "Update result block with RESULT." + (let ((marker rustic-babel-src-location)) + (with-current-buffer (marker-buffer marker) + (goto-char marker) + + (let ((file (cdr (assq :file rustic-babel-params))) + (results-params (cdr (assq :result-params rustic-babel-params)))) + ;; If non-empty result and :file then write to :file. + (when (and file results-params) + (when result + (with-temp-file file + (insert (org-babel-format-result + result (cdr (assq :sep rustic-babel-params)))))) + (setq result file)) + + (org-babel-remove-result rustic-info) + (org-babel-insert-result result results-params rustic-info))))) + +(defun rustic-babel-format-sentinel (proc output) + "This sentinel is used by the process `rustic-babel-format', that runs +after successful compilation." + (ignore-errors + (let ((proc-buffer (process-buffer proc)) + (marker rustic-babel-src-location)) + (save-excursion + (with-current-buffer proc-buffer + (when (string-match-p "^finished" output) + (with-current-buffer (marker-buffer marker) + (goto-char marker) + (org-babel-update-block-body + (with-current-buffer "rustic-babel-format-buffer" + (buffer-string))))))) + (kill-buffer "rustic-babel-format-buffer")))) + +(defun rustic-babel-generate-project (&optional expand) + "Create rust project in `org-babel-temporary-directory'. +Return full path if EXPAND is t." + (let* ((default-directory org-babel-temporary-directory) + (dir (make-temp-file-internal "cargo" 0 "" nil))) + (shell-command-to-string (format "cargo new %s --bin --quiet" dir)) + (if expand + (concat (expand-file-name dir) "/") + dir))) + +(defun rustic-babel-project () + "In order to reduce the execution time when the project has +dependencies, the project name is stored as a text property in the +header of the org-babel block to check if the project already exists +in `org-babel-temporary-directory'. If the project exists, reuse it. +Otherwise create it with `rustic-babel-generate-project'." + (let* ((beg (org-babel-where-is-src-block-head)) + (end (save-excursion (goto-char beg) + (line-end-position))) + (line (buffer-substring beg end))) + (let* ((project (symbol-name (get-text-property 0 'project line))) + (path (concat org-babel-temporary-directory "/" project "/"))) + (if (file-directory-p path) + (progn + (put-text-property beg end 'project (make-symbol project)) + project) + (let ((new (rustic-babel-generate-project))) + (put-text-property beg end 'project (make-symbol new)) + new))))) + +(defun crate-dependencies (name version features) + "Generate a Cargo.toml [dependencies] entry for a crate given a version and features." + (let ((version-string (concat "version = \"" version "\"")) + (features-string + (if features + (concat "features = [" (mapconcat (lambda (s) (concat "\"" s "\"")) features ", ") "]") + nil))) + (let ((toml-entry (string-join (remove nil (list version-string features-string)) ", "))) + (concat name " = {" toml-entry "}")))) + +(defun cargo-toml-dependencies (crate-versions crate-features) + "Generate the [dependencies] section of a Cargo.toml file given crates and their versions & features." + (let ((dependencies "")) + (dolist (crate-and-version crate-versions) + (let ((name (car crate-and-version)) + (version (cdr crate-and-version))) + (let ((features (cdr (assoc name crate-features)))) + (setq name (symbol-name name)) + (when (numberp version) + (setq version (number-to-string version))) + (when (not (listp features)) + (setq features (list features))) + (let ((cargo-toml-entry (crate-dependencies name version features))) + (setq dependencies (concat dependencies cargo-toml-entry "\n")))))) + (setq dependencies (concat "[dependencies]\n" dependencies)))) + +(defun rustic-babel-cargo-toml (dir params) + "Append crates to Cargo.toml. +Use org-babel parameter crates from PARAMS and add them to the project in +directory DIR." + (let ((crates (cdr (assq :crates params))) + (features (cdr (assq :features params))) + (toml (expand-file-name "Cargo.toml" dir))) + (let ((dependencies (cargo-toml-dependencies crates features))) + (make-directory (file-name-directory toml) t) + (with-temp-file toml + (condition-case nil + (insert-file-contents toml) + (file-missing)) + (let ((s (nth 0 (split-string (buffer-string) "\\[dependencies]")))) + (erase-buffer) + (insert s) + (insert dependencies)))))) + +(defun org-babel-execute:rustic (body params) + "Execute a block of Rust code with org-babel. + +If called while there's a live Rust babel process, ask user whether to +kill the running process." + (let ((p (get-process rustic-babel-process-name))) + (if (process-live-p p) + (progn + (rustic-process-kill-p p t) + nil) + (let* ((default-directory org-babel-temporary-directory) + (project (rustic-babel-project)) + (dir (setq rustic-babel-dir (expand-file-name project))) + (main (expand-file-name "main.rs" (concat dir "/src")))) + (make-directory (file-name-directory main) t) + (rustic-babel-cargo-toml dir params) + (setq rustic-info (org-babel-get-src-block-info)) + (setq rustic-babel-params params) + + (rustic-with-spinner rustic-babel-spinner + (make-spinner rustic-spinner-type t 10) + '(rustic-babel-spinner (":Executing " (:eval (spinner-print rustic-babel-spinner)))) + (spinner-start rustic-babel-spinner)) + + (let ((default-directory dir)) + (write-region + (concat "#![allow(non_snake_case)]\n" body) nil main nil 0) + (rustic-babel-eval dir) + (setq rustic-babel-src-location + (set-marker (make-marker) (point) (current-buffer))) + project))))) + +(provide 'rustic-babel) +;;; rustic-babel.el ends here diff --git a/emacs.d/elpa/rustic-20210609.1900/rustic-cargo.el b/emacs.d/elpa/rustic-20210609.1900/rustic-cargo.el new file mode 100644 index 0000000..3e56dd4 --- /dev/null +++ b/emacs.d/elpa/rustic-20210609.1900/rustic-cargo.el @@ -0,0 +1,530 @@ +;;; rustic-cargo.el --- Cargo based commands -*-lexical-binding: t-*- +;;; Commentary: + +;; This library implements support for `cargo'. + +;;; Code: + +(require 'tabulated-list) + +(require 'rustic-compile) +(require 'rustic-interaction) ; for rustic-beginning-of-function + +;;; Customization + +(defcustom rustic-cargo-bin "cargo" + "Path to cargo executable." + :type 'string + :group 'rustic-cargo) + +(defcustom rustic-cargo-open-new-project t + "If t then any project created with cargo-new will be opened automatically. +If nil then the project is simply created." + :type 'boolean + :group 'rustic-cargo) + +(defvar rustic-cargo-outdated-face nil) +(make-obsolete-variable 'rustic-cargo-outdated-face + "use the face `rustic-cargo-outdated' instead." + "1.2") + +(defface rustic-cargo-outdated + '((t (:foreground "red"))) + "Face used for outdated crates." + :group 'rustic) + +(define-obsolete-face-alias 'rustic-cargo-outdated-upgrade-face + 'rustic-cargo-outdated-upgrade "1.2") + +(defface rustic-cargo-outdated-upgrade + '((t (:foreground "LightSeaGreen"))) + "Face used for crates marked for upgrade." + :group 'rustic) + +;;; Clippy + +(defvar rustic-clippy-process-name "rustic-cargo-clippy-process" + "Process name for clippy processes.") + +(defvar rustic-clippy-buffer-name "*cargo-clippy*" + "Buffer name for clippy buffers.") + +(defvar rustic-clippy-arguments "" + "Holds arguments for 'cargo clippy', similar to `compilation-arguments`.") + +(define-derived-mode rustic-cargo-clippy-mode rustic-compilation-mode "cargo-clippy" + :group 'rustic) + +;;;###autoload +(defun rustic-cargo-clippy-run (&optional args) + "Run `cargo clippy' with optional ARGS." + (interactive) + (let* ((command (list rustic-cargo-bin "clippy")) + (c (append command (split-string (if args args "")))) + (buf rustic-clippy-buffer-name) + (proc rustic-clippy-process-name) + (mode 'rustic-cargo-clippy-mode)) + (rustic-compilation-process-live) + (rustic-compilation c (list :buffer buf :process proc :mode mode)))) + +;;;###autoload +(defun rustic-cargo-clippy (&optional arg) + "Run 'cargo clippy'. + +If ARG is not nil, use value as argument and store it in `rustic-clippy-arguments'. +When calling this function from `rustic-popup-mode', always use the value of +`rustic-clippy-arguments'." + (interactive "P") + (rustic-cargo-clippy-run + (cond (arg + (setq rustic-clippy-arguments (read-from-minibuffer "Cargo clippy arguments: " rustic-clippy-arguments))) + ((eq major-mode 'rustic-popup-mode) + rustic-clippy-arguments) + (t "")))) + +;;;###autoload +(defun rustic-cargo-clippy-rerun () + "Run 'cargo clippy' with `rustic-clippy-arguments'." + (interactive) + (rustic-cargo-clippy-run rustic-clippy-arguments)) + +;;; Test + +(defvar rustic-test-process-name "rustic-cargo-test-process" + "Process name for test processes.") + +(defvar rustic-test-buffer-name "*cargo-test*" + "Buffer name for test buffers.") + +(defvar rustic-test-arguments "" + "Holds arguments for 'cargo test', similar to `compilation-arguments`.") + +(define-derived-mode rustic-cargo-test-mode rustic-compilation-mode "cargo-test" + :group 'rustic) + +;;;###autoload +(defun rustic-cargo-test-run (&optional test-args) + "Start compilation process for 'cargo test' with optional TEST-ARGS." + (interactive) + (rustic-compilation-process-live) + (let* ((command (list rustic-cargo-bin "test")) + (c (append command (split-string (if test-args test-args "")))) + (buf rustic-test-buffer-name) + (proc rustic-test-process-name) + (mode 'rustic-cargo-test-mode)) + (rustic-compilation c (list :buffer buf :process proc :mode mode)))) + +;;;###autoload +(defun rustic-cargo-test (&optional arg) + "Run 'cargo test'. + +If ARG is not nil, use value as argument and store it in `rustic-test-arguments'. +When calling this function from `rustic-popup-mode', always use the value of +`rustic-test-arguments'." + (interactive "P") + (rustic-cargo-test-run + (cond (arg + (setq rustic-test-arguments (read-from-minibuffer "Cargo test arguments: " rustic-test-arguments))) + ((eq major-mode 'rustic-popup-mode) + rustic-test-arguments) + (t "")))) + +;;;###autoload +(defun rustic-cargo-test-rerun () + "Run 'cargo test' with `rustic-test-arguments'." + (interactive) + (rustic-cargo-test-run rustic-test-arguments)) + +;;;###autoload +(defun rustic-cargo-current-test () + "Run 'cargo test' for the test near point." + (interactive) + (rustic-compilation-process-live) + (-if-let (func-name (rustic-cargo--get-current-fn-fullname)) + (let* ((command (list rustic-cargo-bin "test" func-name)) + (c (append command (split-string rustic-test-arguments))) + (buf rustic-test-buffer-name) + (proc rustic-test-process-name) + (mode 'rustic-cargo-test-mode)) + (rustic-compilation c (list :buffer buf :process proc :mode mode))) + (message "Could not find test at point."))) + +(defconst rustic-cargo-mod-regexp + "^\s*mod\s+\\([[:word:][:multibyte:]_][[:word:][:multibyte:]_[:digit:]]*\\)\s*{") +(defconst rustic-cargo-fn-regexp + "^\s*\\(?:async\s+\\)?\s*fn\s+\\([^(]+\\)\s*(") + +(defun rustic-cargo--get-current-fn-fullname() + "Return full name of the fn around point including module name if any." + (let ((mod (rustic-cargo--get-current-mod)) + (fn (rustic-cargo--get-current-fn-name))) + (if mod + (concat mod "::" fn) + fn))) + +(defun rustic-cargo--get-current-mod () + "Return mod name around point or nil." + (save-excursion + (when (search-backward-regexp rustic-cargo-mod-regexp nil t) + (match-string 1)))) + +(defun rustic-cargo--get-current-line-fn-name() + "Return fn name from the current line or nil." + (save-excursion + (goto-char (line-beginning-position)) + (when (search-forward-regexp rustic-cargo-fn-regexp (line-end-position) t) + (match-string 1)))) + +(defun rustic-cargo--get-current-fn-name() + "Return fn name around point or nil." + (save-excursion + (or (rustic-cargo--get-current-line-fn-name) + (progn + (rustic-beginning-of-function) + (rustic-cargo--get-current-line-fn-name))))) + +;;; Outdated + +(defvar rustic-cargo-outdated-process-name "rustic-cargo-outdated-process") + +(defvar rustic-cargo-oudated-buffer-name "*cargo-outdated*") + +(defvar rustic-cargo-outdated-spinner nil) + +(defvar rustic-cargo-outdated-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map tabulated-list-mode-map) + (define-key map (kbd "m") 'rustic-cargo-menu-mark-unmark) + (define-key map (kbd "u") 'rustic-cargo-mark-upgrade) + (define-key map (kbd "U") 'rustic-cargo-mark-all-upgrades) + (define-key map (kbd "x") 'rustic-cargo-upgrade-execute) + (define-key map (kbd "r") 'rustic-cargo-reload-outdated) + (define-key map (kbd "c") 'rustic-compile) + (define-key map (kbd "q") 'quit-window) + map) + "Local keymap for `rustic-cargo-outdated-mode' buffers.") + +(define-derived-mode rustic-cargo-outdated-mode tabulated-list-mode "cargo-outdated" + "Major mode for viewing outdated crates in the current workspace." + (setq truncate-lines t) + (setq tabulated-list-format + `[("Name" 25 nil) + ("Project" 10 nil) + ("Compat" 10 nil) + ("Latest" 10 nil) + ("Kind" 10 nil) + ("Platform" 0 nil)]) + (setq tabulated-list-padding 2) + (tabulated-list-init-header)) + +;;;###autoload +(defun rustic-cargo-outdated (&optional path) + "Use 'cargo outdated' to list outdated packages in `tabulated-list-mode'. +Execute process in PATH." + (interactive) + (let* ((dir (or path (rustic-buffer-workspace))) + (buf (get-buffer-create rustic-cargo-oudated-buffer-name)) + (default-directory dir) + (inhibit-read-only t)) + (make-process :name rustic-cargo-outdated-process-name + :buffer buf + :command '("cargo" "outdated" "--depth" "1") + :filter #'rustic-cargo-outdated-filter + :sentinel #'rustic-cargo-outdated-sentinel) + (with-current-buffer buf + (setq default-directory dir) + (erase-buffer) + (rustic-cargo-outdated-mode) + (rustic-with-spinner rustic-cargo-outdated-spinner + (make-spinner rustic-spinner-type t 10) + '(rustic-cargo-outdated-spinner + (":Executing " (:eval (spinner-print rustic-cargo-outdated-spinner)))) + (spinner-start rustic-cargo-outdated-spinner))) + (display-buffer buf))) + +;;;###autoload +(defun rustic-cargo-reload-outdated () + "Update list of outdated packages." + (interactive) + (rustic-cargo-outdated default-directory)) + +(defun rustic-cargo-outdated-filter (proc output) + "Filter for rustic-cargo-outdated-process." + (let ((inhibit-read-only t)) + (with-current-buffer (process-buffer proc) + (insert output)))) + +(defun rustic-cargo-outdated-sentinel (proc _output) + "Sentinel for rustic-cargo-outdated-process." + (let ((buf (process-buffer proc)) + (inhibit-read-only t) + (exit-status (process-exit-status proc))) + (if (zerop exit-status) + (with-current-buffer buf + (goto-char (point-min)) + (forward-line 2) + (let ((packages (split-string + (buffer-substring (point) (point-max)) "\n" t))) + (erase-buffer) + (rustic-cargo-outdated-generate-menu packages)) + (pop-to-buffer buf)) + (with-current-buffer buf + (let ((out (buffer-string))) + (if (= exit-status 101) + (rustic-cargo-install-crate-p "outdated") + (message out)))))) + (rustic-with-spinner rustic-cargo-outdated-spinner nil nil)) + +(defun rustic-cargo-install-crate-p (crate) + "Ask whether to install crate CRATE." + (let ((cmd (format "cargo install cargo-%s" crate))) + (when (yes-or-no-p (format "Cargo-%s missing. Install ? " crate)) + (async-shell-command cmd "cargo" "cargo-error")))) + +(defun rustic-cargo-outdated-generate-menu (packages) + "Re-populate the `tabulated-list-entries' with PACKAGES." + (setq tabulated-list-entries + (mapcar #'rustic-cargo-outdated-menu-entry packages)) + (tabulated-list-print t)) + +(defun rustic-cargo-outdated-menu-entry (crate) + "Return a package entry of CRATE suitable for `tabulated-list-entries'." + (let* ((fields (split-string crate "\s\s+" )) + (name (nth 0 fields)) + (project (nth 1 fields)) + (compat (nth 2 fields))) + (list name `[,name + ,project + ,(if (when (not (string-match "^-" compat)) + (version< project compat)) + (propertize compat 'font-lock-face 'rustic-cargo-outdated) + compat) + ,(nth 3 fields) + ,(nth 4 fields) + ,(nth 5 fields)]))) + +;;;###autoload +(defun rustic-cargo-mark-upgrade () + "Mark an upgradable package." + (interactive) + (let* ((crate (tabulated-list-get-entry (point))) + (v (read-from-minibuffer "Update to version: " + (substring-no-properties (elt crate 2)))) + (inhibit-read-only t)) + (when v + (save-excursion + (goto-char (line-beginning-position)) + (save-match-data + (when (search-forward (elt crate 0)) + (replace-match (propertize (elt crate 0) + 'font-lock-face + 'rustic-cargo-outdated-upgrade))) + (goto-char (line-beginning-position)) + (when (search-forward (elt crate 1)) + (replace-match (propertize v + 'font-lock-face + 'rustic-cargo-outdated-upgrade))))) + (tabulated-list-put-tag "U" t)))) + +;;;###autoload +(defun rustic-cargo-mark-all-upgrades () + "Mark all upgradable packages in the Package Menu." + (interactive) + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + (let ((project (aref (tabulated-list-get-entry) 1)) + (compat (aref (tabulated-list-get-entry) 2))) + (if (or (string-match "^-" compat) + (not (version< project compat))) + (forward-line) + (tabulated-list-put-tag "U" t)))))) + +;;;###autoload +(defun rustic-cargo-menu-mark-unmark () + "Clear any marks on a package." + (interactive) + (tabulated-list-put-tag " " t)) + +;;;###autoload +(defun rustic-cargo-upgrade-execute () + "Perform marked menu actions." + (interactive) + (let (crates) + (save-excursion + (goto-char (point-min)) + (while (not (eobp)) + (let* ((cmd (char-after)) + (crate (tabulated-list-get-entry (point)))) + (when (eq cmd ?U) + (push crate crates))) + (forward-line))) + (if crates + (let ((msg (format "Upgrade %s ?" (mapconcat #'(lambda (x) (elt x 0)) crates " ")))) + (when (yes-or-no-p msg) + (rustic-cargo-upgrade-crates crates))) + (user-error "No operations specified")))) + +(defun rustic-cargo-upgrade-crates (crates) + "Upgrade CRATES." + (let (upgrade) + (dolist (crate crates) + (setq upgrade (concat upgrade (format "%s@%s " (elt crate 0) (elt crate 2))))) + (let ((output (shell-command-to-string (format "cargo upgrade %s" upgrade)))) + (if (string-match "error: no such subcommand:" output) + (rustic-cargo-install-crate-p "edit") + (rustic-cargo-reload-outdated))))) + +;;; New project + +(defun rustic-create-project (project-path is-new &optional bin) + "Run either 'cargo new' if IS-NEW is non-nil, or 'cargo init' otherwise. +Creates or initializes the directory at the path specified by PROJECT-PATH. If +BIN is not nil, create a binary application, otherwise a library." + (let* ((cmd (if is-new "new" "init")) + (bin (if (or bin (y-or-n-p "Create new binary package? ")) + "--bin" + "--lib")) + (new-sentinel (lambda (_process signal) + (when (equal signal "finished\n") + (message (format "Created new package: %s" + (file-name-base project-path))) + (when rustic-cargo-open-new-project + (find-file (concat project-path + (if (string= bin "--bin") + "/src/main.rs" + "/src/lib.rs"))))))) + (proc (format "rustic-cargo-%s-process" cmd)) + (buf (format "*cargo-%s*" cmd))) + (make-process :name proc + :buffer buf + :command (list rustic-cargo-bin cmd bin project-path) + :sentinel new-sentinel))) + +;;;###autoload +(defun rustic-cargo-new (project-path &optional bin) + "Run 'cargo new' to start a new package in the path specified by PROJECT-PATH. +If BIN is not nil, create a binary application, otherwise a library." + (interactive "DProject path: ") + (rustic-create-project project-path t bin)) + +;;;###autoload +(defun rustic-cargo-init (project-path &optional bin) + "Run 'cargo init' to initialize a directory in the path specified by PROJECT-PATH. +If BIN is not nil, create a binary application, otherwise a library." + (interactive "DProject path: ") + (rustic-create-project project-path nil bin)) + +;;; Cargo commands + +(defun rustic-run-cargo-command (command &optional args) + "Run the specified COMMAND with cargo." + (rustic-compilation-process-live) + (rustic-compilation-start (split-string command) args)) + +;;;###autoload +(defun rustic-cargo-build () + "Run 'cargo build' for the current project." + (interactive) + (rustic-run-cargo-command "cargo build")) + +;;;###autoload +(defun rustic-cargo-run (&optional arg) + "Run 'cargo run' for the current project. +If running with prefix command `C-u', read whole command from minibuffer." + (interactive "P") + (let* ((command (if arg + (read-from-minibuffer "Cargo run command: " "cargo run ") + (concat rustic-cargo-bin " run " + (read-from-minibuffer + "Run arguments: " + (car compile-history) + nil nil + 'compile-history))))) + (rustic-run-cargo-command command (list :mode 'rustic-cargo-run-mode)))) + +(define-derived-mode rustic-cargo-run-mode rustic-compilation-mode "Cargo run" + "Mode for 'cargo run' that derives from `rustic-compilation-mode', but uses +the keymap of `comint-mode' so user input is possible." + (buffer-disable-undo) + (setq buffer-read-only nil) + (use-local-map comint-mode-map)) + +;;;###autoload +(defun rustic-cargo-clean () + "Run 'cargo clean' for the current project." + (interactive) + (rustic-run-cargo-command "cargo clean")) + +;;;###autoload +(defun rustic-cargo-check () + "Run 'cargo check' for the current project." + (interactive) + (rustic-run-cargo-command "cargo check")) + +;;;###autoload +(defun rustic-cargo-bench () + "Run 'cargo bench' for the current project." + (interactive) + (rustic-run-cargo-command "cargo bench")) + +;;;###autoload +(defun rustic-cargo-build-doc () + "Build the documentation for the current project." + (interactive) + (if (y-or-n-p "Create documentation for dependencies?") + (rustic-run-cargo-command "cargo doc") + (rustic-run-cargo-command "cargo doc --no-deps"))) + +;; TODO: buffer with cargo output should be in rustic-compilation-mode +;;;###autoload +(defun rustic-cargo-doc () + "Open the documentation for the current project in a browser. +The documentation is built if necessary." + (interactive) + (if (y-or-n-p "Open docs for dependencies as well?") + ;; open docs only works with synchronous process + (shell-command "cargo doc --open") + (shell-command "cargo doc --open --no-deps"))) + +;;; cargo edit + +(defun rustic-cargo-edit-installed-p () + "Check if cargo-edit is installed. If not, ask the user if he wants to install it." + (if (executable-find "cargo-add") t (rustic-cargo-install-crate-p "edit") nil)) + +;;;###autoload +(defun rustic-cargo-add (&optional arg) + "Add crate to Cargo.toml using 'cargo add'. +If running with prefix command `C-u', read whole command from minibuffer." + (interactive "P") + (when (rustic-cargo-edit-installed-p) + (let* ((command (if arg + (read-from-minibuffer "Cargo add command: " "cargo add ") + (concat "cargo add " (read-from-minibuffer "Crate: "))))) + (rustic-run-cargo-command command)))) + +;;;###autoload +(defun rustic-cargo-rm (&optional arg) + "Remove crate from Cargo.toml using 'cargo rm'. +If running with prefix command `C-u', read whole command from minibuffer." + (interactive "P") + (when (rustic-cargo-edit-installed-p) + (let* ((command (if arg + (read-from-minibuffer "Cargo rm command: " "cargo rm ") + (concat "cargo rm " (read-from-minibuffer "Crate: "))))) + (rustic-run-cargo-command command)))) + +;;;###autoload +(defun rustic-cargo-upgrade (&optional arg) + "Upgrade dependencies as specified in the local manifest file using 'cargo upgrade'. +If running with prefix command `C-u', read whole command from minibuffer." + (interactive "P") + (when (rustic-cargo-edit-installed-p) + (let* ((command (if arg + (read-from-minibuffer "Cargo upgrade command: " "cargo upgrade ") + (concat "cargo upgrade")))) + (rustic-run-cargo-command command)))) + +(provide 'rustic-cargo) +;;; rustic-cargo.el ends here diff --git a/emacs.d/elpa/rustic-20210609.1900/rustic-compile.el b/emacs.d/elpa/rustic-20210609.1900/rustic-compile.el new file mode 100644 index 0000000..0742a1f --- /dev/null +++ b/emacs.d/elpa/rustic-20210609.1900/rustic-compile.el @@ -0,0 +1,540 @@ +;;; rustic-compile.el --- Compile facilities -*-lexical-binding: t-*- + +;;; Commentary: + +;; Unlike compile.el, rustic makes use of a non dumb terminal in order to receive +;; all ANSI control sequences, which get translated by xterm-color. +;; This file also adds a derived compilation mode. Error matching regexes from +;; compile.el are removed. + +;;; Code: + +(require 'markdown-mode) +(require 'xterm-color) + +(require 'compile) + +(require 'rustic) + +(defvar rustic-format-trigger) +(defvar rustic-format-on-save) + +;;; Customization + +(defgroup rustic-compilation nil + "Rust Compilation." + :group 'rustic + :group 'processes) + +(defcustom rustic-compile-command (purecopy "cargo build") + "Default command for rust compilation." + :type 'string + :group 'rustic-compilation) + +(defcustom rustic-compile-display-method 'display-buffer + "Default function used for displaying compilation buffer." + :type 'function + :group 'rustic-compilation) + +(defcustom rustic-compile-backtrace "0" + "Set environment variable `RUST_BACKTRACE'." + :type '(choice (string :tag "0") + (string :tag "1") + (string :tag "full")) + :group 'rustic-compilation) + +(defcustom rustic-list-project-buffers-function + (if (fboundp 'projectile-project-buffers) + 'projectile-project-buffers + 'rustic-project-buffer-list) + "Function used to list buffers belonging to current project." + :type '(choice (const projectile-project-buffers) + (const rustic-project-buffer-list) + function) + :group 'rustic) + +;;; Faces + +(define-obsolete-face-alias 'rustic-message-face + 'rustic-message "1.2") +(define-obsolete-face-alias 'rustic-compilation-error-face + 'rustic-compilation-error "1.2") +(define-obsolete-face-alias 'rustic-compilation-warning-face + 'rustic-compilation-warning "1.2") +(define-obsolete-face-alias 'rustic-compilation-info-face + 'rustic-compilation-info "1.2") +(define-obsolete-face-alias 'rustic-compilation-line-face + 'rustic-compilation-line "1.2") +(define-obsolete-face-alias 'rustic-compilation-column-face + 'rustic-compilation-column "1.2") + +(defface rustic-message + '((t :inherit default)) + "Don't use `compilation-message-face', as ansi colors get messed up." + :group 'rustic-compilation) + +(defface rustic-compilation-error + '((t :inherit default)) + "Override `compilation-error-face' for rust compilation." + :group 'rustic-compilation) + +(defface rustic-compilation-warning + '((t :inherit default)) + "Override `compilation-warning-face' for rust compilation." + :group 'rustic-compilation) + +(defface rustic-compilation-info + '((t :inherit default)) + "Override `compilation-info-face' for rust compilation." + :group 'rustic-compilation) + +(defface rustic-compilation-line + '((t :inherit default)) + "Override `compilation-line-face' for rust compilation." + :group 'rustic-compilation) + +(defface rustic-compilation-column + '((t :inherit default)) + "Override `compilation-column-face' for rust compilation." + :group 'rustic-compilation) + +(defcustom rustic-ansi-faces ["black" + "red3" + "green3" + "yellow3" + "blue2" + "magenta3" + "cyan3" + "white"] + "Term ansi faces." + :type '(vector string string string string string string string string) + :group 'rustic-compilation) + +;;; Compilation-mode + +(defvar rustic-compilation-mode-map + (let ((map (make-sparse-keymap))) + (suppress-keymap map t) + (set-keymap-parent map compilation-mode-map) + (define-key map "p" 'rustic-popup) + (define-key map "g" 'rustic-recompile) + map) + "Keymap for rust compilation log buffers.") + +(defvar rustic-compilation-error + (let ((err "^error[^:]*:[^\n]*\n\s*-->\s") + (file "\\([^\n]+\\)") + (start-line "\\([0-9]+\\)") + (start-col "\\([0-9]+\\)")) + (let ((re (concat err file ":" start-line ":" start-col))) + (cons re '(1 2 3)))) + "Create hyperlink in compilation buffers for rust errors.") + +(defvar rustic-compilation-warning + (let ((warning "^warning:[^\n]*\n\s*-->\s") + (file "\\([^\n]+\\)") + (start-line "\\([0-9]+\\)") + (start-col "\\([0-9]+\\)")) + (let ((re (concat warning file ":" start-line ":" start-col))) + (cons re '(1 2 3 1)))) ;; 1 for warning + "Create hyperlink in compilation buffers for rust warnings.") + +(defvar rustic-compilation-info + (let ((file "\\([^\n]+\\)") + (start-line "\\([0-9]+\\)") + (start-col "\\([0-9]+\\)")) + (let ((re (concat "^ *::: " file ":" start-line ":" start-col))) + (cons re '(1 2 3 0)))) ;; 0 for info type + "Create hyperlink in compilation buffers for file paths preceded by ':::'.") + +(defvar rustic-compilation-panic + (let ((panic "thread '[^']+' panicked at '[^']+', ") + (file "\\([^\n]+\\)") + (start-line "\\([0-9]+\\)") + (start-col "\\([0-9]+\\)")) + (let ((re (concat panic file ":" start-line ":" start-col))) + (cons re '(1 2 3)))) + "Match thread panics.") + +(define-compilation-mode rustic-compilation-mode "rust-compilation" + "Rust compilation mode. + +Error matching regexes from compile.el are removed." + (setq-local compilation-message-face 'rustic-message) + (setq-local compilation-error-face 'rustic-compilation-error) + (setq-local compilation-warning-face 'rustic-compilation-warning) + (setq-local compilation-info-face 'rustic-compilation-info) + (setq-local compilation-column-face 'rustic-compilation-column) + (setq-local compilation-line-face 'rustic-compilation-line) + + (setq-local xterm-color-names-bright rustic-ansi-faces) + (setq-local xterm-color-names rustic-ansi-faces) + + (setq-local compilation-error-regexp-alist-alist nil) + (add-to-list 'compilation-error-regexp-alist-alist + (cons 'rustic-error rustic-compilation-error)) + (add-to-list 'compilation-error-regexp-alist-alist + (cons 'rustic-warning rustic-compilation-warning)) + (add-to-list 'compilation-error-regexp-alist-alist + (cons 'rustic-info rustic-compilation-info)) + (add-to-list 'compilation-error-regexp-alist-alist + (cons 'rustic-panic rustic-compilation-panic)) + + (setq-local compilation-error-regexp-alist nil) + (add-to-list 'compilation-error-regexp-alist 'rustic-error) + (add-to-list 'compilation-error-regexp-alist 'rustic-warning) + (add-to-list 'compilation-error-regexp-alist 'rustic-info) + (add-to-list 'compilation-error-regexp-alist 'rustic-panic) + + (add-hook 'compilation-filter-hook #'rustic-insert-errno-button nil t)) + +;;; Compilation Process + +(defvar rustic-compilation-process-name "rustic-compilation-process" + "Process name for rust compilation processes.") + +(defvar rustic-compilation-buffer-name "*rustic-compilation*" + "Buffer name for rust compilation process buffers.") + +(defun rustic-make-process (&rest args) + "Wrapper for `make-process'. + +Set environment variables for rust process." + (let ((coding-system-for-read 'binary) + (process-environment (nconc + (list + (format "TERM=%s" "ansi") + (format "RUST_BACKTRACE=%s" rustic-compile-backtrace)) + process-environment))) + (let ((process (apply + #'start-file-process (plist-get args :name) + (plist-get args :buffer) + (plist-get args :command)))) + (set-process-filter process (plist-get args :filter)) + (set-process-sentinel process (plist-get args :sentinel)) + (set-process-coding-system process 'utf-8-emacs-unix 'utf-8-emacs-unix) + process))) + +(defun rustic-compilation-setup-buffer (buf dir mode &optional no-mode-line) + "Prepare BUF for compilation process." + (let ((inhibit-read-only t)) + (with-current-buffer buf + (erase-buffer) + (setq default-directory dir) + (funcall mode) + (unless no-mode-line + (setq mode-line-process + '((:propertize ":%s" face compilation-mode-line-run) + compilation-mode-line-errors))) + (force-mode-line-update) + (if (or compilation-auto-jump-to-first-error + (eq compilation-scroll-output 'first-error)) + (set (make-local-variable 'compilation-auto-jump-to-next) t)) + (sit-for 0)))) + +(defvar rustic-before-compilation-hook nil) + +(defun rustic-compilation-start (command &optional args) + "Start a compilation process COMMAND with ARGS. +ARGS is a plist that affects how the process is run, +see `rustic-compilation' for details. First run +`rustic-before-compilation-hook' and if any of these +functions fails, then do not start compilation." + (when (run-hook-with-args-until-failure 'rustic-before-compilation-hook) + (rustic-compilation command args))) + +(defun rustic-compilation (command &optional args) + "Start a compilation process with COMMAND. + +ARGS is a plist that affects how the process is run. +- `:no-display' don't display buffer when starting compilation process +- `:buffer' name for process buffer +- `:process' name for compilation process +- `:mode' mode for process buffer +- `:directory' set `default-directory' +- `:sentinel' process sentinel" + (let ((buf (get-buffer-create + (or (plist-get args :buffer) rustic-compilation-buffer-name))) + (process (or (plist-get args :process) rustic-compilation-process-name)) + (mode (or (plist-get args :mode) 'rustic-compilation-mode)) + (directory (or (plist-get args :directory) (rustic-buffer-workspace))) + (sentinel (or (plist-get args :sentinel) #'compilation-sentinel))) + (rustic-compilation-setup-buffer buf directory mode) + (setq next-error-last-buffer buf) + (unless (plist-get args :no-display) + (funcall rustic-compile-display-method buf)) + (with-current-buffer buf + (rustic-make-process :name process + :buffer buf + :command command + :filter #'rustic-compilation-filter + :sentinel sentinel)))) + +(defun rustic-compilation-filter (proc string) + "Insert the text emitted by PROC. +Translate STRING with `xterm-color-filter'." + (let ((buffer (process-buffer proc)) + buffer-empty-p) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (when (= (buffer-size) 0) + (setq buffer-empty-p t)) + (let ((inhibit-read-only t) + ;; `save-excursion' doesn't use the right insertion-type for us. + (pos (copy-marker (point) t)) + ;; `save-restriction' doesn't use the right insertion type either: + ;; If we are inserting at the end of the accessible part of the + ;; buffer, keep the inserted text visible. + (min (point-min-marker)) + (max (copy-marker (point-max) t)) + (compilation-filter-start (marker-position (process-mark proc))) + (xterm-string (xterm-color-filter string))) + (unwind-protect + (progn + (widen) + (goto-char compilation-filter-start) + ;; We used to use `insert-before-markers', so that windows with + ;; point at `process-mark' scroll along with the output, but we + ;; now use window-point-insertion-type instead. + + (insert xterm-string) + (compilation--ensure-parse (point-max)) + + (unless comint-inhibit-carriage-motion + (comint-carriage-motion (process-mark proc) (point))) + (set-marker (process-mark proc) (point)) + (run-hooks 'compilation-filter-hook)) + (goto-char pos) + (narrow-to-region min max) + (set-marker pos nil) + (set-marker min nil) + (set-marker max nil)))) + ;; Issue #101: set window point to `point-min' when `compilation-scroll-output' is nil + (when (and (not compilation-scroll-output) buffer-empty-p) + (let ((win (get-buffer-window buffer))) + (set-window-start win (point-min)) + (set-window-point win (point-min))))))) + +(defun rustic-compilation-process-live (&optional nosave) + "Ask to kill live rustic process if any and call `rustic-save-some-buffers'. +If optional NOSAVE is non-nil, then do not do the latter. +Return non-nil if there was a live process." + (let ((procs (mapcan (lambda (proc) + (and proc + (let ((proc (get-process proc))) + (and (process-live-p proc) + (list proc))))) + (list rustic-compilation-process-name + (bound-and-true-p rustic-format-process-name) + (bound-and-true-p rustic-clippy-process-name) + (bound-and-true-p rustic-test-process-name))))) + (when (> (length procs) 1) + (error "BUG: Multiple live rustic processes: %s" procs)) + (when procs + (rustic-process-kill-p (car procs))) + (unless nosave + (rustic-save-some-buffers)) + procs)) + +(defun rustic-process-kill-p (proc &optional no-error) + "Don't allow two rust processes at once. + +If NO-ERROR is t, don't throw error if user chooses not to kill running process." + (if (yes-or-no-p + (format "`%s' is running; kill it? " proc)) + (condition-case () + (progn + (interrupt-process proc) + (sit-for 0.5) + (delete-process proc)) + (error nil)) + (unless no-error + (error "Cannot have two rust processes at once")))) + +(defun rustic-save-some-buffers () + "Unlike `save-some-buffers', only consider project related files. + +The variable `buffer-save-without-query' can be used for customization and +buffers are formatted after saving if turned on by `rustic-format-trigger'." + (let ((buffers (cl-remove-if-not + #'buffer-file-name + (if (fboundp rustic-list-project-buffers-function) + (funcall rustic-list-project-buffers-function) + (buffer-list)))) + (b (get-buffer (bound-and-true-p rustic-format-buffer-name)))) + (when (buffer-live-p b) + (kill-buffer b)) + (dolist (buffer buffers) + (when (and (buffer-live-p buffer) + (buffer-modified-p buffer)) + (with-current-buffer buffer + (let ((saved-p nil)) + ;; also set rustic-format-on-save for backwards compatibility + (let ((rustic-format-trigger nil) + (rustic-format-on-save nil)) + (setq saved-p + (if buffer-save-without-query + (progn (save-buffer) t) + (if (yes-or-no-p (format "Save file %s ? " + (buffer-file-name buffer))) + (progn (save-buffer) t) + nil)))) + (when (and saved-p + (eq major-mode 'rustic-mode) + (fboundp 'rustic-maybe-format-after-save)) + (rustic-maybe-format-after-save buffer)))))))) + +(defun rustic-compile-goto-error-hook (orig-fun &rest args) + "Provide possibility use `compile-goto-error' on line numbers in compilation buffers. +This hook checks if there's a line number at the beginning of the +current line in an error section." + (-if-let* ((rustic-p (eq major-mode 'rustic-compilation-mode)) + (line-contents (buffer-substring-no-properties + (line-beginning-position) + (line-end-position))) + (line-number-p (string-match "^[0-9]+\s+\|" line-contents)) + (line-number (car (split-string line-contents)))) + (save-excursion + ;; find compilation message in error + (while (not (or (get-text-property (point) 'compilation-message) + (bobp))) + (forward-line -1)) + ;; get file of text property + (let* ((msg (get-text-property (point) 'compilation-message)) + (loc (compilation--message->loc msg)) + (file (caar (compilation--loc->file-struct loc)))) + ;; open file of error and goto line number that we parsed from the line we are on + (with-current-buffer (find-file-other-window file) + (save-restriction + (widen) + (goto-char (point-min)) + (forward-line (1- (string-to-number line-number))))))) + (apply orig-fun args))) + +(advice-add 'compile-goto-error :around #'rustic-compile-goto-error-hook) + +(defun rustic-compile-send-input () + "Read string from minibuffer and send it to the rust process of the current +buffer." + (interactive) + (let ((input (read-from-minibuffer "Send input to rust process: ")) + (proc (get-buffer-process (current-buffer))) + (inhibit-read-only t)) + (process-send-string proc (concat input "\n")))) + + +;;; Rustc + +(defface rustic-errno-face + '((t :foreground "red3")) + "Error number face" + :group 'rustic-compilation) + +(defun rustic-insert-errno-button () + "Insert buttons in `rustic-compilation-mode'." + (save-excursion + (let ((start compilation-filter-start) + (end (point))) + (goto-char start) + (save-match-data + (while (re-search-forward (concat "error\\[E[0-9]+\\]") end t) + (make-button (match-beginning 0) + (match-end 0) + :type 'rustc-errno)))))) + +(defun rustic-explain-error (button) + "Open buffer with explanation for error at point." + (let* ((button-string (button-label button)) + (errno (progn (string-match "E[0-9]+" button-string) + (match-string 0 button-string))) + (buf (get-buffer-create "*rust errno*")) + (inhibit-read-only t)) + (with-current-buffer buf + (erase-buffer) + (insert (shell-command-to-string + (concat "rustc --explain=" errno))) + (markdown-view-mode) + (setq + header-line-format + (concat (propertize " " 'display + `(space :align-to (- right-fringe ,(1+ (length errno))))) + (propertize errno 'face 'rustic-errno-face))) + (setq-local markdown-fontify-code-blocks-natively t) + (setq-local markdown-fontify-code-block-default-mode 'rustic-mode) + (markdown-toggle-markup-hiding 1) + (goto-char (point-min))) + (pop-to-buffer buf))) + +(define-button-type 'rustc-errno + 'action #'rustic-explain-error + 'follow-link t + 'face 'rustic-errno-face + 'help-echo "mouse-1, RET: Explain errno") + +;;; Interactive + +;;;###autoload +(defun rustic-compile (&optional arg) + "Compile rust project. + +If `compilation-read-command' is non-nil or if called with prefix +argument ARG then read the command in the minibuffer. Otherwise +use `rustic-compile-command'. + +In either store the used command in `compilation-arguments'." + (interactive "P") + (setq compilation-arguments + (if (or compilation-read-command arg) + (read-from-minibuffer "Compile command: " + (or compilation-arguments + rustic-compile-command)) + rustic-compile-command)) + (setq compilation-directory (rustic-buffer-workspace)) + (rustic-compilation-process-live) + (rustic-compilation-start (split-string compilation-arguments) + (list :directory compilation-directory))) + +;;;###autoload +(defun rustic-recompile () + "Re-compile the program using `compilation-arguments'." + (interactive) + (let* ((command (or compilation-arguments rustic-compile-command)) + (dir compilation-directory)) + (rustic-compilation-process-live) + (rustic-compilation (split-string command) (list :directory dir)))) + +;;; Spinner + +(require 'spinner) + +(defcustom rustic-display-spinner t + "Display spinner." + :type 'boolean + :group 'rustic) + +(defcustom rustic-spinner-type 'horizontal-moving + "Holds the type of spinner to be used in the mode-line. +Takes a value accepted by `spinner-start'." + :type `(choice (choice :tag "Choose a spinner by name" + ,@(mapcar (lambda (c) (list 'const (car c))) + spinner-types)) + (const :tag "A random spinner" random) + (repeat :tag "A list of symbols from `spinner-types' to randomly choose from" + (choice :tag "Choose a spinner by name" + ,@(mapcar (lambda (c) (list 'const (car c))) + spinner-types))) + (vector :tag "A user defined vector" + (repeat :inline t string)))) + +(defmacro rustic-with-spinner (spinner val mode-line &rest body) + (declare (indent defun)) + `(when rustic-display-spinner + (when (spinner-p ,spinner) + (spinner-stop ,spinner)) + (setq ,spinner ,val) + (setq mode-line-process ,mode-line) + ,@body)) + +;;; _ +(provide 'rustic-compile) +;;; rustic-compile.el ends here diff --git a/emacs.d/elpa/rustic-20210609.1900/rustic-doc.el b/emacs.d/elpa/rustic-20210609.1900/rustic-doc.el new file mode 100644 index 0000000..b3743bd --- /dev/null +++ b/emacs.d/elpa/rustic-20210609.1900/rustic-doc.el @@ -0,0 +1,385 @@ +;;; rustic-doc.el --- Browse rust documentation as .org files -*- lexical-binding: t -*- + +;; Copyright (c) 2020 Sam Hedin + +;; Author: Sam Hedin <sam.hedin@gmail.com> +;; Jonas Møller <jonas.moeller2@protonmail.com> + +;;; Commentary: + +;; This package lets you convert rustic-doc html-files to org mode +;; files, and lets you browse them with `rustic-doc-search'. + +;; Run `M-x rustic-doc-setup' to download the required files and +;; convert the rust standard library. + +;; Run `M-x rustic-doc-convert-current-package' to generate and +;; convert docs for the package you are currently visiting. + +;;; Code: + +(require 'url) +(require 'lsp-mode) +(require 'f) + +(eval-and-compile + (if (< emacs-major-version 27) + (defun rustic-doc--xdg-data-home () + (or (getenv "XDG_DATA_HOME") + (concat (file-name-as-directory (getenv "HOME")) + ".local/share"))) + (require 'xdg) + (fset 'rustic-doc--xdg-data-home 'xdg-data-home))) + +(defvar rustic-doc-lua-filter (concat (file-name-as-directory (getenv "HOME")) + ".local/bin/rustic-doc-filter.lua") + "Save location for the rustic-doc lua filter.") + +(defvar rustic-doc-convert-prog (concat (file-name-as-directory (getenv "HOME")) + ".local/bin/rustic-doc-convert.sh") + "Save location for the rustic-doc conversion script.") + +(defvar rustic-doc-source-repo + "https://raw.githubusercontent.com/brotzeit/rustic/master/rustic-doc/") + +(defvar rustic-doc-current-project nil + "Location to search for documentation. +All projects and std by default, otherwise last open project and std.") + +(defvar rustic-doc-save-loc (concat (rustic-doc--xdg-data-home) + "/emacs/rustic-doc")) + +(defvar rustic-doc-resources + `((,rustic-doc-convert-prog + (:exec) + ,(concat rustic-doc-source-repo "convert.sh")) + (,rustic-doc-lua-filter + () + ,(concat rustic-doc-source-repo "filter.lua")))) + +(defun rustic-doc-default-rg-search-command () + "The default search command when using helm-ag. +Needs to be a function because of its reliance on +`rustic-doc-current-project'" + (concat "rg --smart-case --no-heading --color=never --line-number " + (if rustic-doc-current-project " -L" ""))) + +(defcustom rustic-doc-rg-search-command 'rustic-doc-default-rg-search-command + "The default command string to pass helm-ag when searching." + :type 'function + :group 'rustic-doc) + +(defvar helm-ag-base-command) +(defvar helm-ag-success-exit-status) +(declare-function helm-ag "ext:helm-ag") + +(defun rustic-doc-default-search-function (search-dir search-term) + "Default search functionality. +Uses helm-ag and ripgrep if possible, grep otherwise. +Search for SEARCH-TERM inside SEARCH-DIR" + (cond + ((and (require 'helm-ag nil t) (executable-find "rg")) + (let* ((helm-ag-base-command (funcall rustic-doc-rg-search-command)) + (helm-ag-success-exit-status '(0 2))) + (condition-case nil + (helm-ag search-dir search-term) + ;; If the search didn't turn anything up we re-run the search + ;; in the top level searchdir. + (error (helm-ag rustic-doc-save-loc search-term))))) + ((executable-find "rg") + (grep (format "%s '%s' %s" + (rustic-doc-default-rg-search-command) + search-term + search-dir))) + (t + (grep (format "grep -RPIni '%s' %s" search-term search-dir))))) + + +(defcustom rustic-doc-search-function 'rustic-doc-default-search-function + "Function to use for searching documentation. +The function should take search-dir and search-term as arguments." + :type 'function + :group 'rustic-doc) + +(defun rustic-doc--install-resources () + "Install or update the rustic-doc resources." + (dolist (resource rustic-doc-resources) + (pcase resource + (`(,dst ,opts ,src) + (condition-case nil + (progn + (unless (f-exists? (f-dirname dst)) + (f-mkdir (f-dirname dst))) + (url-copy-file src dst t) + (when (memq :exec opts) + (call-process (executable-find "chmod") + nil + nil + nil + "+x" + dst))) + (error (progn + (if (file-exists-p dst) + (message (format "Could not update %s, using existing one" + dst)) + (error (format "Could not retrieve %s" dst))))))) + (x (error "Invalid resource spec: %s" x))))) + +;;;###autoload +(defun rustic-doc-dumb-search (search-term) + "Search all projects and std for SEARCH-TERM. +Use this when `rustic-doc-search' does not find what you're looking for. +Add `universal-argument' to only search level 1 headers. +See `rustic-doc-search' for more information." + (interactive (let ((short-name (alist-get 'short-name + (rustic-doc--thing-at-point)))) + (list (read-string (format "search term, default %s: " short-name) + nil + nil + short-name)))) + (rustic-doc-search search-term t)) + + +;;;###autoload +(defun rustic-doc-search (search-term &optional root) + "Search the rust documentation for SEARCH-TERM. +Only searches in headers (structs, functions, traits, enums, etc) +to limit the number of results. +To limit search results to only level 1 headers, add `universal-argument' +Level 1 headers are things like struct or enum names. +if ROOT is non-nil the search is performed from the root dir. +This function tries to be smart and limits the search results +as much as possible. If it ends up being so smart that +it doesn't manage to find what you're looking for, try `rustic-doc-dumb-search'." + (interactive (let ((short-name (alist-get 'short-name + (rustic-doc--thing-at-point)))) + (list (read-string (format "search term, default %s: " short-name) + nil + nil + short-name)))) + + (rustic-doc--update-current-project) + (let* ((thing-at-point (rustic-doc--thing-at-point)) + (short-name (alist-get 'short-name thing-at-point)) + ;; If the user did not accept the default search suggestion, + ;; we should not search in that suggestion's directory. + (search-dir + (cond + (root rustic-doc-save-loc) + ((string-equal short-name search-term) + (alist-get 'search-dir thing-at-point)) + (t (rustic-doc--project-doc-dest)))) + ;; If the prefix arg is provided, we only search for level 1 + ;; headers by making sure that there is only one * at the + ;; beginning of the line. + (regex (if current-prefix-arg + (progn + (setq current-prefix-arg nil) + "^\\*") + "^\\*+")) + ;; This seq-reduce turns `enum option' into (kind of) + ;; `enum.*option', which lets there be chars between the + ;; searched words + (regexed-search-term + (concat regex + ;; Regex explanation + ;; `-' => Do not match if a return type. A search + ;; for Option should not show is_some -> Option + ;; `(' => Do not match if it's an argument name. + ;; `<' => Do not match if it's a generic type arg + (seq-reduce (lambda (acc s) + (concat acc "[^-\*(<]*" s)) + (split-string search-term " ") + "")))) + (unless (file-directory-p rustic-doc-save-loc) + (rustic-doc-setup) + (message "Running first time setup. Please re-run your search\ + once conversion has completed.") + (sleep-for 3)) + ;; If the user has not run `rustic-doc-convert-current-package' in + ;; the current project, we create a default directory that only + ;; contains a symlink to std. + (unless (file-directory-p (rustic-doc--project-doc-dest)) + (rustic-doc-create-project-dir)) + (funcall rustic-doc-search-function search-dir regexed-search-term))) + +(defun rustic-doc--update-current-project () + "Update `rustic-doc-current-project' if editing a rust file, otherwise leave it." + (when (and lsp-mode + (derived-mode-p 'rust-mode 'rustic-mode)) + (setq rustic-doc-current-project (lsp-workspace-root)))) + +(defun rustic-doc--deepest-dir (path) + "Find the deepest existing and non-empty arg-directory parent of PATH. +We can sometimes infer the filepath from the crate name. +E.g the enum std::option::Option is in the folder std/option. +Some filepaths can not be inferred properly, seemingly because of +URL `https://github.com/rust-lang/rust/issues/21934'. +In these cases, the deepest dir will be the current project dir." + (if (and (file-exists-p path) + (file-directory-p path) + (not (f-empty-p path))) + path + (rustic-doc--deepest-dir (f-slash (f-dirname path))))) + +(defun rustic-doc--project-doc-dest () + "The location of the documentation for the current or last seen project. +If the user has not visited a project, returns the main doc directory." + (if rustic-doc-current-project + (f-join rustic-doc-save-loc + (f-filename rustic-doc-current-project)) + rustic-doc-save-loc)) + +(defun rustic-doc-create-project-dir () + "Create a rustic-doc arg-directory for the current project. Link with std." + (let* ((link-tgt (concat (file-name-as-directory (rustic-doc--xdg-data-home)) + "emacs/rustic-doc/std")) + (link-name (concat (rustic-doc--project-doc-dest) + "/std")) + (current-doc-dest (rustic-doc--project-doc-dest))) + (if current-doc-dest + (progn + (make-directory (rustic-doc--project-doc-dest) + t) + (make-symbolic-link link-tgt link-name t)) + (message "Couldn't create project doc directory.")))) + +;;;###autoload +(defun rustic-doc-convert-current-package () + "Convert the documentation for a project and its dependencies." + (interactive) + (unless (file-directory-p rustic-doc-save-loc) + (rustic-doc-setup) + (message "Running first time setup.") + (sleep-for 3)) + (if rustic-doc-current-project + (progn + (message "Converting documentation for %s " + rustic-doc-current-project) + (if (/= 0 (call-process "cargo" nil "*cargo-makedocs*" nil "makedocs")) + (message "\ +cargo makedocs could not generate docs for the current package. \ +See buffer *cargo-makedocs* for more info") + (let* ((docs-src + (concat (file-name-as-directory rustic-doc-current-project) + "target/doc")) + ;; FIXME: Many projects could share the same docs. + ;; *However* that would have to be versioned, so + ;; we'll have to figure out a way to coerce `<crate>-<version>` + ;; strings out of cargo, or just parse the Cargo.toml file, but + ;; then we'd have to review different parsing solutions. + (finish-func (lambda (_p) + (message "Finished converting docs for %s" + rustic-doc-current-project)))) + (rustic-doc-create-project-dir) + (rustic-doc--start-process "rustic-doc-convert" + rustic-doc-convert-prog + finish-func + docs-src + (rustic-doc--project-doc-dest))))) + (message "Could not find project to convert. Visit a rust project first! \ +\(Or activate rustic-doc-mode if you are in one)"))) + +(defun rustic-doc-install-deps () + "Install dependencies with Cargo." + (if (not (executable-find "cargo")) + (message "You need to have cargo installed to use rustic-doc") + (let ((missing-rg (not (executable-find "rg"))) + (missing-fd (not (executable-find "fd"))) + (missing-makedocs (not (executable-find "cargo-makedocs")))) + (when (and (or missing-fd missing-makedocs missing-rg) + (y-or-n-p "Missing some dependencies for rustic doc, install them? ")) + (when missing-fd + (rustic-doc--start-process "install-fd" "cargo" nil "install" "fd-find")) + (when missing-rg + (rustic-doc--start-process "install-rg" "cargo" nil "install" "ripgrep")) + (when missing-makedocs + (rustic-doc--start-process "install-makedocs" "cargo" nil + "install" "cargo-makedocs")))))) + +;;;###autoload +(defun rustic-doc-setup () + "Setup or update rustic-doc filter and convert script. Convert std." + (interactive) + (rustic-doc--install-resources) + (rustic-doc-install-deps) + (message "Setup is converting the standard library") + (delete-directory (concat rustic-doc-save-loc "/std") + t) + (rustic-doc--start-process "rustic-doc-std-conversion" + rustic-doc-convert-prog + (lambda (_p) + (message "Finished converting docs for std")) + "std")) + +(defun rustic-doc--start-process (name program finish-func &rest program-args) + (let* ((buf (generate-new-buffer (concat "*" name "*"))) + (proc (let ((process-connection-type nil)) + (apply #'start-process name buf program program-args)))) + (set-process-sentinel + proc (lambda (proc event) + (let ((buf (process-buffer proc))) + (if (string-match-p (regexp-quote "abnormally") event) + (message "Could not finish process: %s. \ +See the *Messages* buffer or %s for more info." event (concat "*" name "*")) + (when finish-func + (funcall finish-func proc)) + (when (buffer-live-p buf) + (kill-buffer buf)))))) + proc)) + +(defun rustic-doc--thing-at-point () + "Return info about `thing-at-point'. If `thing-at-point' is nil, return defaults." + (if-let ((active lsp-mode) + (lsp-content (-some->> (lsp--text-document-position-params) + (lsp--make-request "textDocument/hover") + (lsp--send-request) + (lsp:hover-contents))) + ;; `short-name' is the unqalified of a struct, function + ;; etc, like `Option' + (short-name (thing-at-point 'symbol t)) + ;; If symbol at point is a primitive, the `value' key is + ;; different than in most cases. If it is a primitive, we + ;; concat the name with primitive for searching. + (lsp-info (or (nth 1 + (split-string (gethash "value" lsp-content))) + (setq short-name + (concat "primitive " + (gethash "value" lsp-content))))) + ;; If short-name was `Option', long-name would be `std::option::Option' + (long-name (concat (cond + ((string-prefix-p "core" lsp-info) + (concat "std" + (seq-drop lsp-info 4))) + ((string-prefix-p "alloc" lsp-info) + (concat "std" + (seq-drop lsp-info 5))) + (t lsp-info)) + "::" + short-name)) + (search-dir (rustic-doc--deepest-dir + (concat (rustic-doc--project-doc-dest) + "/" + (seq-reduce (lambda (path p) + (concat path "/" p)) + (split-string long-name "::") + ""))))) + `((search-dir . ,search-dir) + (short-name . ,short-name)) + `((search-dir . ,(rustic-doc--project-doc-dest)) + (short-name . ,nil)))) + +;;;###autoload +(define-minor-mode rustic-doc-mode + "Convert rust html docs to .org, and browse the converted docs." + :lighter " browse rust documentation" + :keymap (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-#") 'rustic-doc-search) + map) + (dolist (mode '(rust-mode-hook rustic-mode-hook org-mode-hook)) + (add-hook mode 'rustic-doc-mode)) + (rustic-doc--update-current-project)) + +(provide 'rustic-doc) + +;;; rustic-doc.el ends here diff --git a/emacs.d/elpa/rustic-20210609.1900/rustic-flycheck.el b/emacs.d/elpa/rustic-20210609.1900/rustic-flycheck.el new file mode 100644 index 0000000..ffc5ffc --- /dev/null +++ b/emacs.d/elpa/rustic-20210609.1900/rustic-flycheck.el @@ -0,0 +1,201 @@ +;;; rustic-flycheck.el --- Flycheck support -*-lexical-binding: t-*- + +;;; Code: + +(eval-when-compile (require 'let-alist)) + +(require 'flycheck) +(require 'json) + +(require 'rustic) + +(defcustom rustic-flycheck-clippy-params "--message-format=json -Zunstable-options" + "Parameters for the flycheck clippy checker `rustic-clippy'." + :type 'string + :group 'rustic-flycheck) + +(defun rustic-flycheck-dirs-list (start end) + "Return a list of directories from START (inclusive) to END (exclusive). +E.g., if START is '/a/b/c/d' and END is '/a', return the list +'(/a/b/c/d /a/b/c /a/b) in this order. +START and END are strings representing file paths. END should be +above START in the file hierarchy; if not, the list stops at the +root of the file hierarchy." + (let ((dirlist) + (dir (expand-file-name start)) + (end (expand-file-name end))) + (while (not (or (equal dir (car dirlist)) ; avoid infinite loop + (file-equal-p dir end))) + (push dir dirlist) + (setq dir (directory-file-name (file-name-directory dir)))) + (nreverse dirlist))) + +(defun rustic-flycheck-get-cargo-targets (manifest) + "Return the list of available Cargo targets for the given project. +MANIFEST is the path to the Cargo.toml file of the project. +Calls `cargo metadata --no-deps --manifest-path MANIFEST +--format-version 1', parses and collects the targets for the +current workspace, and returns them in a list, or nil if no +targets could be found." + (let ((process-output-as-json + (lambda (program &rest args) + (with-temp-buffer + (let ((code-or-signal (apply 'process-file program nil '(t nil) nil args))) + (unless (equal code-or-signal 0) + ;; Prevent from displaying "JSON readtable error". + (let* ((args (combine-and-quote-strings (cons program args))) + (error-message (if (stringp code-or-signal) + (format "%s terminated by %s." args code-or-signal) + (format "%s exited with %s." args code-or-signal)))) + (user-error error-message))) + (goto-char (point-min)) + (let ((json-array-type 'list) + (json-object-type 'alist)) + (json-read)))))) + (cargo (funcall flycheck-executable-find "cargo"))) + (unless cargo + (user-error "flycheck-rust cannot find `cargo'. Please \ +make sure that cargo is installed and on your PATH. See \ +http://www.flycheck.org/en/latest/user/troubleshooting.html for \ +more information on setting your PATH with Emacs.")) + ;; metadata contains a list of packages, and each package has a list of + ;; targets. We concatenate all targets, regardless of the package. + (-when-let (packages (let-alist + (funcall process-output-as-json + cargo "metadata" + "--no-deps" + "--manifest-path" manifest + "--format-version" "1") + .packages)) + (seq-map (lambda (pkg) + (let-alist pkg .targets)) + packages)))) + +(defun rustic-flycheck-find-cargo-target (file-name) + "Return the Cargo build target associated with FILE-NAME. + +FILE-NAME is the path of the file that is matched against the +`src_path' value in the list of `targets' returned by `cargo +read-manifest'. + +Return an alist ((KIND . k) (NAME . n) (REQUIRED-FEATURES . rf)) +where KIND is the target kind (lib, bin, test, example or bench), +NAME the target name (usually, the crate name), and REQUIRED-FEATURES is the +optional list of features required to build the selected target. If FILE-NAME +exactly matches a target `src-path', this target is returned. Otherwise, return +the closest matching target, or nil if no targets could be found. + +See http://doc.crates.io/manifest.html#the-project-layout for a +description of the conventional Cargo project layout." + (-when-let* ((workspace (rustic-buffer-workspace t)) + (manifest (file-local-name (concat workspace "Cargo.toml"))) + (packages (rustic-flycheck-get-cargo-targets manifest)) + (targets (-flatten-n 1 packages))) + (let ((target + (or + ;; If there is a target that matches the file-name exactly, pick + ;; that one + (seq-find (lambda (target) + (let-alist target (string= file-name .src_path))) + targets) + ;; Otherwise find the closest matching target by walking up the tree + ;; from FILE-NAME and looking for targets in each directory. E.g., + ;; the file 'tests/common/a.rs' will look for a target in + ;; 'tests/common', then in 'tests/', etc. + (car (seq-find + (lambda (pair) + (-let [((&alist 'src_path target-path) . dir) pair] + (file-equal-p dir (file-name-directory target-path)))) + ;; build a list of (target . dir) candidates + (-table-flat + 'cons targets + (rustic-flycheck-dirs-list file-name workspace)))) + ;; If all else fails, just pick the first target + (car targets)))) + ;; If target is 'custom-build', we pick another target from the same package (see GH-62) + (when (string= "custom-build" (let-alist target (car .kind))) + (setq target (->> packages + ;; find the same package as current build-script buffer + (--find (--any? (equal target it) it)) + (--find (not (equal target it)))))) + (when target + (let-alist target + (seq-filter (lambda (kv) (cdr kv)) + (list (cons 'kind (rustic-flycheck-normalize-target-kind .kind)) + (cons 'name .name) + (cons 'required-features .required-features)))))))) + +(defun rustic-flycheck-normalize-target-kind (kinds) + "Return the normalized target name from KIND. +KIND is a list of target name as returned by `cargo metadata', +which do not necessarily correspond to to target names that can +be passed as argument to `cargo rustc'. +The normalization returns a valid cargo target based on KINDS." + ;; Assumption: we only care about the first kind name. Multiple kinds only + ;; seem to happen for library crate types, and those all maps to the same + ;; `lib' target. + (pcase (car kinds) + (`"dylib" "lib") + (`"rlib" "lib") + (`"staticlib" "lib") + (`"cdylib" "lib") + (`"proc-macro" "lib") + (_ (car kinds)))) + +;;;###autoload +(defun rustic-flycheck-setup () + "Setup Rust in Flycheck. + +If the current file is part of a Cargo project, configure +Flycheck according to the Cargo project layout." + (interactive) + ;; We should avoid raising any error in this function, as in combination + ;; with `global-flycheck-mode' it will render Emacs unusable (see + ;; https://github.com/flycheck/flycheck-rust/issues/40#issuecomment-253760883). + (with-demoted-errors "Error in rustic-flycheck-setup: %S" + (-when-let* ((file-name (buffer-file-name)) + (target (rustic-flycheck-find-cargo-target file-name))) + (let-alist target + (setq-local flycheck-rust-features .required-features) + (setq-local flycheck-rust-crate-type .kind) + (setq-local flycheck-rust-binary-name .name))))) + +(flycheck-define-checker rustic-clippy + "A Rust syntax checker using clippy. + +See URL `https://github.com/rust-lang-nursery/rust-clippy'." + :command ("cargo" "clippy" (eval (split-string rustic-flycheck-clippy-params))) + :error-parser flycheck-parse-cargo-rustc + :error-filter flycheck-rust-error-filter + :error-explainer flycheck-rust-error-explainer + :modes rustic-mode + :predicate flycheck-buffer-saved-p + :enabled (lambda () + (and (flycheck-rust-cargo-has-command-p "clippy") + (flycheck-rust-manifest-directory))) + :working-directory (lambda (_) (flycheck-rust-manifest-directory)) + :verify + (lambda (_) + (and buffer-file-name + (let ((has-toml (flycheck-rust-manifest-directory)) + (has-clippy (flycheck-rust-cargo-has-command-p "clippy"))) + (list + (flycheck-verification-result-new + :label "Clippy" + :message (if has-clippy "Found" + "Cannot find the `cargo clippy' command") + :face (if has-clippy 'success '(bold warning))) + (flycheck-verification-result-new + :label "Cargo.toml" + :message (if has-toml "Found" "Missing") + :face (if has-toml 'success '(bold warning)))))))) + +(add-hook 'rustic-mode-hook 'flycheck-mode) +(add-hook 'flycheck-mode-hook #'rustic-flycheck-setup) + +;; turn off flymake +(add-hook 'rustic-mode-hook 'flymake-mode-off) + +;;; _ +(provide 'rustic-flycheck) +;;; rustic-flycheck.el ends here diff --git a/emacs.d/elpa/rustic-20210609.1900/rustic-interaction.el b/emacs.d/elpa/rustic-20210609.1900/rustic-interaction.el new file mode 100644 index 0000000..b0819de --- /dev/null +++ b/emacs.d/elpa/rustic-20210609.1900/rustic-interaction.el @@ -0,0 +1,425 @@ +;;; rustic-interaction.el --- Common interactive functions -*-lexical-binding: t-*- + +;;; Code: + +(require 'newcomment) + +(require 'rustic) + +;;; Indent Line + +(defun rustic-rewind-to-beginning-of-current-level-expr () + (let ((current-level (rustic-paren-level))) + (back-to-indentation) + (when (looking-at "->") + (rustic-rewind-irrelevant) + (back-to-indentation)) + (while (> (rustic-paren-level) current-level) + (backward-up-list) + (back-to-indentation)) + ;; When we're in the where clause, skip over it. First find out the start + ;; of the function and its paren level. + (let ((function-start nil) (function-level nil)) + (save-excursion + (rustic-beginning-of-defun) + (back-to-indentation) + ;; Avoid using multiple-value-bind + (setq function-start (point) + function-level (rustic-paren-level))) + ;; On a where clause + (when (or (rustic-looking-at-where) + ;; or in one of the following lines, e.g. + ;; where A: Eq + ;; B: Hash <- on this line + (and (save-excursion + (rustic-rewind-to-where function-start)) + (= current-level function-level))) + (goto-char function-start))))) + +(defun rustic-align-to-expr-after-brace () + (save-excursion + (forward-char) + ;; We don't want to indent out to the open bracket if the + ;; open bracket ends the line + (when (not (looking-at "[[:blank:]]*\\(?://.*\\)?$")) + (when (looking-at "[[:space:]]") + (forward-word 1) + (backward-word 1)) + (current-column)))) + +(defun rustic-align-to-method-chain () + (save-excursion + ;; for method-chain alignment to apply, we must be looking at + ;; another method call or field access or something like + ;; that. This avoids rather "eager" jumps in situations like: + ;; + ;; { + ;; something.foo() + ;; <indent> + ;; + ;; Without this check, we would wind up with the cursor under the + ;; `.`. In an older version, I had the inverse of the current + ;; check, where we checked for situations that should NOT indent, + ;; vs checking for the one situation where we SHOULD. It should be + ;; clear that this is more robust, but also I find it mildly less + ;; annoying to have to press tab again to align to a method chain + ;; than to have an over-eager indent in all other cases which must + ;; be undone via tab. + + (when (looking-at (concat "\s*\." rustic-re-ident)) + (forward-line -1) + (end-of-line) + ;; Keep going up (looking for a line that could contain a method chain) + ;; while we're in a comment or on a blank line. Stop when the paren + ;; level changes. + (let ((level (rustic-paren-level))) + (while (and (or (rustic-in-str-or-cmnt) + ;; Only whitespace (or nothing) from the beginning to + ;; the end of the line. + (looking-back "^\s*" (point-at-bol))) + (= (rustic-paren-level) level)) + (forward-line -1) + (end-of-line))) + + (let + ;; skip-dot-identifier is used to position the point at the + ;; `.` when looking at something like + ;; + ;; foo.bar + ;; ^ ^ + ;; | | + ;; | position of point + ;; returned offset + ;; + ((skip-dot-identifier + (lambda () + (when (and (rustic-looking-back-ident) + (save-excursion + (forward-thing 'symbol -1) + (= ?. (char-before)))) + (forward-thing 'symbol -1) + (backward-char) + (- (current-column) rustic-indent-offset))))) + (cond + ;; foo.bar(...) + ((rustic-looking-back-str ")") + (backward-list 1) + (funcall skip-dot-identifier)) + + ;; foo.bar + (t (funcall skip-dot-identifier))))))) + +;;;###autoload +(defun rustic-indent-line () + (interactive) + (let ((indent + (save-excursion + (back-to-indentation) + ;; Point is now at beginning of current line + (let* ((level (rustic-paren-level)) + (baseline + ;; Our "baseline" is one level out from the indentation of the expression + ;; containing the innermost enclosing opening bracket. That + ;; way if we are within a block that has a different + ;; indentation than this mode would give it, we still indent + ;; the inside of it correctly relative to the outside. + (if (= 0 level) + 0 + (or + (when rustic-indent-method-chain + (rustic-align-to-method-chain)) + (save-excursion + (rustic-rewind-irrelevant) + (backward-up-list) + (rustic-rewind-to-beginning-of-current-level-expr) + (+ (current-column) rustic-indent-offset)))))) + (cond + ;; Indent inside a non-raw string only if the the previous line + ;; ends with a backslash that is inside the same string + ((nth 3 (syntax-ppss)) + (let* + ((string-begin-pos (nth 8 (syntax-ppss))) + (end-of-prev-line-pos (when (> (line-number-at-pos) 1) + (save-excursion + (forward-line -1) + (end-of-line) + (point))))) + (when + (and + ;; If the string begins with an "r" it's a raw string and + ;; we should not change the indentation + (/= ?r (char-after string-begin-pos)) + + ;; If we're on the first line this will be nil and the + ;; rest does not apply + end-of-prev-line-pos + + ;; The end of the previous line needs to be inside the + ;; current string... + (> end-of-prev-line-pos string-begin-pos) + + ;; ...and end with a backslash + (= ?\\ (char-before end-of-prev-line-pos))) + + ;; Indent to the same level as the previous line, or the + ;; start of the string if the previous line starts the string + (if (= (line-number-at-pos end-of-prev-line-pos) + (line-number-at-pos string-begin-pos)) + ;; The previous line is the start of the string. + ;; If the backslash is the only character after the + ;; string beginning, indent to the next indent + ;; level. Otherwise align with the start of the string. + (if (> (- end-of-prev-line-pos string-begin-pos) 2) + (save-excursion + (goto-char (+ 1 string-begin-pos)) + (current-column)) + baseline) + + ;; The previous line is not the start of the string, so + ;; match its indentation. + (save-excursion + (goto-char end-of-prev-line-pos) + (back-to-indentation) + (current-column)))))) + + ;; A function return type is indented to the corresponding + ;; function arguments, if -to-arguments is selected. + ((and rustic-indent-return-type-to-arguments + (looking-at "->")) + (save-excursion + (backward-list) + (or (rustic-align-to-expr-after-brace) + (+ baseline rustic-indent-offset)))) + + ;; A closing brace is 1 level unindented + ((looking-at "[]})]") (- baseline rustic-indent-offset)) + + ;; Doc comments in /** style with leading * indent to line up the *s + ((and (nth 4 (syntax-ppss)) (looking-at "*")) + (+ 1 baseline)) + + ;; When the user chose not to indent the start of the where + ;; clause, put it on the baseline. + ((and (not rustic-indent-where-clause) + (rustic-looking-at-where)) + baseline) + + ;; If we're in any other token-tree / sexp, then: + (t + (or + ;; If we are inside a pair of braces, with something after the + ;; open brace on the same line and ending with a comma, treat + ;; it as fields and align them. + (when (> level 0) + (save-excursion + (rustic-rewind-irrelevant) + (backward-up-list) + ;; Point is now at the beginning of the containing set of braces + (rustic-align-to-expr-after-brace))) + + ;; When where-clauses are spread over multiple lines, clauses + ;; should be aligned on the type parameters. In this case we + ;; take care of the second and following clauses (the ones + ;; that don't start with "where ") + (save-excursion + ;; Find the start of the function, we'll use this to limit + ;; our search for "where ". + (let ((function-start nil) (function-level nil)) + (save-excursion + ;; If we're already at the start of a function, + ;; don't go back any farther. We can easily do + ;; this by moving to the end of the line first. + (end-of-line) + (rustic-beginning-of-defun) + (back-to-indentation) + ;; Avoid using multiple-value-bind + (setq function-start (point) + function-level (rustic-paren-level))) + ;; When we're not on a line starting with "where ", but + ;; still on a where-clause line, go to "where " + (when (and + (not (rustic-looking-at-where)) + ;; We're looking at something like "F: ..." + (looking-at (concat rustic-re-ident ":")) + ;; There is a "where " somewhere after the + ;; start of the function. + (rustic-rewind-to-where function-start) + ;; Make sure we're not inside the function + ;; already (e.g. initializing a struct) by + ;; checking we are the same level. + (= function-level level)) + ;; skip over "where" + (forward-char 5) + ;; Unless "where" is at the end of the line + (if (eolp) + ;; in this case the type parameters bounds are just + ;; indented once + (+ baseline rustic-indent-offset) + ;; otherwise, skip over whitespace, + (skip-chars-forward "[:space:]") + ;; get the column of the type parameter and use that + ;; as indentation offset + (current-column))))) + + (progn + (back-to-indentation) + ;; Point is now at the beginning of the current line + (if (or + ;; If this line begins with "else" or "{", stay on the + ;; baseline as well (we are continuing an expression, + ;; but the "else" or "{" should align with the beginning + ;; of the expression it's in.) + ;; Or, if this line starts a comment, stay on the + ;; baseline as well. + (looking-at "\\<else\\>\\|{\\|/[/*]") + + ;; If this is the start of a top-level item, + ;; stay on the baseline. + (looking-at rustic-top-item-beg-re) + + (save-excursion + (rustic-rewind-irrelevant) + ;; Point is now at the end of the previous line + (or + ;; If we are at the start of the buffer, no + ;; indentation is needed, so stay at baseline... + (= (point) 1) + ;; ..or if the previous line ends with any of these: + ;; { ? : ( , ; [ } + ;; then we are at the beginning of an + ;; expression, so stay on the baseline... + (looking-back "[(,:;?[{}]\\|[^|]|" (- (point) 2)) + ;; or if the previous line is the end of an + ;; attribute, stay at the baseline... + (progn + (rustic-rewind-to-beginning-of-current-level-expr) + (looking-at "#"))))) + baseline + + ;; Otherwise, we are continuing the same + ;; expression from the previous line, so add one + ;; additional indent level + (+ baseline rustic-indent-offset)))))))))) + + (when indent + ;; If we're at the beginning of the line (before or at the current + ;; indentation), jump with the indentation change. Otherwise, save the + ;; excursion so that adding the indentations will leave us at the + ;; equivalent position within the line to where we were before. + (if (<= (current-column) (current-indentation)) + (indent-line-to indent) + (save-excursion (indent-line-to indent)))))) + +;;; Miscellaneous + +;;;###autoload +(defun rustic-promote-module-into-dir () + "Promote the module file visited by the current buffer into its own directory. + +For example, if the current buffer is visiting the file `foo.rs', +then this function creates the directory `foo' and renames the +file to `foo/mod.rs'. The current buffer will be updated to +visit the new file." + (interactive) + (let ((filename (buffer-file-name))) + (if (not filename) + (message "Buffer is not visiting a file.") + (if (string-equal (file-name-nondirectory filename) "mod.rs") + (message "Won't promote a module file already named mod.rs.") + (let* ((basename (file-name-sans-extension + (file-name-nondirectory filename))) + (mod-dir (file-name-as-directory + (concat (file-name-directory filename) basename))) + (new-name (concat mod-dir "mod.rs"))) + (mkdir mod-dir t) + (rename-file filename new-name 1) + (set-visited-file-name new-name)))))) + +(defun rustic-docstring-dwim () + "Use `comment-dwim' to make a docstring." + (interactive) + (let ((comment-start "/// ")) + (call-interactively 'comment-dwim))) + +;;;###autoload +(defun rustic-open-dependency-file () + "Open the 'Cargo.toml' file at the project root if the current buffer is +visiting a project." + (interactive) + (let ((workspace (rustic-buffer-workspace t))) + (if workspace + (find-file (concat workspace "/Cargo.toml")) + (message "The current buffer is not inside a rust project!")))) + +;;; Defun Motions + +(defvar rustic-func-item-beg-re + (concat "\\s-*\\(?:priv\\|pub\\)?\\s-*\\(?:async\\)?\\s-*" + (regexp-opt '("fn"))) + "Start of a rust function.") + +(defun rustic-beginning-of-function () + "Move to beginning of rust function at point." + (rustic-beginning-of-defun nil rustic-func-item-beg-re)) + +;; TODO: since we are using `rustic-top-item-beg-re' this function actually sets +;; the point where it finds the first item of the list +;; this function should be renamed or documented correctly +;;;###autoload +(defun rustic-beginning-of-defun (&optional arg regex) + "Move backward to the beginning of the current defun. + +With ARG, move backward multiple defuns. Negative ARG means +move forward. + +This is written mainly to be used as `beginning-of-defun-function' for Rust. +Don't move to the beginning of the line. `beginning-of-defun', +which calls this, does that afterwards." + (interactive "p") + (let* ((arg (or arg 1)) + (magnitude (abs arg)) + (sign (if (< arg 0) -1 1))) + ;; If moving forward, don't find the defun we might currently be + ;; on. + (when (< sign 0) + (end-of-line)) + (catch 'done + (dotimes (_ magnitude) + ;; Search until we find a match that is not in a string or comment. + (while (if (re-search-backward + (concat "^\\(" (or regex rustic-top-item-beg-re) "\\)") + nil 'move sign) + (rustic-in-str-or-cmnt) + ;; Did not find it. + (throw 'done nil))))) + t)) + +;;;###autoload +(defun rustic-end-of-defun () + "Move forward to the next end of defun. + +With argument, do it that many times. +Negative argument -N means move back to Nth preceding end of defun. + +Assume that this is called after beginning-of-defun. So point is +at the beginning of the defun body. + +This is written mainly to be used as `end-of-defun-function' for Rust." + (interactive) + ;; Find the opening brace + (if (re-search-forward "[{]" nil t) + (progn + (goto-char (match-beginning 0)) + ;; Go to the closing brace + (condition-case nil + (forward-sexp) + (scan-error + ;; The parentheses are unbalanced; instead of being unable + ;; to fontify, just jump to the end of the buffer + (goto-char (point-max))))) + ;; There is no opening brace, so consider the whole buffer to be one "defun" + (goto-char (point-max)))) + +;;; _ +(provide 'rustic-interaction) +;;; rustic-interaction.el ends here diff --git a/emacs.d/elpa/rustic-20210609.1900/rustic-lsp.el b/emacs.d/elpa/rustic-20210609.1900/rustic-lsp.el new file mode 100644 index 0000000..471e7cc --- /dev/null +++ b/emacs.d/elpa/rustic-20210609.1900/rustic-lsp.el @@ -0,0 +1,170 @@ +;;; rustic-lsp.el --- Support for lsp -*- lexical-binding:t -*- +;;; Commentary: + +;; This library implements support for "lsp". + +;;; Code: + +(require 'rustic-rustfmt) + +;;; Options + +;; FIXME This is non-idomatic. This option should be replaced with +;; documentation that instructs the user to add the setup function +;; themselves, iff so desired. +(defcustom rustic-lsp-setup-p t + "Setup LSP related stuff automatically. +If this is non-nil (the default), then loading `rustic-lsp' adds +`rustic-setup-lsp' to `rustic-mode-hook'. If you don't want that +then you must set this to nil before loading `rustic-lsp'." + :type 'boolean + :safe #'booleanp + :group 'rustic) +(when rustic-lsp-setup-p + (add-hook 'rustic-mode-hook 'rustic-setup-lsp)) + +(defcustom rustic-lsp-server 'rust-analyzer + "Choose your LSP server." + :type '(choice (const :tag "rls" rls) + (const :tag "rust-analyzer" rust-analyzer)) + :group 'rustic) + +(define-obsolete-variable-alias 'rustic-rls-pkg 'rustic-lsp-client "Rustic 0.18") +(defcustom rustic-lsp-client 'lsp-mode + "Emacs package for interaction with the language server." + :type '(choice (const :tag "eglot" eglot) + (const :tag "lsp-mode" lsp-mode) + (const :tag "No LSP client" nil)) + :group 'rustic) + +(defcustom rustic-lsp-format nil + "Allow formatting through lsp server." + :type 'boolean + :safe #'booleanp + :group 'rustic) + +(defcustom rustic-analyzer-command '("rust-analyzer") + "Command for calling rust analyzer." + :type '(repeat (string)) + :group 'rustic) + +;;; Common + +(defun rustic-setup-lsp () + "Setup LSP client. If client isn't installed, offer to install it." + (let ((client rustic-lsp-client)) + (cond ((eq client nil) + nil) + ((require client nil t) + (if (eq client 'eglot) + (eglot-ensure) + (rustic-lsp-mode-setup) + (lsp))) + (t + (rustic-install-lsp-client-p client))))) + +;;; lsp support + +(defvar lsp-rust-analyzer-macro-expansion-method) +(defvar lsp-rust-analyzer-server-command) +(defvar lsp-rust-server) +(declare-function lsp "lsp-mode" (&optional arg)) +(declare-function lsp-rust-switch-server "lsp-rust" (lsp-server)) +(declare-function lsp-workspace-folders-add "lsp-rust" (project-root)) +(declare-function lsp-workspace-root "lsp-mode" (&optional path)) + +(defun rustic-lsp-mode-setup () + "When changing the `lsp-rust-server', it's also necessary to update the priorities +with `lsp-rust-switch-server'." + (require 'lsp-rust) + (require 'lsp-modeline) + (lsp-workspace-folders-add (rustic-buffer-workspace)) + (setq lsp-rust-server rustic-lsp-server) + (setq lsp-rust-analyzer-server-command rustic-analyzer-command) + (lsp-rust-switch-server rustic-lsp-server)) + +(defun rustic-install-lsp-client-p (lsp-client) + "Ask user whether to install missing LSP-CLIENT." + (if (yes-or-no-p (format "%s not found. Install it ?" lsp-client)) + (condition-case err + (progn + (package-refresh-contents) + (package-install lsp-client) + (require lsp-client) + (rustic-setup-lsp)) + (error err)) + (message "No LSP server running."))) + +;;; eglot support + +(defvar eglot-ignored-server-capabilites) +(defvar eglot-ignored-server-capabilites) +(defvar eglot-server-programs) +(defvar eglot-server-programs) +(declare-function eglot-ensure "eglot" ()) + +(defun rustic-setup-eglot () + "Configure eglot for rustic." + (require 'eglot) + (if (equal rustic-lsp-server 'rls) + ;; add rustic to `eglot-server-programs' + (let ((rls '(rustic-mode . (eglot-rls "rls")))) + (unless (member rls eglot-server-programs) + (setq eglot-server-programs + `(,rls + ;; replace rust-mode with rustic + ,@(-remove-first (lambda (mode) + (when (symbolp (car mode)) + (eq (car mode) 'rust-mode))) + eglot-server-programs))))) + (add-to-list 'eglot-server-programs `(rustic-mode . ,rustic-analyzer-command))) + ;; don't allow formatting with rls + (unless rustic-lsp-format + (let ((feature :documentFormattingProvider)) + (unless (-contains? eglot-ignored-server-capabilites feature) + (add-to-list 'eglot-ignored-server-capabilites feature))))) + +(with-eval-after-load 'eglot + (rustic-setup-eglot)) + +;;; rustic-macro-expansion-mode + +(setq lsp-rust-analyzer-macro-expansion-method 'rustic-analyzer-macro-expand) + +(define-derived-mode rustic-macro-expansion-mode special-mode "Rust" + :group 'rustic + :syntax-table rustic-mode-syntax-table + ;; Fonts + (setq-local font-lock-defaults '(rustic-font-lock-keywords + nil nil nil nil + (font-lock-syntactic-face-function + . rustic-syntactic-face-function)))) + +;;;###autoload +(defun rustic-analyzer-macro-expand (result) + "Default method for displaying macro expansion results." + (interactive) + (let* ((root (lsp-workspace-root default-directory)) + (buf (get-buffer-create + (format "*rust-analyzer macro expansion %s*" root)))) + (with-current-buffer buf + (let ((inhibit-read-only t)) + (erase-buffer) + ;; wrap expanded macro in a main function so we can run rustfmt + (insert "fn main()") + ;; rustfmt complains about $s + (insert (replace-regexp-in-string "\\$" "" result)) + (rustic-macro-expansion-mode) + (rustic-format-buffer) + (with-current-buffer buf + (save-excursion + (goto-char (point-min)) + (delete-region (point-min) (line-end-position)) + (goto-char (point-max)) + (forward-line -1) + (delete-region (line-beginning-position) (point-max)))))) + (display-buffer buf))) + +;;; _ +(provide 'rustic-lsp) +;;; rustic-lsp.el ends here diff --git a/emacs.d/elpa/rustic-20210609.1900/rustic-pkg.el b/emacs.d/elpa/rustic-20210609.1900/rustic-pkg.el new file mode 100644 index 0000000..64c1a7d --- /dev/null +++ b/emacs.d/elpa/rustic-20210609.1900/rustic-pkg.el @@ -0,0 +1,20 @@ +(define-package "rustic" "20210609.1900" "Rust development environment" + '((emacs "26.1") + (dash "2.13.0") + (f "0.18.2") + (let-alist "1.0.4") + (markdown-mode "2.3") + (project "0.3.0") + (s "1.10.0") + (seq "2.3") + (spinner "1.7.3") + (xterm-color "1.6")) + :commit "6ca73bb3cce4d1db3c4f91efb83b63227eb712d1" :authors + '(("Mozilla")) + :maintainer + '("Mozilla") + :keywords + '("languages")) +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/emacs.d/elpa/rustic-20210609.1900/rustic-playpen.el b/emacs.d/elpa/rustic-20210609.1900/rustic-playpen.el new file mode 100644 index 0000000..82e38b5 --- /dev/null +++ b/emacs.d/elpa/rustic-20210609.1900/rustic-playpen.el @@ -0,0 +1,61 @@ +;;; rustic-playpen.el --- Support for playpen -*- lexical-binding:t -*- +;;; Commentary: +;;; Code: + +(require 'org-element) +(require 'url) + +;;; Options + +(defcustom rustic-playpen-url-format "https://play.rust-lang.org/?code=%s" + "Format string to use when submitting code to the playpen." + :type 'string + :group 'rustic) + +(defcustom rustic-shortener-url-format "https://is.gd/create.php?format=simple&url=%s" + "Format string to use for creating the shortened link of a playpen submission." + :type 'string + :group 'rustic) + +;;; Commands + +;;;###autoload +(defun rustic-playpen (begin end) + "Create a shareable URL for the contents of the current region, +src-block or buffer on the Rust playpen." + (interactive "r") + (let (data) + (cond + ((region-active-p) + (setq data (buffer-substring begin end))) + ((org-in-src-block-p) + (setq data (org-element-property :value (org-element-at-point)))) + (t + (setq data (buffer-substring (point-min) (point-max))))) + (let* ((escaped-data (url-hexify-string data)) + (escaped-playpen-url (url-hexify-string + (format rustic-playpen-url-format + escaped-data)))) + (if (> (length escaped-playpen-url) 5000) + (error "encoded playpen data exceeds 5000 character limit (length %s)" + (length escaped-playpen-url)) + (let ((shortener-url (format rustic-shortener-url-format escaped-playpen-url)) + (url-request-method "POST")) + (url-retrieve shortener-url + (lambda (state) + ;; filter out the headers etc. included at the + ;; start of the buffer: the relevant text + ;; (shortened url or error message) is exactly + ;; the last line. + (goto-char (point-max)) + (let ((last-line (thing-at-point 'line t)) + (err (plist-get state :error))) + (kill-buffer) + (if err + (error "failed to shorten playpen url: %s" last-line) + (let ((URL (read-from-minibuffer "Playpen URL: " last-line))) + (browse-url URL))))))))))) + +;;; _ +(provide 'rustic-playpen) +;;; rustic-playpen.el ends here diff --git a/emacs.d/elpa/rustic-20210609.1900/rustic-popup.el b/emacs.d/elpa/rustic-20210609.1900/rustic-popup.el new file mode 100644 index 0000000..c8864eb --- /dev/null +++ b/emacs.d/elpa/rustic-20210609.1900/rustic-popup.el @@ -0,0 +1,241 @@ +;;; rustic-popup.el --- Cargo popup -*-lexical-binding: t-*- + +;;; Commentary: + +;; Provides magit like popup. + +;;; Code: + +(require 'rustic-cargo) + +;;; Customization + +(defcustom rustic-popup-commands + '((?b "build" build) + (?f "fmt" fmt) + (?r "run" run) + (?c "clippy" clippy) + (?o "outdated" outdated) + (?e "clean" clean) + (?k "check" check) + (?t "test" test) + (?d "doc" doc)) + "List of commands that are displayed in the popup. +The first element of each list contains a command's binding." + :type 'list + :group 'rustic-popup) + +(define-obsolete-face-alias 'rustic-popup-key-face + 'rustic-popup-key "1.2") +(define-obsolete-face-alias 'rustic-popup-section-face + 'rustic-popup-section "1.2") + +(defface rustic-popup-key + '((t (:foreground "DeepSkyBlue"))) + "Face used for command shortcuts." + :group 'rustic) + +(defface rustic-popup-section + '((t (:foreground "#f74c00"))) + "Face used for popup section description." + :group 'rustic) + +;;; Popup Mode + +(defvar rustic-popup-buffer-name "rustic-popup-buffer" + "Buffer name for rustic popup buffers.") + +(defvar rustic-popup-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [remap self-insert-command] 'rustic-popup-invoke-popup-action) + (define-key map (kbd "g") 'rustic-recompile) + (define-key map (kbd "RET") 'rustic-popup-default-action) + (define-key map (kbd "<tab>") 'rustic-popup-default-action) + (define-key map (kbd "h") 'rustic-popup-cargo-command-help) + (define-key map (kbd "q") 'kill-buffer-and-window) + map) + "Keymap for rustic popup buffers.") + +(define-derived-mode rustic-popup-mode fundamental-mode "RusticPopup" + "Mode for rustic popup buffers." + (setq truncate-lines t) + (setq buffer-read-only t) + (setq-local scroll-margin 0)) + +(defun rustic-popup-insert-backtrace () + "Insert backtrace section." + (let ((inhibit-read-only t) + (prop (lambda (s) + (propertize s 'face 'rustic-popup-section)))) + (insert (funcall prop "Backtrace: ")) + (cond + ((string= rustic-compile-backtrace "0") + (insert " " (funcall prop "0") " | 1 | full")) + ((string= rustic-compile-backtrace "1") + (insert " 0 | " (funcall prop "1") " | full")) + ((string= rustic-compile-backtrace "full") + (insert " 0 | 1 | " (funcall prop "full"))))) + (insert "\n\n")) + +(defun rustic-popup-insert-contents (buf) + "Insert popup buffer contents." + (let ((inhibit-read-only t)) + (with-current-buffer buf + (erase-buffer) + (rustic-popup-mode) + (rustic-popup-insert-backtrace) + (insert (propertize "Commands: " 'face 'rustic-popup-section) "\n") + (insert " " (propertize "g" 'face 'rustic-popup-key) + " " "recompile" " " "\"" + (or compilation-arguments rustic-compile-command) + "\"" "\n\n") + (dolist (command rustic-popup-commands) + (insert "\s") + (insert (propertize (char-to-string (nth 0 command)) + 'face 'rustic-popup-key)) + (insert "\s\s\s\s\s\s") + (insert (nth 1 command)) + (when (and (string= (nth 1 command) "test") + (> (length rustic-test-arguments) 0)) + (insert " " "\"" rustic-test-arguments "\"")) + (insert "\n")) + (goto-char (point-min))))) + +;;;###autoload +(defun rustic-popup () + "Setup popup. +If directory is not in a rust project call `read-directory-name'." + (interactive) + (let ((func (lambda () + (let ((buf (get-buffer-create rustic-popup-buffer-name)) + (win (split-window-below)) + (inhibit-read-only t)) + (rustic-popup-insert-contents buf) + (set-window-buffer win buf) + (select-window win) + (fit-window-to-buffer) + (set-window-text-height win (+ (window-height) 1)))))) + (if (rustic-buffer-workspace t) + (funcall func) + (let ((dir (read-directory-name "Rust project:"))) + (let ((default-directory dir)) + (if (rustic-buffer-workspace t) + (funcall func) + (message "Not a rust project."))))))) + +;;; Interactive + +;;;###autoload +(defun rustic-popup-invoke-popup-action (event) + "Execute commands which are listed in `rustic-popup-commands'." + (interactive (list last-command-event)) + (save-excursion + (let ((char (char-to-string event))) + (save-match-data + (goto-char (point-min)) + (when (re-search-forward (concat "\s" char "\s")) + (goto-char (match-beginning 0))))) + (let* ((command (cadr (split-string + (buffer-substring-no-properties + (point) (line-end-position))))) + (c (intern (concat "rustic-cargo-" command)))) + (if (commandp c) + (call-interactively c) + (call-interactively 'rustic-compile (concat "cargo " command)))))) + +;;;###autoload +(defun rustic-popup-default-action () + "Change backtrace and `compilation-arguments' when executed on +corresponding line." + (interactive) + (let ((inhibit-read-only t)) + (save-excursion + (goto-char (line-beginning-position)) + (cond + ((looking-at "Backtrace:") + (cond + ((string= rustic-compile-backtrace "0") + (setq rustic-compile-backtrace "1")) + ((string= rustic-compile-backtrace "1") + (setq rustic-compile-backtrace "full")) + ((string= rustic-compile-backtrace "full") + (setq rustic-compile-backtrace "0"))) + (rustic-popup-insert-contents (current-buffer))) + ((search-forward-regexp "\srecompile\s" (line-end-position) t) + (setq compilation-arguments + (read-string "Compilation arguments: " + (or compilation-arguments rustic-compile-command))) + (rustic-popup-insert-contents (current-buffer))) + ((search-forward-regexp "\stest" (line-end-position) t) + (setq rustic-test-arguments + (read-string "Cargo test arguments: " rustic-test-arguments)) + (rustic-popup-insert-contents (current-buffer))) + (t + (message "No default action for line.")))))) + +;;; Help Popup + +(defvar rustic-popup-help-buffer-name "rustic-popup-help-buffer" + "Buffer name for rustic popup help buffers.") + +(defvar rustic-popup-help-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "q") 'rustic-popup-kill-help-buffer) + map) + "Keymap for rustic popup help buffers.") + +(define-derived-mode rustic-popup-help-mode fundamental-mode "RusticHelpPopup" + "Mode for rustic popup help buffers." + (setq truncate-lines t) + (setq buffer-read-only t) + (setq-local scroll-margin 0)) + +;;;###autoload +(defun rustic-popup-cargo-command-help () + "Display help buffer for cargo command at point." + (interactive) + (let (command) + (save-excursion + (goto-char (line-beginning-position)) + (setq command (cadr (split-string + (buffer-substring-no-properties (line-beginning-position) + (line-end-position)))))) + (let* ((string (rustic-popup-help-flags command)) + (inhibit-read-only t)) + (if (not (and (> (length command) 0) + (> (length (split-string string "\n")) 0))) + (message "No help information for command at point.") + (rustic-popup-setup-help-popup string))))) + +(defun rustic-popup-help-flags (command) + "Get flags of COMMAND." + (let ((string (shell-command-to-string (format "cargo %s -h" command))) + flags) + (dolist (s (split-string string "\n")) + (when (and (not (string-match "^\s+\-h" s)) + (string-match "^\s+\-" s)) + (setq flags (concat flags s "\n")))) + flags)) + +(defun rustic-popup-setup-help-popup (string) + "Switch to help buffer." + (let ((buf (get-buffer-create rustic-popup-help-buffer-name))) + (switch-to-buffer buf) + (erase-buffer) + (rustic-popup-help-mode) + (insert string) + (fit-window-to-buffer) + (set-window-text-height (selected-window) (+ (window-height) 1)) + (goto-char (point-min)))) + +;;;###autoload +(defun rustic-popup-kill-help-buffer () + "Kill popup help buffer and switch to popup buffer." + (interactive) + (switch-to-buffer rustic-popup-buffer-name) + (fit-window-to-buffer) + (set-window-text-height (selected-window) (+ (window-height) 1))) + +;;; _ +(provide 'rustic-popup) +;;; rustic-popup.el ends here diff --git a/emacs.d/elpa/rustic-20210609.1900/rustic-racer.el b/emacs.d/elpa/rustic-20210609.1900/rustic-racer.el new file mode 100644 index 0000000..7910183 --- /dev/null +++ b/emacs.d/elpa/rustic-20210609.1900/rustic-racer.el @@ -0,0 +1,515 @@ +;;; rustic-racer.el --- Racer support -*-lexical-binding: t-*- + +;;; Code: + +(require 'f) +(require 's) + +(require 'button) +(require 'etags) +(require 'help-mode) +(require 'thingatpt) + +(require 'rustic) + +(defvar rustic-racer-args nil) + +(defgroup racer nil + "Docs browsing for Rust via racer." + :link '(url-link "https://github.com/racer-rust/emacs-racer/") + :group 'rustic-mode) + +;;; Customization + +(defcustom rustic-racer-cmd + (or (executable-find "racer") + (f-expand "~/.cargo/bin/racer") + "/usr/local/bin/racer") + "Path to the racer binary." + :type 'file + :group 'racer) + +(defcustom rustic-racer-rust-src-path + (or + (getenv "RUST_SRC_PATH") + (when (executable-find "rustc") + (let* ((sysroot (s-trim-right + (shell-command-to-string + (format "%s --print sysroot" (executable-find "rustc"))))) + (src-path (f-join sysroot "lib/rustlib/src/rust/src"))) + (when (file-exists-p src-path) + src-path) + src-path)) + "/usr/local/src/rust/src") + + "Path to the rust source tree. +If nil, we will query $RUST_SRC_PATH at runtime. +If $RUST_SRC_PATH is not set, look for rust source +in rustup's install directory." + :type 'file + :group 'racer) + +(defcustom rustic-racer-cargo-home + (or + (getenv "CARGO_HOME") + "~/.cargo") + "Path to your current cargo home. Usually `~/.cargo'. +If nil, we will query $CARGO_HOME at runtime." + :type 'file + :group 'racer) + +;;; Faces + +(define-obsolete-face-alias 'rustic-racer-help-heading-face + 'rustic-racer-help-heading "1.2") + +(defface rustic-racer-help-heading + '((t :weight bold)) + "Face for markdown headings in *Racer Help* buffers.") + +(defface rustic-racer-tooltip + '((((min-colors 16777216)) + :background "#292C33" :foreground "white") + (t + :background "black" :foreground "white")) + "Face used for the tooltip with `racer-describe-tooltip'") + +;;; Help-mode + +(defvar rustic-racer-help-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map (make-composed-keymap button-buffer-map + special-mode-map)) + map) + "Keymap for racer help mode.") + +(define-derived-mode rustic-racer-help-mode fundamental-mode + "Racer-Help" + "Major mode for *Racer Help* buffers. +Commands: +\\{racer-help-mode-map}") + +(defun rustic-racer-header (text) + "Helper function for adding text properties to TEXT." + (propertize text 'face 'rustic-racer-help-heading)) + +(defun rustic-racer-button-go-to-src (button) + (rustic-racer-find-file + (button-get button 'path) + (button-get button 'line) + (button-get button 'column))) + +(define-button-type 'racer-src-button + 'action 'rustic-racer-button-go-to-src + 'follow-link t + 'help-echo "Go to definition") + +(defun rustic-racer-url-button (text url) + "Return a button that opens a browser at URL." + (with-temp-buffer + (insert-text-button + text + :type 'help-url + 'help-args (list url)) + (buffer-string))) + +(defun rustic-racer-src-button (path line column) + "Return a button that navigates to PATH at LINE number and +COLUMN number." + ;; Convert "/foo/bar/baz/foo.rs" to "baz/foo.rs" + (let* ((filename (f-filename path)) + (parent-dir (f-filename (f-parent path))) + (short-path (f-join parent-dir filename))) + (with-temp-buffer + (insert-text-button + short-path + :type 'racer-src-button + 'path path + 'line line + 'column column) + (buffer-string)))) + +(defun rustic-racer-help-buf (contents) + "Create a *Racer Help* buffer with CONTENTS." + (let ((buf (get-buffer-create "*Racer Help*")) + ;; If the buffer already existed, we need to be able to + ;; override `buffer-read-only'. + (inhibit-read-only t)) + (with-current-buffer buf + (erase-buffer) + (insert contents) + (setq buffer-read-only t) + (goto-char (point-min)) + (rustic-racer-help-mode)) + buf)) + +;;; Racer + +(defvar rustic-racer-prev-state nil) + +(defun rustic-racer-call (command &rest args) + "Call racer command COMMAND with args ARGS. +Return stdout if COMMAND exits normally, otherwise show an +error." + (let ((rust-src-path (or rustic-racer-rust-src-path (getenv "RUST_SRC_PATH"))) + (cargo-home (or rustic-racer-cargo-home (getenv "CARGO_HOME")))) + (when (null rust-src-path) + (user-error "You need to set `rustic-racer-rust-src-path' or `RUST_SRC_PATH'")) + (unless (file-exists-p rust-src-path) + (user-error "No such directory: %s. Please set `rustic-racer-rust-src-path' or `RUST_SRC_PATH'" + rust-src-path)) + (let ((default-directory (rustic-buffer-workspace)) + (process-environment (append (list + (format "RUST_SRC_PATH=%s" (expand-file-name rust-src-path)) + (format "CARGO_HOME=%s" (expand-file-name cargo-home))) + process-environment))) + (-let [(exit-code stdout _stderr) + (rustic-racer-shell-command rustic-racer-cmd (cons command args))] + ;; Use `equal' instead of `zero' as exit-code can be a string + ;; "Aborted" if racer crashes. + (unless (equal 0 exit-code) + (user-error "%s exited with %s. `M-x rustic-racer-debug' for more info" + rustic-racer-cmd exit-code)) + stdout)))) + +(defun rustic-racer-doc (name) + "Return a *Racer Help* buffer for the function or type at point. +If there are multiple candidates at point, use NAME to find the +correct value." + (let ((description (rustic-racer-describe-at-point name))) + (when description + (let* ((name (plist-get description :name)) + (raw-docstring (plist-get description :docstring)) + (docstring (if raw-docstring + (rustic-racer-propertize-docstring raw-docstring) + "Not documented.")) + (kind (plist-get description :kind))) + (rustic-racer-help-buf + (format + "%s is %s defined in %s.\n\n%s%s" + name + (rustic-racer-kind-description kind) + (rustic-racer-src-button + (plist-get description :path) + (plist-get description :line) + (plist-get description :column)) + (if (equal kind "Module") + ;; No point showing the 'signature' of modules, which is + ;; just their full path. + "" + (format " %s\n\n" (rustic-racer-syntax-highlight (plist-get description :signature)))) + docstring)))))) + +(defun rustic-racer-describe-at-point (name) + "Get a description of the symbol at point matching NAME. +If there are multiple possibilities with this NAME, prompt +the user to choose." + (let* ((output-lines (save-excursion + ;; Move to the end of the current symbol, to + ;; increase racer accuracy. + (skip-syntax-forward "w_") + (rustic-racer-call-at-point "complete-with-snippet"))) + (all-matches (--map (when (s-starts-with-p "MATCH " it) + (rustic-racer-split-snippet-match it)) + output-lines)) + (relevant-matches (--filter (equal (plist-get it :name) name) + all-matches))) + (if (> (length relevant-matches) 1) + ;; We might have multiple matches with the same name but + ;; different types. E.g. Vec::from. + (let ((signature + (completing-read "Multiple matches: " + (--map (plist-get it :signature) relevant-matches)))) + (--first (equal (plist-get it :signature) signature) relevant-matches)) + (-first-item relevant-matches)))) + +(defmacro rustic-racer-with-temporary-file (path-sym &rest body) + "Create a temporary file, and bind its path to PATH-SYM. +Evaluate BODY, then delete the temporary file." + (declare (indent 1) (debug (symbolp body))) + `(let ((,path-sym (make-temp-file "racer"))) + (unwind-protect + (progn ,@body) + (delete-file ,path-sym)))) + +(defun rustic-racer-call-at-point (command) + "Call racer command COMMAND at point of current buffer. +Return a list of all the lines returned by the command." + (rustic-racer-with-temporary-file tmp-file + (write-region nil nil tmp-file nil 'silent) + (let ((racer-args (list + command + (number-to-string (line-number-at-pos)) + (number-to-string (rustic-racer-current-column))))) + ;; If this buffer is backed by a file, pass that to racer too. + (-when-let (file-name (buffer-file-name (buffer-base-buffer))) + (setq rustic-racer-args + (append racer-args (list file-name)))) + + (setq rustic-racer-args (append rustic-racer-args (list tmp-file))) + (s-lines + (s-trim-right + (apply #'rustic-racer-call rustic-racer-args)))))) + +(defun rustic-racer-shell-command (program args) + "Execute PROGRAM with ARGS. +Return a list (exit-code stdout stderr)." + (rustic-racer-with-temporary-file tmp-file-for-stderr + (let (exit-code stdout stderr) + ;; Create a temporary buffer for `call-process` to write stdout + ;; into. + (with-temp-buffer + (setq exit-code + (apply #'call-process program nil + (list (current-buffer) tmp-file-for-stderr) + nil args)) + (setq stdout (buffer-string))) + (setq stderr (rustic-racer-slurp tmp-file-for-stderr)) + (setq rustic-racer-prev-state + (list + :program program + :args args + :exit-code exit-code + :stdout stdout + :stderr stderr + :default-directory default-directory + :process-environment process-environment)) + (list exit-code stdout stderr)))) + +;;; Utility Functions + +(defun rustic-racer-slurp (file) + "Return the contents of FILE as a string." + (with-temp-buffer + (insert-file-contents-literally file) + (buffer-string))) + +(defun rustic-racer-read-rust-string (string) + "Convert STRING, a rust string literal, to an elisp string." + (when string + (->> string + ;; Remove outer double quotes. + (s-chop-prefix "\"") + (s-chop-suffix "\"") + ;; Replace escaped characters. + (s-replace "\\n" "\n") + (s-replace "\\\"" "\"") + (s-replace "\\'" "'") + (s-replace "\\;" ";")))) + +(defun rustic-racer-url-p (target) + "Return t if TARGET looks like a fully qualified URL." + (not (null + (string-match-p (rx bol "http" (? "s") "://") target)))) + +(defun rustic-racer-propertize-links (markdown) + "Propertize links in MARKDOWN." + (replace-regexp-in-string + ;; Text of the form [foo](http://example.com) + (rx "[" (group (+? (not (any "]")))) "](" (group (+? anything)) ")") + ;; For every match: + (lambda (whole-match) + ;; Extract link and target. + (let ((link-text (match-string 1 whole-match)) + (link-target (match-string 2 whole-match))) + ;; If it's a web URL, use a clickable link. + (if (rustic-racer-url-p link-target) + (rustic-racer-url-button link-text link-target) + ;; Otherwise, just discard the target. + link-text))) + markdown)) + +(defun rustic-racer-propertize-all-inline-code (markdown) + "Given a single line MARKDOWN, replace all instances of `foo` or +\[`foo`\] with a propertized string." + (let ((highlight-group + (lambda (whole-match) + (rustic-racer-syntax-highlight (match-string 1 whole-match))))) + (->> markdown + (replace-regexp-in-string + (rx "[`" (group (+? anything)) "`]") + highlight-group) + (replace-regexp-in-string + (rx "`" (group (+? anything)) "`") + highlight-group)))) + +(defun rustic-racer-indent-block (str) + "Indent every line in STR." + (s-join "\n" (--map (concat " " it) (s-lines str)))) + +(defun rustic-racer-trim-newlines (str) + "Remove newlines from the start and end of STR." + (->> str + (s-chop-prefix "\n") + (s-chop-suffix "\n"))) + +(defun rustic-racer-remove-footnote-links (str) + "Remove footnote links from markdown STR." + (->> (s-lines str) + (--remove (string-match-p (rx bol "[`" (+? anything) "`]: ") it)) + (s-join "\n") + ;; Collapse consecutive blank lines caused by removing footnotes. + (s-replace "\n\n\n" "\n\n"))) + +(defun rustic-racer-docstring-sections (docstring) + "Split DOCSTRING into text, code and heading sections." + (let* ((sections nil) + (current-section-lines nil) + (section-type :text) + ;; Helper function. + (finish-current-section + (lambda () + (when current-section-lines + (let ((current-section + (s-join "\n" (nreverse current-section-lines)))) + (unless (s-blank? current-section) + (push (list section-type current-section) sections)) + (setq current-section-lines nil)))))) + (dolist (line (s-lines docstring)) + (cond + ;; If this is a closing ``` + ((and (s-starts-with-p "```" line) (eq section-type :code)) + (push line current-section-lines) + (funcall finish-current-section) + (setq section-type :text)) + ;; If this is an opening ``` + ((s-starts-with-p "```" line) + (funcall finish-current-section) + (push line current-section-lines) + (setq section-type :code)) + ;; Headings + ((and (not (eq section-type :code)) (s-starts-with-p "# " line)) + (funcall finish-current-section) + (push (list :heading line) sections)) + ;; Normal text. + (t + (push line current-section-lines)))) + (funcall finish-current-section) + (nreverse sections))) + +(defun rustic-racer-clean-code-section (section) + "Given a SECTION, a markdown code block, remove +fenced code delimiters and code annotations." + (->> (s-lines section) + (-drop 1) + (-drop-last 1) + ;; Ignore annotations like # #[allow(dead_code)] + (--remove (s-starts-with-p "# " it)) + (s-join "\n"))) + +(defun rustic-racer-propertize-docstring (docstring) + "Replace markdown syntax in DOCSTRING with text properties." + (let* ((sections (rustic-racer-docstring-sections docstring)) + (propertized-sections + (--map (-let [(section-type section) it] + ;; Remove trailing newlines, so we can ensure we + ;; have consistent blank lines between sections. + (rustic-racer-trim-newlines + (pcase section-type + (:text + (rustic-racer-propertize-all-inline-code + (rustic-racer-propertize-links + (rustic-racer-remove-footnote-links + section)))) + (:code + (rustic-racer-indent-block + (rustic-racer-syntax-highlight + (rustic-racer-clean-code-section section)))) + (:heading + (rustic-racer-header + (s-chop-prefix "# " section)))))) + sections))) + (s-join "\n\n" propertized-sections))) + +(defun rustic-racer-find-file (path line column) + "Open PATH and move point to LINE and COLUMN." + (find-file path) + (goto-char (point-min)) + (forward-line (1- line)) + (forward-char column)) + +(defun rustic-racer-kind-description (raw-kind) + "Human friendly description of a rust kind. +For example, 'EnumKind' -> 'an enum kind'." + (let* ((parts (s-split-words raw-kind)) + (description (s-join " " (--map (downcase it) parts))) + (a (if (string-match-p (rx bos (or "a" "e" "i" "o" "u")) description) + "an" "a"))) + (format "%s %s" a description))) + +(defun rustic-racer-current-column () + "Get the current column based on underlying character representation." + (length (buffer-substring-no-properties + (line-beginning-position) (point)))) + +(defun rustic-racer-syntax-highlight (str) + "Apply font-lock properties to a string STR of Rust code." + (let (result) + ;; Load all of STR in a rustic-mode buffer, and use its + ;; highlighting. + (with-temp-buffer + (insert str) + (delay-mode-hooks (rustic-mode)) + (if (fboundp 'font-lock-ensure) + (font-lock-ensure) + (with-no-warnings + (font-lock-fontify-buffer))) + (setq result (buffer-string))) + (when (and + ;; If we haven't applied any properties yet, + (null (text-properties-at 0 result)) + ;; and if it's a standalone symbol, then assume it's a + ;; variable. + (string-match-p (rx bos (+ (any lower "_")) eos) str)) + (setq result (propertize str 'face 'font-lock-variable-name-face))) + result)) + +(defun rustic-racer-split-parts (raw-output) + "Given RAW-OUTPUT from racer, split on semicolons and doublequotes. +Unescape strings as necessary." + (let ((parts nil) + (current "") + (i 0)) + (while (< i (length raw-output)) + (let ((char (elt raw-output i)) + (prev-char (and (> i 0) (elt raw-output (1- i))))) + (cond + ;; A semicolon that wasn't escaped, start a new part. + ((and (equal char ?\;) (not (equal prev-char ?\\))) + (push current parts) + (setq current "")) + (t + (setq current (concat current (string char)))))) + (setq i (1+ i))) + (push current parts) + (mapcar #'rustic-racer-read-rust-string (nreverse parts)))) + +(defun rustic-racer-split-snippet-match (line) + "Given LINE, a string \"MATCH ...\" from complete-with-snippet, +split it into its constituent parts." + (let* ((match-parts (rustic-racer-split-parts line)) + (docstring (nth 7 match-parts))) + (when (and match-parts (equal (length match-parts) 8)) + (list :name (s-chop-prefix "MATCH " (nth 0 match-parts)) + :line (string-to-number (nth 2 match-parts)) + :column (string-to-number (nth 3 match-parts)) + :path (nth 4 match-parts) + ;; Struct or Function: + :kind (nth 5 match-parts) + :signature (nth 6 match-parts) + :docstring (if (> (length docstring) 0) docstring nil))))) + +;;; Interactive + +;;;###autoload +(defun rustic-racer-describe () + "Show a *Racer Help* buffer for the function or type at point." + (interactive) + (let ((buf (rustic-racer-doc (thing-at-point 'symbol)))) + (if buf + (pop-to-buffer buf) + (user-error "No function or type found at point")))) + +;;; _ +(provide 'rustic-racer) +;;; rustic-racer.el ends here diff --git a/emacs.d/elpa/rustic-20210609.1900/rustic-rustfix.el b/emacs.d/elpa/rustic-20210609.1900/rustic-rustfix.el new file mode 100644 index 0000000..2e44e8f --- /dev/null +++ b/emacs.d/elpa/rustic-20210609.1900/rustic-rustfix.el @@ -0,0 +1,33 @@ +;;; rustic-rustfix.el --- Support for rustfix -*- lexical-binding:t -*- +;;; Commentary: + +;; This library implements support for `rustfix', a tool that applies +;; the suggestions made by `rustc'. + +;;; Code: + +(require 'rustic-cargo) + +(defvar rustic-rustfix-process-name "rustic-rustfix-process" + "Process name for rustfix processes.") + +(defvar rustic-rustfix-buffer-name "*cargo-rustfix*" + "Buffer name for rustfix buffers.") + +(define-derived-mode rustic-rustfix-mode rustic-compilation-mode "rustfix" + :group 'rustic) + +;;;###autoload +(defun rustic-rustfix () + "Run 'cargo fix'." + (interactive) + (let* ((command (list rustic-cargo-bin "fix" "--allow-dirty")) + (err-buf rustic-rustfix-buffer-name) + (proc rustic-rustfix-process-name) + (mode 'rustic-rustfix-mode)) + (rustic-compilation-process-live) + (rustic-compilation-start command (list :buffer err-buf :process proc :mode mode)))) + +;;; _ +(provide 'rustic-rustfix) +;;; rustic-rustfix.el ends here diff --git a/emacs.d/elpa/rustic-20210609.1900/rustic-rustfmt.el b/emacs.d/elpa/rustic-20210609.1900/rustic-rustfmt.el new file mode 100644 index 0000000..921cfdd --- /dev/null +++ b/emacs.d/elpa/rustic-20210609.1900/rustic-rustfmt.el @@ -0,0 +1,301 @@ +;;; rustic-rustfmt.el --- Support for rustfmt -*- lexical-binding:t -*- +;;; Commentary: + +;; This library implements support for `rustfmt', a tool that formats +;; Rust code according to style guidelines. + +;;; Code: + +(require 'rustic-cargo) + +(declare-function project-root "project") + +;;; Options + +(defcustom rustic-rustfmt-bin "rustfmt" + "Path to rustfmt executable." + :type 'string + :group 'rustic) + +(defcustom rustic-rustfmt-config-alist nil + "An alist of (KEY . VAL) pairs that are passed to rustfmt. + +KEY is a symbol that corresponds to a config value of rustfmt. +VALUE is a string, an integer or a boolean." + :type '(alist :key-type symbol + :value-type (choice string integer boolean)) + :group 'rustic) + +(defcustom rustic-format-trigger nil + "Format future rust buffers before saving using rustfmt." + :type '(choice (const :tag "Format buffer before saving." on-save) + (const :tag "Run 'cargo fmt' before compilation." on-compile) + (const :tag "Don't format automatically." nil)) + :group 'rustic) + +(defcustom rustic-format-display-method 'pop-to-buffer + "Default function used for displaying rustfmt buffer." + :type 'function + :group 'rustic) + +;;; _ + +(defvar rustic-format-process-name "rustic-rustfmt-process" + "Process name for rustfmt processes.") + +(defvar rustic-format-buffer-name "*rustfmt*" + "Buffer name for rustfmt process buffers.") + +(defvar rustic-save-pos nil + "Marker, holding location of the cursor's position before +running rustfmt.") + +(defun rustic-format-start-process (sentinel &rest args) + "Run rustfmt with ARGS. + +:buffer BUFFER -- BUFFER is the buffer that is being formatted. + +:stdin STRING -- STRING will be written to the standard input of rustfmt. +When `:files' is non-nil, STRING will be ignored by rustfmt. + +:files FILES -- FILES is a string or list of strings that +specify the input file or files to rustfmt. + +:command COMMAND -- COMMAND is a string or a list of strings. +When COMMAND is non-nil, it replaces the default command. +When COMMAND is a string, it is the program file name. +When COMMAND is a list, it's `car' is the program file name +and it's `cdr' is a list of arguments." + (let* ((err-buf (get-buffer-create rustic-format-buffer-name)) + (inhibit-read-only t) + (dir (rustic-buffer-workspace)) + (buffer (plist-get args :buffer)) + (string (plist-get args :stdin)) + (files (plist-get args :files)) + (files (if (listp files) files (list files))) + (command (or (plist-get args :command) + (cons rustic-rustfmt-bin (rustic-compute-rustfmt-args)))) + (command (if (listp command) command (list command)))) + (setq rustic-save-pos (set-marker (make-marker) (point) (current-buffer))) + (rustic-compilation-setup-buffer err-buf dir 'rustic-format-mode t) + (--each files + (unless (file-exists-p it) + (error (format "File %s does not exist." it)))) + (with-current-buffer err-buf + (let ((proc (rustic-make-process :name rustic-format-process-name + :buffer err-buf + :command `(,@command "--" ,@files) + :filter #'rustic-compilation-filter + :sentinel sentinel))) + (setq next-error-last-buffer buffer) + (when string + (while (not (process-live-p proc)) + (sleep-for 0.01)) + (process-send-string proc (concat string "\n")) + (process-send-eof proc)) + proc)))) + +(defun rustic-compute-rustfmt-args () + "Compute the arguments to rustfmt from `rustic-rustfmt-config-alist'." + (let (args) + (cl-dolist (elem rustic-rustfmt-config-alist args) + (cl-destructuring-bind (key . val) elem + (push (format "%s=%s" key (if (booleanp val) (if val "true" "false") val)) args) + (push "--config" args))))) + +(defun rustic-format-sentinel (proc output) + "Sentinel for rustfmt processes when using stdin." + (ignore-errors + (let ((proc-buffer (process-buffer proc)) + (inhibit-read-only t)) + (with-current-buffer proc-buffer + (if (string-match-p "^finished" output) + (let ((file-buffer next-error-last-buffer) + ;; replace-buffer-contents was in emacs 26.1, but it + ;; was broken for non-ASCII strings, so we need 26.2. + (use-replace (version<= "26.2" emacs-version))) + (unless use-replace + (copy-to-buffer file-buffer (point-min) (point-max))) + (with-current-buffer file-buffer + (if use-replace + (replace-buffer-contents proc-buffer)) + (goto-char rustic-save-pos)) + (kill-buffer proc-buffer) + (message "Formatted buffer with rustfmt.")) + (goto-char (point-min)) + (when-let ((file (buffer-file-name next-error-last-buffer))) + (save-excursion + (save-match-data + (when (search-forward "<stdin>" nil t) + (replace-match file))))) + (with-current-buffer next-error-last-buffer + (goto-char rustic-save-pos)) + (funcall rustic-format-display-method proc-buffer) + (message "Rustfmt error.")))))) + +(defun rustic-format-file-sentinel (proc output) + "Sentinel for rustfmt processes when formatting a file." + (ignore-errors + (let ((proc-buffer (process-buffer proc))) + (with-current-buffer proc-buffer + (if (string-match-p "^finished" output) + (with-current-buffer next-error-last-buffer + (revert-buffer t t)) + (sit-for 0.1) + (with-current-buffer next-error-last-buffer + (goto-char rustic-save-pos)) + (goto-char (point-min)) + (funcall rustic-format-display-method proc-buffer) + (message "Rustfmt error.")))))) + +(define-derived-mode rustic-format-mode rustic-compilation-mode "rustfmt" + :group 'rustic) + +(define-derived-mode rustic-cargo-fmt-mode rustic-compilation-mode "cargo-fmt" + :group 'rustic) + +;;;###autoload +(defun rustic-cargo-fmt () + "Use rustfmt via cargo." + (interactive) + (let ((command (list rustic-cargo-bin "fmt")) + (buffer rustic-format-buffer-name) + (proc rustic-format-process-name) + (mode 'rustic-cargo-fmt-mode)) + (rustic-compilation-process-live) + (rustic-compilation command + (list + :no-display t + :buffer buffer + :process proc + :mode mode + :sentinel #'rustic-cargo-fmt-sentinel)))) + +(defun rustic-cargo-fmt-sentinel (proc output) + "Sentinel for formatting with `rustic-cargo-fmt'." + (let ((proc-buffer (process-buffer proc)) + (inhibit-read-only t)) + (with-current-buffer proc-buffer + (if (not (string-match-p "^finished" output)) + (funcall rustic-compile-display-method proc-buffer) + (when (fboundp rustic-list-project-buffers-function) + (let ((buffers (cl-remove-if-not + #'buffer-file-name + (funcall rustic-list-project-buffers-function)))) + (dolist (b buffers) + (with-current-buffer b + (revert-buffer t t))))) + (kill-buffer proc-buffer) + (message "Workspace formatted with cargo-fmt."))))) + +;;;###autoload +(defun rustic-format-buffer () + "Format the current buffer using rustfmt. + +Provide optional argument NO-STDIN for `rustic-before-save-hook' since there +were issues when using stdin for formatting." + (interactive) + (unless (or (eq major-mode 'rustic-mode) + (eq major-mode 'rustic-macro-expansion-mode)) + (error "Not a rustic-mode buffer.")) + (rustic-compilation-process-live t) + (rustic-format-start-process 'rustic-format-sentinel + :buffer (current-buffer) + :stdin (buffer-string))) + +;;;###autoload +(defun rustic-format-file (&optional file) + "Unlike `rustic-format-buffer' format file directly and revert the buffer." + (interactive "P") + (let* ((buf (current-buffer)) + (file (or (if file (read-from-minibuffer "Format file: ") nil) + (buffer-file-name buf) + (read-from-minibuffer "Format file: "))) + (string (buffer-string))) + (write-region string nil file nil 0) + (let ((proc (rustic-format-start-process 'rustic-format-file-sentinel + :buffer buf + :files file))) + (while (eq (process-status proc) 'run) + (sit-for 0.05))))) + +(defun rustic-project-buffer-list () + "Return a list of the buffers belonging to the current project. +This is basically a wrapper around `project--buffer-list'." + (when-let ((pr (project-current))) + (if (fboundp 'project--buffer-list) + (project--buffer-list pr) + ;; Like the above function but for releases before Emacs 28. + (let ((root (project-root pr)) + bufs) + (dolist (buf (buffer-list)) + (let ((filename (or (buffer-file-name buf) + (buffer-local-value 'default-directory buf)))) + (when (and filename (file-in-directory-p filename root)) + (push buf bufs)))) + (nreverse bufs))))) + +;;; Hooks + +(defun rustic-maybe-format-before-compilation () + (if (eq rustic-format-trigger 'on-compile) + (let ((proc (rustic-cargo-fmt))) + (while (eq (process-status proc) 'run) + (sit-for 0.1)) + (and (not (zerop (process-exit-status proc))) + (funcall rustic-compile-display-method (process-buffer proc)) + t)) + t)) + +(add-hook 'rustic-before-compilation-hook + #'rustic-maybe-format-before-compilation) + +(defun rustic-before-save-hook () + "Don't throw error if rustfmt isn't installed, as it makes saving impossible." + (when (and (rustic-format-on-save-p) + (not (rustic-compilation-process-live t))) + (condition-case nil + (progn + (rustic-format-file) + (sit-for 0.1)) + (error nil)))) + +(defun rustic-after-save-hook () + "Check if rustfmt is installed after saving the file." + (when (rustic-format-on-save-p) + (unless (executable-find rustic-rustfmt-bin) + (error "Could not locate executable \"%s\"" rustic-rustfmt-bin)))) + +(defun rustic-maybe-format-after-save (buffer) + (when (rustic-format-on-save-p) + (let* ((file (buffer-file-name buffer)) + (proc (rustic-format-start-process + 'rustic-format-file-sentinel + :buffer buffer + :files file))) + (while (eq (process-status proc) 'run) + (sit-for 0.1))))) + +(defvar rustic-format-on-save nil + "Format rust buffers before saving using rustfmt.") + +(make-obsolete 'rustic-format-on-save 'rustic-format-trigger "Rustic 0.19") + +(defun rustic-format-on-save-p () + "Return non-nil if formatting should happen when saving. +See option `rustic-format-trigger'. For backward compatibility, +if obsolete `rustic-format-on-save' is non-nil, then also return +non-nil." + (or rustic-format-on-save (eq rustic-format-trigger 'on-save))) + +(defun rustic-save-some-buffers-advice (orig-fun &rest args) + (let ((rustic-format-trigger nil) + (rustic-format-on-save nil)) + (apply orig-fun args))) + +(advice-add 'save-some-buffers :around + #'rustic-save-some-buffers-advice) + +;;; _ +(provide 'rustic-rustfmt) +;;; rustic-rustfmt.el ends here diff --git a/emacs.d/elpa/rustic-20210609.1900/rustic.el b/emacs.d/elpa/rustic-20210609.1900/rustic.el new file mode 100644 index 0000000..e85ee72 --- /dev/null +++ b/emacs.d/elpa/rustic-20210609.1900/rustic.el @@ -0,0 +1,1253 @@ +;;; rustic.el --- Rust development environment -*-lexical-binding: t-*- + +;; Version: 1.3 +;; Author: Mozilla +;; +;; Keywords: languages +;; Package-Requires: ((emacs "26.1") (dash "2.13.0") (f "0.18.2") (let-alist "1.0.4") (markdown-mode "2.3") (project "0.3.0") (s "1.10.0") (seq "2.3") (spinner "1.7.3") (xterm-color "1.6")) + +;; This file is distributed under the terms of both the MIT license and the +;; Apache License (version 2.0). + +;;; Commentary: + +;; This package is a fork of rust-mode. +;; +;; Differences with rust-mode: +;; +;; - rust-analyzer configuration +;; - flycheck integration +;; - cargo popup +;; - multiline error parsing +;; - translation of ANSI control sequences through xterm-color +;; - async org babel +;; - custom compilation process +;; - rustfmt errors in a rust compilation mode +;; - automatic RLS configuration with eglot or lsp-mode +;; - cask for testing +;; - requires emacs 26 +;; - etc. + +;;; Code: + +(require 'cl-lib) +(require 'pcase) +(require 'seq) +(require 'subr-x) + +(require 'dash) + +(eval-when-compile (require 'rx)) + +(defvar electric-pair-inhibit-predicate) +(defvar electric-pair-skip-self) +(defvar electric-indent-chars) + +;;; Customization + +(defgroup rustic nil + "Support for Rust code." + :link '(url-link "https://www.rustic-lang.org/") + :group 'languages) + +(defcustom rustic-indent-offset 4 + "Indent Rust code by this number of spaces." + :type 'integer + :group 'rustic + :safe #'integerp) + +(defcustom rustic-indent-method-chain nil + "Indent Rust method chains, aligned by the `.' operators." + :type 'boolean + :group 'rustic + :safe #'booleanp) + +(defcustom rustic-indent-where-clause nil + "Indent lines starting with the `where' keyword following a function or trait. +When nil, `where' will be aligned with `fn' or `trait'." + :type 'boolean + :group 'rustic + :safe #'booleanp) + +(defcustom rustic-match-angle-brackets t + "Whether to enable angle bracket (`<' and `>') matching where appropriate." + :type 'boolean + :safe #'booleanp + :group 'rustic) + +(defcustom rustic-indent-return-type-to-arguments t + "Indent a line starting with the `->' (RArrow) following a function, aligning +to the function arguments. When nil, `->' will be indented one level." + :type 'boolean + :group 'rustic + :safe #'booleanp) + +;;; Faces + +(define-obsolete-face-alias 'rustic-unsafe-face + 'rustic-unsafe "1.2") +(define-obsolete-face-alias 'rustic-question-mark-face + 'rustic-question-mark "1.2") +(define-obsolete-face-alias 'rustic-builtin-formatting-macro-face + 'rustic-builtin-formatting-macro "1.2") +(define-obsolete-face-alias 'rustic-string-interpolation-face + 'rustic-string-interpolation "1.2") + +(defface rustic-unsafe + '((t :inherit font-lock-warning-face)) + "Face for the `unsafe' keyword." + :group 'rustic) + +(defface rustic-question-mark + '((t :weight bold :inherit font-lock-builtin-face)) + "Face for the question mark operator." + :group 'rustic) + +(defface rustic-builtin-formatting-macro + '((t :inherit font-lock-builtin-face)) + "Face for builtin formatting macros (print! &c.)." + :group 'rustic) + +(defface rustic-string-interpolation + '((t :slant italic :inherit font-lock-string-face)) + "Face for interpolating braces in builtin formatting macro strings." + :group 'rustic) + +;;; Workspace + +(defvar-local rustic--buffer-workspace nil + "Use function `rustic-buffer-workspace' instead.") + +(defun rustic-buffer-workspace (&optional nodefault) + "Return the Rust workspace for the current buffer. +This is the directory containing the file \"Cargo.lock\". When +called outside a Rust project, then return `default-directory', +or if NODEFAULT is non-nil, then fall back to returning nil." + (or rustic--buffer-workspace + (let ((dir (locate-dominating-file default-directory "Cargo.toml"))) + (when dir + (setq dir (expand-file-name dir))) + (setq rustic--buffer-workspace dir) + (or dir + (and (not nodefault) + default-directory))))) + +;;; Syntax + +(defconst rustic-re-ident "[[:word:][:multibyte:]_][[:word:][:multibyte:]_[:digit:]]*") +(defconst rustic-re-lc-ident "[[:lower:][:multibyte:]_][[:word:][:multibyte:]_[:digit:]]*") +(defconst rustic-re-uc-ident "[[:upper:]][[:word:][:multibyte:]_[:digit:]]*") +(defconst rustic-re-vis "pub") +(defconst rustic-re-unsafe "unsafe") +(defconst rustic-re-extern "extern") +(defconst rustic-re-generic + (concat "<[[:space:]]*'" rustic-re-ident "[[:space:]]*>")) +(defconst rustic-re-union + (rx-to-string + `(seq + (or space line-start) + (group symbol-start "union" symbol-end) + (+ space) (regexp ,rustic-re-ident)))) + +(defun rustic-re-shy (inner) (concat "\\(?:" inner "\\)")) +(defun rustic-re-grab (inner) (concat "\\(" inner "\\)")) +(defun rustic-re-item-def (itype) + (concat (rustic-re-word itype) + (rustic-re-shy rustic-re-generic) "?" + "[[:space:]]+" (rustic-re-grab rustic-re-ident))) +(defun rustic-re-word (inner) (concat "\\<" inner "\\>")) + +(defun rustic-re-item-def-imenu (itype) + (concat "^[[:space:]]*" + (rustic-re-shy (concat (rustic-re-word rustic-re-vis) "[[:space:]]+")) "?" + (rustic-re-shy (concat (rustic-re-word "default") "[[:space:]]+")) "?" + (rustic-re-shy (concat (rustic-re-word rustic-re-unsafe) "[[:space:]]+")) "?" + (rustic-re-shy (concat (rustic-re-word rustic-re-extern) "[[:space:]]+" + (rustic-re-shy "\"[^\"]+\"[[:space:]]+") "?")) "?" + (rustic-re-item-def itype))) + +(defvar rustic-imenu-generic-expression + (append (mapcar #'(lambda (x) + (list (capitalize x) (rustic-re-item-def-imenu x) 1)) + '("async fn" "enum" "struct" "union" "type" "mod" "fn" "trait" "impl")) + `(("Macro" ,(rustic-re-item-def-imenu "macro_rules!") 1))) + "Value for `imenu-generic-expression' in Rust mode. + +Create a hierarchical index of the item definitions in a Rust file. + +Imenu will show all the enums, structs, etc. in their own subheading. +Use idomenu (imenu with `ido-mode') for best mileage.") + +(defvar rustic-mode-syntax-table + (let ((table (make-syntax-table))) + + ;; Operators + (dolist (i '(?+ ?- ?* ?/ ?% ?& ?| ?^ ?! ?< ?> ?~ ?@)) + (modify-syntax-entry i "." table)) + + ;; Strings + (modify-syntax-entry ?\" "\"" table) + (modify-syntax-entry ?\\ "\\" table) + + ;; Angle brackets. We suppress this with syntactic propertization + ;; when needed + (modify-syntax-entry ?< "(>" table) + (modify-syntax-entry ?> ")<" table) + + ;; Comments + (modify-syntax-entry ?/ ". 124b" table) + (modify-syntax-entry ?* ". 23n" table) + (modify-syntax-entry ?\n "> b" table) + (modify-syntax-entry ?\^m "> b" table) + + table) + "Syntax definitions and helpers.") + +;;; Mode + +(defvar rustic-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-c C-p") 'rustic-popup) + + (define-key map (kbd "C-c C-c C-u") 'rustic-compile) + (define-key map (kbd "C-c C-c C-i") 'rustic-recompile) + (define-key map (kbd "C-c C-c C-b") 'rustic-cargo-build) + (define-key map (kbd "C-c C-c C-k") 'rustic-cargo-check) + (define-key map (kbd "C-c C-c C-r") 'rustic-cargo-run) + (define-key map (kbd "C-c C-c C-f") 'rustic-cargo-fmt) + (define-key map (kbd "C-c C-c C-t") 'rustic-cargo-test) + (define-key map (kbd "C-c C-c C-c") 'rustic-cargo-current-test) + (define-key map (kbd "C-c C-c C-l") 'rustic-cargo-clippy) + (define-key map (kbd "C-c C-c C-o") 'rustic-format-buffer) + + (define-key map (kbd "C-c C-c C-d") 'rustic-racer-describe) + (define-key map (kbd "C-c C-c C-,") 'rustic-docstring-dwim) + (define-key map (kbd "C-c C-c C-n") 'rustic-cargo-outdated) + map) + "Keymap for Rust major mode.") + +;;;###autoload +(define-derived-mode rustic-mode prog-mode "Rustic" + "Major mode for Rust code. + +\\{rustic-mode-map}" + :group 'rustic + :syntax-table rustic-mode-syntax-table + + ;; Syntax + (setq-local syntax-propertize-function #'rustic-syntax-propertize) + + ;; Indentation + (setq-local indent-line-function 'rustic-indent-line) + + ;; Fonts + (setq-local font-lock-defaults + '(rustic-font-lock-keywords + nil nil nil nil + (font-lock-syntactic-face-function + . rustic-syntactic-face-function))) + + ;; Misc + (setq-local comment-start "// ") + (setq-local comment-end "") + (setq-local open-paren-in-column-0-is-defun-start nil) + + ;; Auto indent on } + (setq-local electric-indent-chars + (cons ?} (and (boundp 'electric-indent-chars) + electric-indent-chars))) + + ;; Allow paragraph fills for comments + (setq-local comment-start-skip "\\(?://[/!]*\\|/\\*[*!]?\\)[[:space:]]*") + (setq-local paragraph-start + (concat "[[:space:]]*\\(?:" + comment-start-skip + "\\|\\*/?[[:space:]]*\\|\\)$")) + (setq-local paragraph-separate paragraph-start) + (setq-local normal-auto-fill-function 'rustic-do-auto-fill) + (setq-local fill-paragraph-function 'rustic-fill-paragraph) + (setq-local fill-forward-paragraph-function 'rustic-fill-forward-paragraph) + (setq-local adaptive-fill-function 'rustic-find-fill-prefix) + (setq-local adaptive-fill-first-line-regexp "") + (setq-local comment-multi-line t) + (setq-local comment-line-break-function 'rustic-comment-indent-new-line) + (setq-local imenu-generic-expression rustic-imenu-generic-expression) + (setq-local imenu-syntax-alist '((?! . "w"))) ; For macro_rules! + (setq-local beginning-of-defun-function 'rustic-beginning-of-defun) + (setq-local end-of-defun-function 'rustic-end-of-defun) + (setq-local parse-sexp-lookup-properties t) + (setq-local electric-pair-inhibit-predicate + 'rustic-electric-pair-inhibit-predicate-wrap) + (setq-local electric-pair-skip-self 'rustic-electric-pair-skip-self-wrap) + + (when (fboundp 'rustic-before-save-hook) + (add-hook 'before-save-hook 'rustic-before-save-hook nil t) + (add-hook 'after-save-hook 'rustic-after-save-hook nil t))) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.rs\\'" . rustic-mode)) + +;; remove rust-mode from `auto-mode-alist' +(let ((mode '("\\.rs\\'" . rust-mode))) + (when (member mode auto-mode-alist) + (setq auto-mode-alist (remove mode auto-mode-alist)))) + +(defvar rustic-top-item-beg-re + (concat "\\s-*\\(?:priv\\|pub\\)?\\s-*" + (regexp-opt + '("enum" "struct" "union" "type" "mod" "use" "fn" "static" "impl" + "extern" "trait" "async")) + "\\_>") + "Start of a Rust item.") + +(defconst rustic-re-type-or-constructor + (rx symbol-start + (group upper (0+ (any word nonascii digit "_"))) + symbol-end)) + +(defconst rustic-keywords + '("as" "async" "await" + "box" "break" + "const" "continue" "crate" + "do" "dyn" + "else" "enum" "extern" "existential" + "false" "fn" "for" + "if" "impl" "in" + "let" "loop" + "match" "mod" "move" "mut" + "priv" "pub" + "ref" "return" + "self" "static" "struct" "super" + "true" "trait" "type" "try" + "use" + "virtual" + "where" "while" + "yield") + "Font-locking definitions and helpers.") + +(defconst rustic-special-types + '("u8" "i8" + "u16" "i16" + "u32" "i32" + "u64" "i64" + "u128" "i128" + + "f32" "f64" + "isize" "usize" + "bool" + "str" "char")) + +(defvar rustic-builtin-formatting-macros + '("eprint" + "eprintln" + "format" + "print" + "println") + "List of builtin Rust macros for string formatting. +This is used by `rust-font-lock-keywords'. +\(`write!' is handled separately).") + +(defvar rustic-formatting-macro-opening-re + "[[:space:]]*[({[][[:space:]]*" + "Regular expression to match the opening delimiter of a Rust formatting macro.") + +(defvar rustic-start-of-string-re + "\\(?:r#*\\)?\"" + "Regular expression to match the start of a Rust raw string.") + +(defun rustic-path-font-lock-matcher (re-ident) + "Match occurrences of RE-IDENT followed by a double-colon. +Examples include to match names like \"foo::\" or \"Foo::\". +Does not match type annotations of the form \"foo::<\"." + `(lambda (limit) + (catch 'rustic-path-font-lock-matcher + (while t + (let* ((symbol-then-colons (rx-to-string '(seq (group (regexp ,re-ident)) "::"))) + (match (re-search-forward symbol-then-colons limit t))) + (cond + ;; If we didn't find a match, there are no more occurrences + ;; of foo::, so return. + ((null match) (throw 'rustic-path-font-lock-matcher nil)) + ;; If this isn't a type annotation foo::<, we've found a + ;; match, so a return it! + ((not (looking-at (rx (0+ space) "<"))) + (throw 'rustic-path-font-lock-matcher match)))))))) + +(defvar rustic-font-lock-keywords + (append + `( + ;; Keywords proper + (,(regexp-opt rustic-keywords 'symbols) . font-lock-keyword-face) + + ;; Contextual keywords + ("\\_<\\(default\\)[[:space:]]+fn\\_>" 1 font-lock-keyword-face) + (,rustic-re-union 1 font-lock-keyword-face) + + ;; Special types + (,(regexp-opt rustic-special-types 'symbols) . font-lock-type-face) + + ;; The unsafe keyword + ("\\_<unsafe\\_>" . 'rustic-unsafe) + + ;; Attributes like `#[bar(baz)]` or `#![bar(baz)]` or `#[bar = "baz"]` + (,(rustic-re-grab (concat "#\\!?\\[" rustic-re-ident "[^]]*\\]")) + 1 font-lock-preprocessor-face keep) + + ;; Builtin formatting macros + (,(concat (rustic-re-grab (concat (regexp-opt rustic-builtin-formatting-macros) "!")) + rustic-formatting-macro-opening-re + rustic-start-of-string-re) + (1 'rustic-builtin-formatting-macro) + (rustic-string-interpolation-matcher + (rustic-end-of-string) + nil + (0 'rustic-string-interpolation t nil))) + + ;; write! macro + (,(concat (rustic-re-grab "write\\(ln\\)?!") + rustic-formatting-macro-opening-re + "[[:space:]]*[^\"]+,[[:space:]]*" + rustic-start-of-string-re) + (1 'rustic-builtin-formatting-macro) + (rustic-string-interpolation-matcher + (rustic-end-of-string) + nil + (0 'rustic-string-interpolation t nil))) + + ;; Syntax extension invocations like `foo!`, highlight including the ! + (,(concat (rustic-re-grab (concat rustic-re-ident "!")) "[({[:space:][]") + 1 font-lock-preprocessor-face) + + ;; Field names like `foo:`, highlight excluding the : + (,(concat (rustic-re-grab rustic-re-ident) ":[^:]") 1 font-lock-variable-name-face) + + ;; CamelCase Means Type Or Constructor + (,rustic-re-type-or-constructor 1 font-lock-type-face) + + ;; Type-inferred binding + (,(concat "\\_<\\(?:let\\s-+ref\\|let\\|ref\\)\\s-+\\(?:mut\\s-+\\)?" + (rustic-re-grab rustic-re-ident) + "\\_>") + 1 font-lock-variable-name-face) + + ;; Type names like `Foo::`, highlight excluding the :: + (,(rustic-path-font-lock-matcher rustic-re-uc-ident) 1 font-lock-type-face) + + ;; Module names like `foo::`, highlight excluding the :: + (,(rustic-path-font-lock-matcher rustic-re-lc-ident) 1 font-lock-constant-face) + + ;; Lifetimes like `'foo` + (,(concat "'" (rustic-re-grab rustic-re-ident) "[^']") 1 font-lock-variable-name-face) + + ;; Question mark operator + ("\\?" . 'rustic-question-mark) + ) + + ;; Ensure we highlight `Foo` in `struct Foo` as a type. + (mapcar #'(lambda (x) + (list (rustic-re-item-def (car x)) + 1 (cdr x))) + '(("enum" . font-lock-type-face) + ("struct" . font-lock-type-face) + ("union" . font-lock-type-face) + ("type" . font-lock-type-face) + ("mod" . font-lock-constant-face) + ("use" . font-lock-constant-face) + ("fn" . font-lock-function-name-face))))) + +(defun rustic-end-of-string () + "Skip to the end of the current string." + (save-excursion + (skip-syntax-forward "^\"|") + (skip-syntax-forward "\"|") + (point))) + +(defun rustic-looking-back-str (str) + "Return non-nil if there's a match on the text before point and STR. +Like `looking-back' but for fixed strings rather than regexps (so +that it's not so slow)." + (let ((len (length str))) + (and (> (point) len) + (equal str (buffer-substring-no-properties (- (point) len) (point)))))) + +(defun rustic-looking-back-symbols (symbols) + "Return non-nil if the point is after a member of SYMBOLS. +SYMBOLS is a list of strings that represent the respective +symbols." + (save-excursion + (let* ((pt-orig (point)) + (beg-of-symbol (progn (forward-thing 'symbol -1) (point))) + (end-of-symbol (progn (forward-thing 'symbol 1) (point)))) + (and + (= end-of-symbol pt-orig) + (member (buffer-substring-no-properties beg-of-symbol pt-orig) + symbols))))) + +(defun rustic-looking-back-ident () + "Non-nil if we are looking backwards at a valid rust identifier." + (let ((beg-of-symbol (save-excursion (forward-thing 'symbol -1) (point)))) + (looking-back rustic-re-ident beg-of-symbol))) + +(defun rustic-looking-back-macro () + "Non-nil if looking back at an ident followed by a ! + +This is stricter than rust syntax which allows a space between +the ident and the ! symbol. If this space is allowed, then we +would also need a keyword check to avoid `if !(condition)` being +seen as a macro." + (if (> (- (point) (point-min)) 1) + (save-excursion + (backward-char) + (and (= ?! (char-after)) + (rustic-looking-back-ident))))) + +;;; Syntax definitions and helpers + +(defun rustic-paren-level () (nth 0 (syntax-ppss))) +(defun rustic-in-str () (nth 3 (syntax-ppss))) +(defun rustic-in-str-or-cmnt () (nth 8 (syntax-ppss))) +(defun rustic-rewind-past-str-cmnt () (goto-char (nth 8 (syntax-ppss)))) + +(defun rustic-rewind-irrelevant () + (let ((continue t)) + (while continue + (let ((starting (point))) + (skip-chars-backward "[:space:]\n") + (when (rustic-looking-back-str "*/") + (backward-char)) + (when (rustic-in-str-or-cmnt) + (rustic-rewind-past-str-cmnt)) + ;; Rewind until the point no longer moves + (setq continue (/= starting (point))))))) + +(defvar-local rustic-macro-scopes nil + "Cache for the scopes calculated by `rustic-macro-scope'. + +This variable can be `let' bound directly or indirectly around +`rustic-macro-scope' as an optimization but should not be otherwise +set.") + +(defun rustic-macro-scope (start end) + "Return the scope of macros in the buffer. + +The return value is a list of (START END) positions in the +buffer. + +If set START and END are optimizations which limit the return +value to scopes which are approximately with this range." + (save-excursion + ;; need to special case macro_rules which has unique syntax + (let ((scope nil) + (start (or start (point-min))) + (end (or end (point-max)))) + (goto-char start) + ;; if there is a start move back to the previous top level, + ;; as any macros before that must have closed by this time. + (let ((top (syntax-ppss-toplevel-pos (syntax-ppss)))) + (when top + (goto-char top))) + (while + (and + ;; The movement below may have moved us passed end, in + ;; which case search-forward will error + (< (point) end) + (search-forward "!" end t)) + (let ((pt (point))) + (cond + ;; in a string or comment is boring, move straight on + ((rustic-in-str-or-cmnt)) + ;; in a normal macro, + ((and (skip-chars-forward " \t\n\r") + (memq (char-after) + '(?\[ ?\( ?\{)) + ;; Check that we have a macro declaration after. + (rustic-looking-back-macro)) + (let ((start (point))) + (ignore-errors (forward-list)) + (setq scope (cons (list start (point)) scope)))) + ;; macro_rules, why, why, why did you not use macro syntax?? + ((save-excursion + ;; yuck -- last test moves point, even if it fails + (goto-char (- pt 1)) + (skip-chars-backward " \t\n\r") + (rustic-looking-back-str "macro_rules")) + (save-excursion + (when (re-search-forward "[[({]" nil t) + (backward-char) + (let ((start (point))) + (ignore-errors (forward-list)) + (setq scope (cons (list start (point)) scope))))))))) + ;; Return 'empty rather than nil, to indicate a buffer with no + ;; macros at all. + (or scope 'empty)))) + +(defun rustic-in-macro (&optional start end) + "Return non-nil when point is within the scope of a macro. + +If START and END are set, minimize the buffer analysis to +approximately this location as an optimization. + +Alternatively, if `rustic-macro-scopes' is a list use the scope +information in this variable. This last is an optimization and +the caller is responsible for ensuring that the data in +`rustic-macro-scopes' is up to date." + (when (> (rustic-paren-level) 0) + (let ((scopes + (or + rustic-macro-scopes + (rustic-macro-scope start end)))) + ;; `rustic-macro-scope' can return the symbol `empty' if the + ;; buffer has no macros at all. + (when (listp scopes) + (seq-some + (lambda (sc) + (and (>= (point) (car sc)) + (< (point) (cadr sc)))) + scopes))))) + +(defun rustic-looking-at-where () + "Return T when looking at the \"where\" keyword." + (and (looking-at-p "\\bwhere\\b") + (not (rustic-in-str-or-cmnt)))) + +(defun rustic-rewind-to-where (&optional limit) + "Rewind the point to the closest occurrence of the \"where\" keyword. +Return T iff a where-clause was found. Does not rewind past +LIMIT when passed, otherwise only stops at the beginning of the +buffer." + (when (re-search-backward "\\bwhere\\b" limit t) + (if (rustic-in-str-or-cmnt) + (rustic-rewind-to-where limit) + t))) + +(defconst rustic-re-pre-expression-operators "[-=!%&*/:<>[{(|.^;}]") + +(defconst rustic-re-special-types (regexp-opt rustic-special-types 'symbols)) + +;;; Font-locking definitions and helpers + +(defun rustic-next-string-interpolation (limit) + "Search forward from point for next Rust interpolation marker before LIMIT. +Set point to the end of the occurrence found, and return match beginning +and end." + (catch 'match + (save-match-data + (save-excursion + (while (search-forward "{" limit t) + (if (eql (char-after (point)) ?{) + (forward-char) + (let ((start (match-beginning 0))) + ;; According to fmt_macros::Parser::next, an opening brace + ;; must be followed by an optional argument and/or format + ;; specifier, then a closing brace. A single closing brace + ;; without a corresponding unescaped opening brace is an + ;; error. We don't need to do anything special with + ;; arguments, specifiers, or errors, so we only search for + ;; the single closing brace. + (when (search-forward "}" limit t) + (throw 'match (list start (point))))))))))) + +(defun rustic-string-interpolation-matcher (limit) + "Match next Rust interpolation marker before LIMIT and set match data if found. +Returns nil if not within a Rust string." + (when (rustic-in-str) + (let ((match (rustic-next-string-interpolation limit))) + (when match + (set-match-data match) + (goto-char (cadr match)) + match)))) + +(defun rustic-syntax-class-before-point () + (when (> (point) 1) + (syntax-class (syntax-after (1- (point)))))) + +(defun rustic-rewind-qualified-ident () + (while (rustic-looking-back-ident) + (backward-sexp) + (when (save-excursion (rustic-rewind-irrelevant) (rustic-looking-back-str "::")) + (rustic-rewind-irrelevant) + (backward-char 2) + (rustic-rewind-irrelevant)))) + +(defun rustic-rewind-type-param-list () + (cond + ((and (rustic-looking-back-str ">") (equal 5 (rustic-syntax-class-before-point))) + (backward-sexp) + (rustic-rewind-irrelevant)) + + ;; We need to be able to back up past the Fn(args) -> RT form as well. If + ;; we're looking back at this, we want to end up just after "Fn". + ((member (char-before) '(?\] ?\) )) + (let* ((is-paren (rustic-looking-back-str ")")) + (dest (save-excursion + (backward-sexp) + (rustic-rewind-irrelevant) + (or + (when (rustic-looking-back-str "->") + (backward-char 2) + (rustic-rewind-irrelevant) + (when (rustic-looking-back-str ")") + (backward-sexp) + (point))) + (and is-paren (point)))))) + (when dest + (goto-char dest)))))) + +(defun rustic-rewind-to-decl-name () + "Return the point at the beginning of the name in a declaration. +I.e. if we are before an ident that is part of a declaration that +can have a where clause, rewind back to just before the name of +the subject of that where clause and return the new point. +Otherwise return nil." + (let* ((ident-pos (point)) + (newpos (save-excursion + (rustic-rewind-irrelevant) + (rustic-rewind-type-param-list) + (cond + ((rustic-looking-back-symbols + '("fn" "trait" "enum" "struct" "union" "impl" "type")) + ident-pos) + + ((equal 5 (rustic-syntax-class-before-point)) + (backward-sexp) + (rustic-rewind-to-decl-name)) + + ((looking-back "[:,'+=]" (1- (point))) + (backward-char) + (rustic-rewind-to-decl-name)) + + ((rustic-looking-back-str "->") + (backward-char 2) + (rustic-rewind-to-decl-name)) + + ((rustic-looking-back-ident) + (rustic-rewind-qualified-ident) + (rustic-rewind-to-decl-name)))))) + (when newpos (goto-char newpos)) + newpos)) + +(defun rustic-is-in-expression-context (token) + "Return t if what comes right after the point is part of an +expression (as opposed to starting a type) by looking at what +comes before. Takes a symbol that roughly indicates what is +after the point. + +This function is used as part of `rustic-is-lt-char-operator' as +part of angle bracket matching, and is not intended to be used +outside of this context." + (save-excursion + (let ((postchar (char-after))) + (rustic-rewind-irrelevant) + ;; A type alias or ascription could have a type param list. Skip backwards past it. + (when (member token '(ambiguous-operator open-brace)) + (rustic-rewind-type-param-list)) + (cond + + ;; Certain keywords always introduce expressions + ((rustic-looking-back-symbols '("if" "while" "match" "return" "box" "in")) t) + + ;; "as" introduces a type + ((rustic-looking-back-symbols '("as")) nil) + + ;; An open angle bracket never introduces expression context WITHIN the angle brackets + ((and (equal token 'open-brace) (equal postchar ?<)) nil) + + ;; An ident! followed by an open brace is a macro invocation. Consider + ;; it to be an expression. + ((and (equal token 'open-brace) (rustic-looking-back-macro)) t) + + ;; In a brace context a "]" introduces an expression. + ((and (eq token 'open-brace) (rustic-looking-back-str "]"))) + + ;; An identifier is right after an ending paren, bracket, angle bracket + ;; or curly brace. It's a type if the last sexp was a type. + ((and (equal token 'ident) (equal 5 (rustic-syntax-class-before-point))) + (backward-sexp) + (rustic-is-in-expression-context 'open-brace)) + + ;; If a "for" appears without a ; or { before it, it's part of an + ;; "impl X for y", so the y is a type. Otherwise it's + ;; introducing a loop, so the y is an expression + ((and (equal token 'ident) (rustic-looking-back-symbols '("for"))) + (backward-sexp) + (rustic-rewind-irrelevant) + (looking-back "[{;]" (1- (point)))) + + ((rustic-looking-back-ident) + (rustic-rewind-qualified-ident) + (rustic-rewind-irrelevant) + (cond + ((equal token 'open-brace) + ;; We now know we have: + ;; ident <maybe type params> [{([] + ;; where [{([] denotes either a {, ( or [. + ;; This character is bound as postchar. + (cond + ;; If postchar is a paren or square bracket, then if the + ;; brace is a type if the identifier is one + ((member postchar '(?\( ?\[ )) (rustic-is-in-expression-context 'ident)) + + ;; If postchar is a curly brace, the brace can only be a type if + ;; ident2 is the name of an enum, struct or trait being declared. + ;; Note that if there is a -> before the ident then the ident would + ;; be a type but the { is not. + ((equal ?{ postchar) + (not (and (rustic-rewind-to-decl-name) + (progn + (rustic-rewind-irrelevant) + (rustic-looking-back-symbols + '("enum" "struct" "union" "trait" "type")))))))) + + ((equal token 'ambiguous-operator) + (cond + ;; An ampersand after an ident has to be an operator rather + ;; than a & at the beginning of a ref type + ((equal postchar ?&) t) + + ;; A : followed by a type then an = introduces an + ;; expression (unless it is part of a where clause of a + ;; "type" declaration) + ((and (equal postchar ?=) + (looking-back "[^:]:" (- (point) 2)) + (not (save-excursion + (and (rustic-rewind-to-decl-name) + (progn (rustic-rewind-irrelevant) + (rustic-looking-back-symbols '("type")))))))) + + ;; "let ident =" introduces an expression--and so does "const" and "mut" + ((and (equal postchar ?=) (rustic-looking-back-symbols '("let" "const" "mut"))) t) + + ;; As a specific special case, see if this is the = in this situation: + ;; enum EnumName<type params> { Ident = + ;; In this case, this is a c-like enum and despite Ident + ;; representing a type, what comes after the = is an expression + ((and + (> (rustic-paren-level) 0) + (save-excursion + (backward-up-list) + (rustic-rewind-irrelevant) + (rustic-rewind-type-param-list) + (and + (rustic-looking-back-ident) + (progn + (rustic-rewind-qualified-ident) + (rustic-rewind-irrelevant) + (rustic-looking-back-str "enum"))))) + t) + + ;; Otherwise the ambiguous operator is a type if the identifier is a type + ((rustic-is-in-expression-context 'ident) t))) + + ((equal token 'colon) + (cond + ;; If we see a ident: not inside any braces/parens, we're at top level. + ;; There are no allowed expressions after colons there, just types. + ((<= (rustic-paren-level) 0) nil) + + ;; We see ident: inside a list + ((looking-back "[{,]" (1- (point))) + (backward-up-list) + + ;; If a : appears whose surrounding paren/brackets/braces are + ;; anything other than curly braces, it can't be a field + ;; initializer and must be denoting a type. + (when (looking-at "{") + (rustic-rewind-irrelevant) + (rustic-rewind-type-param-list) + (when (rustic-looking-back-ident) + ;; We have a context that looks like this: + ;; ident2 <maybe type params> { [maybe paren-balanced code ending in comma] ident1: + ;; the point is sitting just after ident2, and we trying to + ;; figure out if the colon introduces an expression or a type. + ;; The answer is that ident1 is a field name, and what comes + ;; after the colon is an expression, if ident2 is an + ;; expression. + (rustic-rewind-qualified-ident) + (rustic-is-in-expression-context 'ident)))) + + ;; Otherwise, if the ident: appeared with anything other than , or { + ;; before it, it can't be part of a struct initializer and therefore + ;; must be denoting a type. + (t nil))))) + + ;; An operator-like character after a string is indeed an operator + ((and (equal token 'ambiguous-operator) + (member (rustic-syntax-class-before-point) '(5 7 15))) t) + + ;; A colon that has something other than an identifier before it is a + ;; type ascription + ((equal token 'colon) nil) + + ;; A :: introduces a type (or module, but not an expression in any case) + ((rustic-looking-back-str "::") nil) + + ((rustic-looking-back-str ":") + (backward-char) + (rustic-is-in-expression-context 'colon)) + + ;; A -> introduces a type + ((rustic-looking-back-str "->") nil) + + ;; If we are up against the beginning of a list, or after a comma inside + ;; of one, back up out of it and check what the list itself is + ((or + (equal 4 (rustic-syntax-class-before-point)) + (rustic-looking-back-str ",")) + (condition-case nil + (progn + (backward-up-list) + (rustic-is-in-expression-context 'open-brace)) + (scan-error nil))) + + ;; A => introduces an expression + ((rustic-looking-back-str "=>") t) + + ;; A == introduces an expression + ((rustic-looking-back-str "==") t) + + ;; These operators can introduce expressions or types + ((looking-back "[-+=!?&*]" (1- (point))) + (backward-char) + (rustic-is-in-expression-context 'ambiguous-operator)) + + ;; These operators always introduce expressions. (Note that if this + ;; regexp finds a < it must not be an angle bracket, or it'd + ;; have been caught in the syntax-class check above instead of this.) + ((looking-back rustic-re-pre-expression-operators (1- (point))) t))))) + +(defun rustic-is-lt-char-operator () + "Return non-nil if the `<' sign just after point is an operator. +Otherwise, if it is an opening angle bracket, then return nil." + (let ((case-fold-search nil)) + (save-excursion + (rustic-rewind-irrelevant) + ;; We are now just after the character syntactically before the <. + (cond + + ;; If we are looking back at a < that is not an angle bracket (but not + ;; two of them) then this is the second < in a bit shift operator + ((and (rustic-looking-back-str "<") + (not (equal 4 (rustic-syntax-class-before-point))) + (not (rustic-looking-back-str "<<")))) + + ;; On the other hand, if we are after a closing paren/brace/bracket it + ;; can only be an operator, not an angle bracket. Likewise, if we are + ;; after a string it's an operator. (The string case could actually be + ;; valid in rust for character literals.) + ((member (rustic-syntax-class-before-point) '(5 7 15)) t) + + ;; If we are looking back at an operator, we know that we are at + ;; the beginning of an expression, and thus it has to be an angle + ;; bracket (starting a "<Type as Trait>::" construct.) + ((looking-back rustic-re-pre-expression-operators (1- (point))) nil) + + ;; If we are looking back at a keyword, it's an angle bracket + ;; unless that keyword is "self", "true" or "false" + ((rustic-looking-back-symbols rustic-keywords) + (rustic-looking-back-symbols '("self" "true" "false"))) + + ((rustic-looking-back-str "?") + (rustic-is-in-expression-context 'ambiguous-operator)) + + ;; If we're looking back at an identifier, this depends on whether + ;; the identifier is part of an expression or a type + ((rustic-looking-back-ident) + (backward-sexp) + (or + ;; The special types can't take type param lists, so a < after one is + ;; always an operator + (looking-at rustic-re-special-types) + + (rustic-is-in-expression-context 'ident))) + + ;; Otherwise, assume it's an angle bracket + )))) + +(defun rustic-electric-pair-inhibit-predicate-wrap (char) + "Prevent \"matching\" with a `>' when CHAR is the less-than operator. +This wraps the default defined by `electric-pair-inhibit-predicate'." + (or + (when (= ?< char) + (save-excursion + (backward-char) + (rustic-is-lt-char-operator))) + (funcall (default-value 'electric-pair-inhibit-predicate) char))) + +(defun rustic-electric-pair-skip-self-wrap (char) + "Skip CHAR instead of inserting a second closing character. +This wraps the default defined by `electric-pair-skip-self'." + (or + (= ?> char) + (funcall (default-value 'electric-pair-skip-self) char))) + +(defun rustic-ordinary-lt-gt-p () + "Test whether the `<' or `>' at point is an ordinary operator of some kind. + +This returns t if the `<' or `>' is an ordinary operator (like +less-than) or part of one (like `->'); and nil if the character +should be considered a paired angle bracket." + (cond + ;; If matching is turned off suppress all of them + ((not rustic-match-angle-brackets) t) + + ;; This is a cheap check so we do it early. + ;; Don't treat the > in -> or => as an angle bracket + ((and (= (following-char) ?>) (memq (preceding-char) '(?- ?=))) t) + + ;; We don't take < or > in strings or comments to be angle brackets + ((rustic-in-str-or-cmnt) t) + + ;; Inside a macro we don't really know the syntax. Any < or > may be an + ;; angle bracket or it may not. But we know that the other braces have + ;; to balance regardless of the < and >, so if we don't treat any < or > + ;; as angle brackets it won't mess up any paren balancing. + ((rustic-in-macro) t) + + ((looking-at "<") + (rustic-is-lt-char-operator)) + + ((looking-at ">") + (cond + ;; Don't treat the > in -> or => as an angle bracket + ((member (char-before (point)) '(?- ?=)) t) + + ;; If we are at top level and not in any list, it can't be a closing + ;; angle bracket + ((>= 0 (rustic-paren-level)) t) + + ;; Otherwise, treat the > as a closing angle bracket if it would + ;; match an opening one + ((save-excursion + (backward-up-list) + (not (looking-at "<")))))))) + +(defun rustic-syntactic-face-function (state) + "Return face that distinguishes doc and normal comments in given syntax STATE." + (if (nth 3 state) + 'font-lock-string-face + (save-excursion + (goto-char (nth 8 state)) + (if (looking-at "/\\([*][*!][^*!]\\|/[/!][^/!]\\)") + 'font-lock-doc-face + 'font-lock-comment-face)))) + +(eval-and-compile + (defconst rustic--char-literal-rx + (rx (seq + (group "'") + (or + (seq + "\\" + (or + (: "u{" (** 1 6 xdigit) "}") + (: "x" (= 2 xdigit)) + (any "'nrt0\"\\"))) + (not (any "'\\"))) + (group "'"))) + "A regular expression matching a character literal.")) + +(defun rustic--syntax-propertize-raw-string (str-start end) + "A helper for rustic-syntax-propertize. + +This will apply the appropriate string syntax to the character +from the STR-START up to the end of the raw string, or to END, +whichever comes first." + (when (save-excursion + (goto-char str-start) + (looking-at "r\\(#*\\)\\(\"\\)")) + ;; In a raw string, so try to find the end. + (let ((hashes (match-string 1))) + ;; Match \ characters at the end of the string to suppress + ;; their normal character-quote syntax. + (when (re-search-forward (concat "\\(\\\\*\\)\\(\"" hashes "\\)") end t) + (put-text-property (match-beginning 1) (match-end 1) + 'syntax-table (string-to-syntax "_")) + (put-text-property (1- (match-end 2)) (match-end 2) + 'syntax-table (string-to-syntax "|")) + (goto-char (match-end 0)))))) + +(defun rustic-syntax-propertize (start end) + "A `syntax-propertize-function' to apply properties from START to END." + (let ((rustic-macro-scopes (rustic-macro-scope start end))) + (goto-char start) + (let ((str-start (rustic-in-str-or-cmnt))) + (when str-start + (rustic--syntax-propertize-raw-string str-start end))) + (funcall + (syntax-propertize-rules + ;; Character literals. + (rustic--char-literal-rx (1 "\"") (2 "\"")) + ;; Raw strings. + ("\\(r\\)#*\"" + (0 (ignore + (goto-char (match-end 0)) + (unless (save-excursion (nth 8 (syntax-ppss (match-beginning 0)))) + (put-text-property (match-beginning 1) (match-end 1) + 'syntax-table (string-to-syntax "|")) + (rustic--syntax-propertize-raw-string (match-beginning 0) end))))) + ("[<>]" + (0 (ignore + (when (save-match-data + (save-excursion + (goto-char (match-beginning 0)) + (rustic-ordinary-lt-gt-p))) + (put-text-property (match-beginning 0) (match-end 0) + 'syntax-table (string-to-syntax ".")) + (goto-char (match-end 0))))))) + (point) end))) + +(defun rustic-fill-prefix-for-comment-start (line-start) + "Determine what to use for `fill-prefix' based on the text at LINE-START." + (let ((result + ;; Replace /* with same number of spaces + (replace-regexp-in-string + "\\(?:/\\*+?\\)[!*]?" + (lambda (s) + ;; We want the * to line up with the first * of the + ;; comment start + (let ((offset (if (eq t + (compare-strings "/*" nil nil + s + (- (length s) 2) + (length s))) + 1 2))) + (concat (make-string (- (length s) offset) + ?\x20) "*"))) + line-start))) + ;; Make sure we've got at least one space at the end + (if (not (= (aref result (- (length result) 1)) ?\x20)) + (setq result (concat result " "))) + result)) + +(defun rustic-in-comment-paragraph (body) + ;; We might move the point to fill the next comment, but we don't want it + ;; seeming to jump around on the user + (save-excursion + ;; If we're outside of a comment, with only whitespace and then a comment + ;; in front, jump to the comment and prepare to fill it. + (when (not (nth 4 (syntax-ppss))) + (beginning-of-line) + (when (looking-at (concat "[[:space:]\n]*" comment-start-skip)) + (goto-char (match-end 0)))) + + ;; We need this when we're moving the point around and then checking syntax + ;; while doing paragraph fills, because the cache it uses isn't always + ;; invalidated during this. + (syntax-ppss-flush-cache 1) + ;; If we're at the beginning of a comment paragraph with nothing but + ;; whitespace til the next line, jump to the next line so that we use the + ;; existing prefix to figure out what the new prefix should be, rather than + ;; inferring it from the comment start. + (let ((next-bol (line-beginning-position 2))) + (while (save-excursion + (end-of-line) + (syntax-ppss-flush-cache 1) + (and (nth 4 (syntax-ppss)) + (save-excursion + (beginning-of-line) + (looking-at paragraph-start)) + (looking-at "[[:space:]]*$") + (nth 4 (syntax-ppss next-bol)))) + (goto-char next-bol))) + + (syntax-ppss-flush-cache 1) + ;; If we're on the last line of a multiline-style comment that started + ;; above, back up one line so we don't mistake the * of the */ that ends + ;; the comment for a prefix. + (when (save-excursion + (and (nth 4 (syntax-ppss (line-beginning-position 1))) + (looking-at "[[:space:]]*\\*/"))) + (goto-char (line-end-position 0))) + (funcall body))) + +(defun rustic-with-comment-fill-prefix (body) + (let* + ((line-string (buffer-substring-no-properties + (line-beginning-position) (line-end-position))) + (line-comment-start + (when (nth 4 (syntax-ppss)) + (cond + ;; If we're inside the comment and see a * prefix, use it + ((string-match "^\\([[:space:]]*\\*+[[:space:]]*\\)" + line-string) + (match-string 1 line-string)) + ;; If we're at the start of a comment, figure out what prefix + ;; to use for the subsequent lines after it + ((string-match (concat "[[:space:]]*" comment-start-skip) line-string) + (rustic-fill-prefix-for-comment-start + (match-string 0 line-string)))))) + (fill-prefix + (or line-comment-start + fill-prefix))) + (funcall body))) + +(defun rustic-find-fill-prefix () + (rustic-in-comment-paragraph + (lambda () + (rustic-with-comment-fill-prefix + (lambda () + fill-prefix))))) + +(defun rustic-fill-paragraph (&rest args) + "Special wrapping for `fill-paragraph'. +This handles multi-line comments with a * prefix on each line." + (rustic-in-comment-paragraph + (lambda () + (rustic-with-comment-fill-prefix + (lambda () + (let + ((fill-paragraph-function + (if (not (eq fill-paragraph-function 'rustic-fill-paragraph)) + fill-paragraph-function)) + (fill-paragraph-handle-comment t)) + (apply 'fill-paragraph args) + t)))))) + +(defun rustic-do-auto-fill (&rest args) + "Special wrapping for `do-auto-fill'. +This handles multi-line comments with a * prefix on each line." + (rustic-with-comment-fill-prefix + (lambda () + (apply 'do-auto-fill args) + t))) + +(defun rustic-fill-forward-paragraph (arg) + ;; This is to work around some funny behavior when a paragraph separator is + ;; at the very top of the file and there is a fill prefix. + (let ((fill-prefix nil)) (forward-paragraph arg))) + +(defun rustic-comment-indent-new-line (&optional arg) + (rustic-with-comment-fill-prefix + (lambda () (comment-indent-new-line arg)))) + +;;; _ + +(defun rustic-reload () + "Reload rustic package." + (interactive) + (unload-feature 'rustic) + (require 'rustic) + (rustic-mode)) + +(provide 'rustic) + +(require 'rustic-interaction) + +(defvar rustic-load-optional-libraries t + "Whether loading `rustic' also loads optional libraries. +This variable might soon be remove again.") + +(when rustic-load-optional-libraries + (require 'rustic-compile) + (require 'rustic-popup) + (require 'rustic-cargo) + (require 'rustic-babel) + (require 'rustic-racer) + (require 'rustic-rustfmt) + (require 'rustic-rustfix) + (require 'rustic-playpen) + (require 'rustic-lsp) + (with-eval-after-load 'flycheck + (require 'rustic-flycheck))) + +;;; rustic.el ends here diff --git a/emacs.d/elpa/spinner-1.7.4.signed b/emacs.d/elpa/spinner-1.7.4.signed new file mode 100644 index 0000000..0771088 --- /dev/null +++ b/emacs.d/elpa/spinner-1.7.4.signed @@ -0,0 +1 @@ +Good signature from 066DAFCB81E42C40 GNU ELPA Signing Agent (2019) <elpasign@elpa.gnu.org> (trust undefined) created at 2021-07-02T12:10:02+0300 using RSA
\ No newline at end of file diff --git a/emacs.d/elpa/spinner-1.7.4/README.org b/emacs.d/elpa/spinner-1.7.4/README.org new file mode 100644 index 0000000..06c7b32 --- /dev/null +++ b/emacs.d/elpa/spinner-1.7.4/README.org @@ -0,0 +1,76 @@ +#+TITLE: spinner.el + +Add spinners and progress-bars to the mode-line for ongoing operations. + +[[file:some-spinners.gif]] + +[[file:all-spinners.gif]] + +* Usage + +First of all, don’t forget to add ~(spinner "VERSION")~ to your package’s dependencies. + +** Major-modes +1. Just call ~(spinner-start)~ and a spinner will be added to the mode-line. +2. Call ~(spinner-stop)~ on the same buffer when you want to remove it. + +The default spinner is a line drawing that rotates. You can pass an +argument to ~spinner-start~ to specify which spinner you want. All +possibilities are listed in the ~spinner-types~ variable, but here are +a few examples for you to try: + +- ~(spinner-start 'vertical-breathing 10)~ +- ~(spinner-start 'minibox)~ +- ~(spinner-start 'moon)~ +- ~(spinner-start 'triangle)~ + +You can also define your own as a vector of strings (see the examples +in ~spinner-types~). + +** Minor-modes +Minor-modes can create a spinner with ~spinner-create~ and then add it +to their mode-line lighter. They can then start the spinner by setting +a variable and calling ~spinner-start-timer~. Finally, they can stop +the spinner (and the timer) by just setting the same variable to nil. + +Here’s an example for a minor-mode named ~foo~. Assuming that +~foo--lighter~ is used as the mode-line lighter, the following code +will add an *inactive* global spinner to the mode-line. +#+begin_src emacs-lisp +(defvar foo--spinner (spinner-create 'rotating-line)) +(defconst foo--lighter + '(" foo" (:eval (spinner-print foo--spinner)))) +#+end_src + +1. To activate the spinner, just call ~(spinner-start foo--spinner)~. + It will show up on the mode-line and start animating. +2. To get rid of it, call ~(spinner-stop foo--spinner)~. It will then + disappear again. + +Some minor-modes will need spinners to be buffer-local. To achieve +that, just make the ~foo--spinner~ variable buffer-local and use the +third argument of the ~spinner-create~ function. The snippet below is an example. + +#+begin_src emacs-lisp +(defvar-local foo--spinner nil) +(defconst foo--lighter + '(" foo" (:eval (spinner-print foo--spinner)))) +(defun foo--start-spinner () + "Create and start a spinner on this buffer." + (unless foo--spinner + (setq foo--spinner (spinner-create 'moon t))) + (spinner-start foo--spinner)) +#+end_src + +1. To activate the spinner, just call ~(foo--start-spinner)~. +2. To get rid of it, call ~(spinner-stop foo--spinner)~. + +This will use the ~moon~ spinner, but you can use any of the names +defined in the ~spinner-types~ variable or even define your own. + +* Extra options + +Both ~spinner-start~ and ~spinner-create~ take extra options to configure the spinner, these are: + +- ~FPS~: The number of frames to display per second. Defaults to ~spinner-frames-per-second~. +- ~DELAY~: After starting a spinner, it still won’t be displayed for this many seconds. diff --git a/emacs.d/elpa/spinner-1.7.4/all-spinners.gif b/emacs.d/elpa/spinner-1.7.4/all-spinners.gif Binary files differnew file mode 100644 index 0000000..5540b68 --- /dev/null +++ b/emacs.d/elpa/spinner-1.7.4/all-spinners.gif diff --git a/emacs.d/elpa/spinner-1.7.4/some-spinners.gif b/emacs.d/elpa/spinner-1.7.4/some-spinners.gif Binary files differnew file mode 100644 index 0000000..a8028e7 --- /dev/null +++ b/emacs.d/elpa/spinner-1.7.4/some-spinners.gif diff --git a/emacs.d/elpa/spinner-1.7.4/spinner-autoloads.el b/emacs.d/elpa/spinner-1.7.4/spinner-autoloads.el new file mode 100644 index 0000000..a6cc99a --- /dev/null +++ b/emacs.d/elpa/spinner-1.7.4/spinner-autoloads.el @@ -0,0 +1,77 @@ +;;; spinner-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "spinner" "spinner.el" (0 0 0 0)) +;;; Generated autoloads from spinner.el + +(autoload 'spinner-create "spinner" "\ +Create a spinner of the given TYPE. +The possible TYPEs are described in `spinner--type-to-frames'. + +FPS, if given, is the number of desired frames per second. +Default is `spinner-frames-per-second'. + +If BUFFER-LOCAL is non-nil, the spinner will be automatically +deactivated if the buffer is killed. If BUFFER-LOCAL is a +buffer, use that instead of current buffer. + +When started, in order to function properly, the spinner runs a +timer which periodically calls `force-mode-line-update' in the +current buffer. If BUFFER-LOCAL was set at creation time, then +`force-mode-line-update' is called in that buffer instead. When +the spinner is stopped, the timer is deactivated. + +DELAY, if given, is the number of seconds to wait after starting +the spinner before actually displaying it. It is safe to cancel +the spinner before this time, in which case it won't display at +all. + +\(fn &optional TYPE BUFFER-LOCAL FPS DELAY)" nil nil) + +(autoload 'spinner-start "spinner" "\ +Start a mode-line spinner of given TYPE-OR-OBJECT. +If TYPE-OR-OBJECT is an object created with `make-spinner', +simply activate it. This method is designed for minor modes, so +they can use the spinner as part of their lighter by doing: + '(:eval (spinner-print THE-SPINNER)) +To stop this spinner, call `spinner-stop' on it. + +If TYPE-OR-OBJECT is anything else, a buffer-local spinner is +created with this type, and it is displayed in the +`mode-line-process' of the buffer it was created it. Both +TYPE-OR-OBJECT and FPS are passed to `make-spinner' (which see). +To stop this spinner, call `spinner-stop' in the same buffer. + +Either way, the return value is a function which can be called +anywhere to stop this spinner. You can also call `spinner-stop' +in the same buffer where the spinner was created. + +FPS, if given, is the number of desired frames per second. +Default is `spinner-frames-per-second'. + +DELAY, if given, is the number of seconds to wait until actually +displaying the spinner. It is safe to cancel the spinner before +this time, in which case it won't display at all. + +\(fn &optional TYPE-OR-OBJECT FPS DELAY)" nil nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "spinner" '("spinner-"))) + +;;;*** + +;;;### (autoloads nil nil ("spinner-pkg.el") (0 0 0 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; spinner-autoloads.el ends here diff --git a/emacs.d/elpa/spinner-1.7.4/spinner-pkg.el b/emacs.d/elpa/spinner-1.7.4/spinner-pkg.el new file mode 100644 index 0000000..2f4bbb7 --- /dev/null +++ b/emacs.d/elpa/spinner-1.7.4/spinner-pkg.el @@ -0,0 +1,2 @@ +;; Generated package description from spinner.el -*- no-byte-compile: t -*- +(define-package "spinner" "1.7.4" "Add spinners and progress-bars to the mode-line for ongoing operations" '((emacs "24.3")) :keywords '("processes" "mode-line") :authors '(("Artur Malabarba" . "emacs@endlessparentheses.com")) :maintainer '("Artur Malabarba" . "emacs@endlessparentheses.com") :url "https://github.com/Malabarba/spinner.el") diff --git a/emacs.d/elpa/spinner-1.7.4/spinner.el b/emacs.d/elpa/spinner-1.7.4/spinner.el new file mode 100644 index 0000000..6be8f13 --- /dev/null +++ b/emacs.d/elpa/spinner-1.7.4/spinner.el @@ -0,0 +1,340 @@ +;;; spinner.el --- Add spinners and progress-bars to the mode-line for ongoing operations -*- lexical-binding: t; -*- + +;; Copyright (C) 2015 Free Software Foundation, Inc. + +;; Author: Artur Malabarba <emacs@endlessparentheses.com> +;; Version: 1.7.4 +;; Package-Requires: ((emacs "24.3")) +;; URL: https://github.com/Malabarba/spinner.el +;; Keywords: processes mode-line + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: +;; +;; 1 Usage +;; â•â•â•â•â•â•â• +;; +;; First of all, don’t forget to add `(spinner "VERSION")' to your +;; package’s dependencies. +;; +;; +;; 1.1 Major-modes +;; ─────────────── +;; +;; 1. Just call `(spinner-start)' and a spinner will be added to the +;; mode-line. +;; 2. Call `(spinner-stop)' on the same buffer when you want to remove +;; it. +;; +;; The default spinner is a line drawing that rotates. You can pass an +;; argument to `spinner-start' to specify which spinner you want. All +;; possibilities are listed in the `spinner-types' variable, but here are +;; a few examples for you to try: +;; +;; • `(spinner-start 'vertical-breathing 10)' +;; • `(spinner-start 'minibox)' +;; • `(spinner-start 'moon)' +;; • `(spinner-start 'triangle)' +;; +;; You can also define your own as a vector of strings (see the examples +;; in `spinner-types'). +;; +;; +;; 1.2 Minor-modes +;; ─────────────── +;; +;; Minor-modes can create a spinner with `spinner-create' and then add it +;; to their mode-line lighter. They can then start the spinner by setting +;; a variable and calling `spinner-start-timer'. Finally, they can stop +;; the spinner (and the timer) by just setting the same variable to nil. +;; +;; Here’s an example for a minor-mode named `foo'. Assuming that +;; `foo--lighter' is used as the mode-line lighter, the following code +;; will add an *inactive* global spinner to the mode-line. +;; ┌──── +;; │ (defvar foo--spinner (spinner-create 'rotating-line)) +;; │ (defconst foo--lighter +;; │ '(" foo" (:eval (spinner-print foo--spinner)))) +;; └──── +;; +;; 1. To activate the spinner, just call `(spinner-start foo--spinner)'. +;; It will show up on the mode-line and start animating. +;; 2. To get rid of it, call `(spinner-stop foo--spinner)'. It will then +;; disappear again. +;; +;; Some minor-modes will need spinners to be buffer-local. To achieve +;; that, just make the `foo--spinner' variable buffer-local and use the +;; third argument of the `spinner-create' function. The snippet below is an +;; example. +;; +;; ┌──── +;; │ (defvar-local foo--spinner nil) +;; │ (defconst foo--lighter +;; │ '(" foo" (:eval (spinner-print foo--spinner)))) +;; │ (defun foo--start-spinner () +;; │ "Create and start a spinner on this buffer." +;; │ (unless foo--spinner +;; │ (setq foo--spinner (spinner-create 'moon t))) +;; │ (spinner-start foo--spinner)) +;; └──── +;; +;; 1. To activate the spinner, just call `(foo--start-spinner)'. +;; 2. To get rid of it, call `(spinner-stop foo--spinner)'. +;; +;; This will use the `moon' spinner, but you can use any of the names +;; defined in the `spinner-types' variable or even define your own. + + +;;; Code: +(eval-when-compile + (require 'cl-lib)) + +(defconst spinner-types + '((3-line-clock . ["┤" "┘" "â”´" "â””" "├" "┌" "┬" "â”"]) + (2-line-clock . ["┘" "â””" "┌" "â”"]) + (flipping-line . ["_" "\\" "|" "/"]) + (rotating-line . ["-" "\\" "|" "/"]) + (progress-bar . ["[ ]" "[= ]" "[== ]" "[=== ]" "[====]" "[ ===]" "[ ==]" "[ =]"]) + (progress-bar-filled . ["| |" "|â–ˆ |" "|██ |" "|███ |" "|████|" "| ███|" "| ██|" "| â–ˆ|"]) + (vertical-breathing . ["â–" "â–‚" "â–ƒ" "â–„" "â–…" "â–†" "â–‡" "â–ˆ" "â–‡" "â–†" "â–…" "â–„" "â–ƒ" "â–‚" "â–" " "]) + (vertical-rising . ["â–" "â–„" "â–ˆ" "â–€" "â–”"]) + (horizontal-breathing . [" " "â–" "â–Ž" "â–" "â–Œ" "â–‹" "â–Š" "â–‰" "â–‰" "â–Š" "â–‹" "â–Œ" "â–" "â–Ž" "â–"]) + (horizontal-breathing-long + . [" " "â–Ž " "â–Œ " "â–Š " "â–ˆ " "█▎" "█▌" "█▊" "██" "█▊" "█▌" "█▎" "â–ˆ " "â–Š " "â–‹ " "â–Œ " "â– " "â–Ž " "â– "]) + (horizontal-moving . [" " "â–Œ " "â–ˆ " "â–â–Œ" " â–ˆ" " â–"]) + (minibox . ["â––" "â–˜" "â–" "â–—"]) + (triangle . ["â—¢" "â—£" "â—¤" "â—¥"]) + (box-in-box . ["â—°" "â—³" "â—²" "â—±"]) + (box-in-circle . ["â—´" "â—·" "â—¶" "â—µ"]) + (half-circle . ["â—" "â—“" "â—‘" "â—’"]) + (moon . ["🌑" "🌘" "🌗" "🌖" "🌕" "🌔" "🌓" "🌒"])) + "Predefined alist of spinners. +Each car is a symbol identifying the spinner, and each cdr is a +vector, the spinner itself.") + +(defun spinner-make-progress-bar (width &optional char) + "Return a vector of strings of the given WIDTH. +The vector is a valid spinner type and is similar to the +`progress-bar' spinner, except without the surrounding brackets. +CHAR is the character to use for the moving bar (defaults to =)." + (let ((whole-string (concat (make-string (1- width) ?\s) + (make-string 4 (or char ?=)) + (make-string width ?\s)))) + (apply #'vector (mapcar (lambda (n) (substring whole-string n (+ n width))) + (number-sequence (+ width 3) 0 -1))))) + +(defvar spinner-current nil + "Spinner currently being displayed on the `mode-line-process'.") +(make-variable-buffer-local 'spinner-current) + +(defconst spinner--mode-line-construct + '(:eval (spinner-print spinner-current)) + "Construct used to display a spinner in `mode-line-process'.") +(put 'spinner--mode-line-construct 'risky-local-variable t) + +(defvar spinner-frames-per-second 10 + "Default speed at which spinners spin, in frames per second. +Each spinner can override this value.") + + +;;; The spinner object. +(defun spinner--type-to-frames (type) + "Return a vector of frames corresponding to TYPE. +The list of possible built-in spinner types is given by the +`spinner-types' variable, but you can also use your own (see +below). + +If TYPE is nil, the frames of this spinner are given by the first +element of `spinner-types'. +If TYPE is a symbol, it specifies an element of `spinner-types'. +If TYPE is 'random, use a random element of `spinner-types'. +If TYPE is a list, it should be a list of symbols, and a random +one is chosen as the spinner type. +If TYPE is a vector, it should be a vector of strings and these +are used as the spinner's frames. This allows you to make your +own spinner animations." + (cond + ((vectorp type) type) + ((not type) (cdr (car spinner-types))) + ((eq type 'random) + (cdr (elt spinner-types + (random (length spinner-types))))) + ((listp type) + (cdr (assq (elt type (random (length type))) + spinner-types))) + ((symbolp type) (cdr (assq type spinner-types))) + (t (error "Unknown spinner type: %s" type)))) + +(cl-defstruct (spinner + (:copier nil) + (:conc-name spinner--) + (:constructor make-spinner (&optional type buffer-local frames-per-second delay-before-start))) + (frames (spinner--type-to-frames type)) + (counter 0) + (fps (or frames-per-second spinner-frames-per-second)) + (timer (timer-create)) + (active-p nil) + (buffer (when buffer-local + (if (bufferp buffer-local) + buffer-local + (current-buffer)))) + (delay (or delay-before-start 0))) + +;;;###autoload +(defun spinner-create (&optional type buffer-local fps delay) + "Create a spinner of the given TYPE. +The possible TYPEs are described in `spinner--type-to-frames'. + +FPS, if given, is the number of desired frames per second. +Default is `spinner-frames-per-second'. + +If BUFFER-LOCAL is non-nil, the spinner will be automatically +deactivated if the buffer is killed. If BUFFER-LOCAL is a +buffer, use that instead of current buffer. + +When started, in order to function properly, the spinner runs a +timer which periodically calls `force-mode-line-update' in the +current buffer. If BUFFER-LOCAL was set at creation time, then +`force-mode-line-update' is called in that buffer instead. When +the spinner is stopped, the timer is deactivated. + +DELAY, if given, is the number of seconds to wait after starting +the spinner before actually displaying it. It is safe to cancel +the spinner before this time, in which case it won't display at +all." + (make-spinner type buffer-local fps delay)) + +(defun spinner-print (spinner) + "Return a string of the current frame of SPINNER. +If SPINNER is nil, just return nil. +Designed to be used in the mode-line with: + (:eval (spinner-print some-spinner))" + (when (and spinner (spinner--active-p spinner)) + (let ((frame (spinner--counter spinner))) + (when (>= frame 0) + (elt (spinner--frames spinner) frame))))) + +(defun spinner--timer-function (spinner) + "Function called to update SPINNER. +If SPINNER is no longer active, or if its buffer has been killed, +stop the SPINNER's timer." + (let ((buffer (spinner--buffer spinner))) + (if (or (not (spinner--active-p spinner)) + (and buffer (not (buffer-live-p buffer)))) + (spinner-stop spinner) + ;; Increment + (cl-callf (lambda (x) (if (< x 0) + (1+ x) + (% (1+ x) (length (spinner--frames spinner))))) + (spinner--counter spinner)) + ;; Update mode-line. + (if (buffer-live-p buffer) + (with-current-buffer buffer + (force-mode-line-update)) + (force-mode-line-update))))) + +(defun spinner--start-timer (spinner) + "Start a SPINNER's timer." + (let ((old-timer (spinner--timer spinner))) + (when (timerp old-timer) + (cancel-timer old-timer)) + + (setf (spinner--active-p spinner) t) + + (unless (ignore-errors (> (spinner--fps spinner) 0)) + (error "A spinner's FPS must be a positive number")) + (setf (spinner--counter spinner) + (round (- (* (or (spinner--delay spinner) 0) + (spinner--fps spinner))))) + ;; Create timer. + (let* ((repeat (/ 1.0 (spinner--fps spinner))) + (time (timer-next-integral-multiple-of-time (current-time) repeat)) + ;; Create the timer as a lex variable so it can cancel itself. + (timer (spinner--timer spinner))) + (timer-set-time timer time repeat) + (timer-set-function timer #'spinner--timer-function (list spinner)) + (timer-activate timer) + ;; Return a stopping function. + (lambda () (spinner-stop spinner))))) + + +;;; The main functions +;;;###autoload +(defun spinner-start (&optional type-or-object fps delay) + "Start a mode-line spinner of given TYPE-OR-OBJECT. +If TYPE-OR-OBJECT is an object created with `make-spinner', +simply activate it. This method is designed for minor modes, so +they can use the spinner as part of their lighter by doing: + '(:eval (spinner-print THE-SPINNER)) +To stop this spinner, call `spinner-stop' on it. + +If TYPE-OR-OBJECT is anything else, a buffer-local spinner is +created with this type, and it is displayed in the +`mode-line-process' of the buffer it was created it. Both +TYPE-OR-OBJECT and FPS are passed to `make-spinner' (which see). +To stop this spinner, call `spinner-stop' in the same buffer. + +Either way, the return value is a function which can be called +anywhere to stop this spinner. You can also call `spinner-stop' +in the same buffer where the spinner was created. + +FPS, if given, is the number of desired frames per second. +Default is `spinner-frames-per-second'. + +DELAY, if given, is the number of seconds to wait until actually +displaying the spinner. It is safe to cancel the spinner before +this time, in which case it won't display at all." + (unless (spinner-p type-or-object) + ;; Choose type. + (if (spinner-p spinner-current) + (setf (spinner--frames spinner-current) (spinner--type-to-frames type-or-object)) + (setq spinner-current (make-spinner type-or-object (current-buffer) fps delay))) + (setq type-or-object spinner-current) + ;; Maybe add to mode-line. + (unless (and (listp mode-line-process) + (memq 'spinner--mode-line-construct mode-line-process)) + (setq mode-line-process + (list (or mode-line-process "") + 'spinner--mode-line-construct)))) + + ;; Create timer. + (when fps (setf (spinner--fps type-or-object) fps)) + (when delay (setf (spinner--delay type-or-object) delay)) + (spinner--start-timer type-or-object)) + +(defun spinner-start-print (spinner) + "Like `spinner-print', but also start SPINNER if it's not active." + (unless (spinner--active-p spinner) + (spinner-start spinner)) + (spinner-print spinner)) + +(defun spinner-stop (&optional spinner) + "Stop SPINNER, defaulting to the current buffer's spinner. +It is always safe to call this function, even if there is no +active spinner." + (let ((spinner (or spinner spinner-current))) + (when (spinner-p spinner) + (let ((timer (spinner--timer spinner))) + (when (timerp timer) + (cancel-timer timer))) + (setf (spinner--active-p spinner) nil) + (force-mode-line-update)))) + +(provide 'spinner) + +;; Local Variables: +;; indent-tabs-mode: nil +;; End: +;;; spinner.el ends here diff --git a/emacs.d/elpa/xref-1.1.0.signed b/emacs.d/elpa/xref-1.1.0.signed new file mode 100644 index 0000000..f4efdd2 --- /dev/null +++ b/emacs.d/elpa/xref-1.1.0.signed @@ -0,0 +1 @@ +Good signature from 066DAFCB81E42C40 GNU ELPA Signing Agent (2019) <elpasign@elpa.gnu.org> (trust undefined) created at 2021-04-29T12:05:02+0300 using RSA
\ No newline at end of file diff --git a/emacs.d/elpa/xref-1.1.0/xref-autoloads.el b/emacs.d/elpa/xref-1.1.0/xref-autoloads.el new file mode 100644 index 0000000..9cf959d --- /dev/null +++ b/emacs.d/elpa/xref-1.1.0/xref-autoloads.el @@ -0,0 +1,110 @@ +;;; xref-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "xref" "xref.el" (0 0 0 0)) +;;; Generated autoloads from xref.el + +(autoload 'xref-find-backend "xref" nil nil nil) + +(autoload 'xref-pop-marker-stack "xref" "\ +Pop back to where \\[xref-find-definitions] was last invoked." t nil) + +(autoload 'xref-marker-stack-empty-p "xref" "\ +Return t if the marker stack is empty; nil otherwise." nil nil) + +(autoload 'xref-find-definitions "xref" "\ +Find the definition of the identifier at point. +With prefix argument or when there's no identifier at point, +prompt for it. + +If sufficient information is available to determine a unique +definition for IDENTIFIER, display it in the selected window. +Otherwise, display the list of the possible definitions in a +buffer where the user can select from the list. + +\(fn IDENTIFIER)" t nil) + +(autoload 'xref-find-definitions-other-window "xref" "\ +Like `xref-find-definitions' but switch to the other window. + +\(fn IDENTIFIER)" t nil) + +(autoload 'xref-find-definitions-other-frame "xref" "\ +Like `xref-find-definitions' but switch to the other frame. + +\(fn IDENTIFIER)" t nil) + +(autoload 'xref-find-references "xref" "\ +Find references to the identifier at point. +This command might prompt for the identifier as needed, perhaps +offering the symbol at point as the default. +With prefix argument, or if `xref-prompt-for-identifier' is t, +always prompt for the identifier. If `xref-prompt-for-identifier' +is nil, prompt only if there's no usable symbol at point. + +\(fn IDENTIFIER)" t nil) + +(autoload 'xref-find-definitions-at-mouse "xref" "\ +Find the definition of identifier at or around mouse click. +This command is intended to be bound to a mouse event. + +\(fn EVENT)" t nil) + +(autoload 'xref-find-apropos "xref" "\ +Find all meaningful symbols that match PATTERN. +The argument has the same meaning as in `apropos'. + +\(fn PATTERN)" t nil) + (define-key esc-map "." #'xref-find-definitions) + (define-key esc-map "," #'xref-pop-marker-stack) + (define-key esc-map "?" #'xref-find-references) + (define-key esc-map [?\C-.] #'xref-find-apropos) + (define-key ctl-x-4-map "." #'xref-find-definitions-other-window) + (define-key ctl-x-5-map "." #'xref-find-definitions-other-frame) + +(autoload 'xref-references-in-directory "xref" "\ +Find all references to SYMBOL in directory DIR. +Return a list of xref values. + +This function uses the Semantic Symbol Reference API, see +`semantic-symref-tool-alist' for details on which tools are used, +and when. + +\(fn SYMBOL DIR)" nil nil) + +(autoload 'xref-matches-in-directory "xref" "\ +Find all matches for REGEXP in directory DIR. +Return a list of xref values. +Only files matching some of FILES and none of IGNORES are searched. +FILES is a string with glob patterns separated by spaces. +IGNORES is a list of glob patterns for files to ignore. + +\(fn REGEXP FILES DIR IGNORES)" nil nil) + +(autoload 'xref-matches-in-files "xref" "\ +Find all matches for REGEXP in FILES. +Return a list of xref values. +FILES must be a list of absolute file names. + +\(fn REGEXP FILES)" nil nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "xref" '("xref-"))) + +;;;*** + +;;;### (autoloads nil nil ("xref-pkg.el") (0 0 0 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; xref-autoloads.el ends here diff --git a/emacs.d/elpa/xref-1.1.0/xref-pkg.el b/emacs.d/elpa/xref-1.1.0/xref-pkg.el new file mode 100644 index 0000000..a51b51b --- /dev/null +++ b/emacs.d/elpa/xref-1.1.0/xref-pkg.el @@ -0,0 +1,2 @@ +;; Generated package description from xref.el -*- no-byte-compile: t -*- +(define-package "xref" "1.1.0" "Cross-referencing commands" '((emacs "26.1")) :url "https://elpa.gnu.org/packages/xref.html") diff --git a/emacs.d/elpa/xref-1.1.0/xref.el b/emacs.d/elpa/xref-1.1.0/xref.el new file mode 100644 index 0000000..7fc7181 --- /dev/null +++ b/emacs.d/elpa/xref-1.1.0/xref.el @@ -0,0 +1,1744 @@ +;;; xref.el --- Cross-referencing commands -*-lexical-binding:t-*- + +;; Copyright (C) 2014-2021 Free Software Foundation, Inc. +;; Version: 1.1.0 +;; Package-Requires: ((emacs "26.1")) + +;; This is a GNU ELPA :core package. Avoid functionality that is not +;; compatible with the version of Emacs recorded above. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This file provides a somewhat generic infrastructure for cross +;; referencing commands, in particular "find-definition". +;; +;; Some part of the functionality must be implemented in a language +;; dependent way and that's done by defining an xref backend. +;; +;; That consists of a constructor function, which should return a +;; backend value, and a set of implementations for the generic +;; functions: +;; +;; `xref-backend-identifier-at-point', +;; `xref-backend-identifier-completion-table', +;; `xref-backend-definitions', `xref-backend-references', +;; `xref-backend-apropos', which see. +;; +;; A major mode would normally use `add-hook' to add the backend +;; constructor to `xref-backend-functions'. +;; +;; The last three methods operate with "xref" and "location" values. +;; +;; One would usually call `make-xref' and `xref-make-file-location', +;; `xref-make-buffer-location' or `xref-make-bogus-location' to create +;; them. More generally, a location must be an instance of an EIEIO +;; class inheriting from `xref-location' and implementing +;; `xref-location-group' and `xref-location-marker'. +;; +;; There's a special kind of xrefs we call "match xrefs", which +;; correspond to search results. For these values, +;; `xref-match-length' must be defined, and `xref-location-marker' +;; must return the beginning of the match. +;; +;; Each identifier must be represented as a string. Implementers can +;; use string properties to store additional information about the +;; identifier, but they should keep in mind that values returned from +;; `xref-backend-identifier-completion-table' should still be +;; distinct, because the user can't see the properties when making the +;; choice. +;; +;; See the etags and elisp-mode implementations for full examples. + +;;; Code: + +(require 'cl-lib) +(require 'eieio) +(require 'ring) +(require 'project) + +(defgroup xref nil "Cross-referencing commands" + :version "25.1" + :group 'tools) + + +;;; Locations + +(defclass xref-location () () + :documentation "A location represents a position in a file or buffer.") + +(cl-defgeneric xref-location-marker (location) + "Return the marker for LOCATION.") + +(cl-defgeneric xref-location-group (location) + "Return a string used to group a set of locations. +This is typically the filename.") + +(cl-defgeneric xref-location-line (_location) + "Return the line number corresponding to the location." + nil) + +(cl-defgeneric xref-match-length (_item) + "Return the length of the match." + nil) + +;;;; Commonly needed location classes are defined here: + +(defcustom xref-file-name-display 'project-relative + "Style of file name display in *xref* buffers. + +If the value is the symbol `abs', the default, show the file names +in their full absolute form. + +If `nondirectory', show only the nondirectory (a.k.a. \"base name\") +part of the file name. + +If `project-relative', show only the file name relative to the +current project root. If there is no current project, or if the +file resides outside of its root, show that particular file name +in its full absolute form." + :type '(choice (const :tag "absolute file name" abs) + (const :tag "nondirectory file name" nondirectory) + (const :tag "relative to project root" project-relative)) + :version "27.1") + +;; FIXME: might be useful to have an optional "hint" i.e. a string to +;; search for in case the line number is slightly out of date. +(defclass xref-file-location (xref-location) + ((file :type string :initarg :file) + (line :type fixnum :initarg :line :reader xref-location-line) + (column :type fixnum :initarg :column :reader xref-file-location-column)) + :documentation "A file location is a file/line/column triple. +Line numbers start from 1 and columns from 0.") + +(defun xref-make-file-location (file line column) + "Create and return a new `xref-file-location'." + (make-instance 'xref-file-location :file file :line line :column column)) + +(cl-defmethod xref-location-marker ((l xref-file-location)) + (with-slots (file line column) l + (with-current-buffer + (or (get-file-buffer file) + (let ((find-file-suppress-same-file-warnings t)) + (find-file-noselect file))) + (save-restriction + (widen) + (save-excursion + (goto-char (point-min)) + (ignore-errors + ;; xref location may be out of date; it may be past the + ;; end of the current file, or the file may have been + ;; deleted. Return a reasonable location; the user will + ;; figure it out. + (beginning-of-line line) + (forward-char column)) + (point-marker)))))) + +(defvar xref--project-root-memo nil + "Cons mapping `default-directory' value to the search root.") + +(cl-defmethod xref-location-group ((l xref-file-location)) + (cl-ecase xref-file-name-display + (abs + (oref l file)) + (nondirectory + (file-name-nondirectory (oref l file))) + (project-relative + (unless (and xref--project-root-memo + (equal (car xref--project-root-memo) + default-directory)) + (setq xref--project-root-memo + (cons default-directory + (let ((root + (let ((pr (project-current))) + (and pr (xref--project-root pr))))) + (and root (expand-file-name root)))))) + (let ((file (oref l file)) + (search-root (cdr xref--project-root-memo))) + (if (and search-root + (string-prefix-p search-root file)) + (substring file (length search-root)) + file))))) + +(defclass xref-buffer-location (xref-location) + ((buffer :type buffer :initarg :buffer) + (position :type fixnum :initarg :position))) + +(defun xref-make-buffer-location (buffer position) + "Create and return a new `xref-buffer-location'." + (make-instance 'xref-buffer-location :buffer buffer :position position)) + +(cl-defmethod xref-location-marker ((l xref-buffer-location)) + (with-slots (buffer position) l + (let ((m (make-marker))) + (move-marker m position buffer)))) + +(cl-defmethod xref-location-group ((l xref-buffer-location)) + (with-slots (buffer) l + (or (buffer-file-name buffer) + (format "(buffer %s)" (buffer-name buffer))))) + +(defclass xref-bogus-location (xref-location) + ((message :type string :initarg :message + :reader xref-bogus-location-message)) + :documentation "Bogus locations are sometimes useful to +indicate errors, e.g. when we know that a function exists but the +actual location is not known.") + +(defun xref-make-bogus-location (message) + "Create and return a new `xref-bogus-location'." + (make-instance 'xref-bogus-location :message message)) + +(cl-defmethod xref-location-marker ((l xref-bogus-location)) + (user-error "%s" (oref l message))) + +(cl-defmethod xref-location-group ((_ xref-bogus-location)) "(No location)") + + +;;; Cross-reference + +(defclass xref-item () + ((summary :type string :initarg :summary + :reader xref-item-summary + :documentation "One line which will be displayed for +this item in the output buffer.") + (location :initarg :location + :reader xref-item-location + :documentation "An object describing how to navigate +to the reference's target.")) + :comment "An xref item describes a reference to a location +somewhere.") + +(defun xref-make (summary location) + "Create and return a new `xref-item'. +SUMMARY is a short string to describe the xref. +LOCATION is an `xref-location'." + (make-instance 'xref-item :summary summary :location location)) + +(defclass xref-match-item () + ((summary :type string :initarg :summary + :reader xref-item-summary) + (location :initarg :location + :type xref-file-location + :reader xref-item-location) + (length :initarg :length :reader xref-match-length)) + :comment "A match xref item describes a search result.") + +(defun xref-make-match (summary location length) + "Create and return a new `xref-match-item'. +SUMMARY is a short string to describe the xref. +LOCATION is an `xref-location'. +LENGTH is the match length, in characters." + (make-instance 'xref-match-item :summary summary + :location location :length length)) + + +;;; API + +(defvar xref-backend-functions nil + "Special hook to find the xref backend for the current context. +Each function on this hook is called in turn with no arguments, +and should return either nil to mean that it is not applicable, +or an xref backend, which is a value to be used to dispatch the +generic functions.") + +;; We make the etags backend the default for now, until something +;; better comes along. Use APPEND so that any `add-hook' calls made +;; before this package is loaded put new items before this one. +(add-hook 'xref-backend-functions #'etags--xref-backend t) + +;;;###autoload +(defun xref-find-backend () + (run-hook-with-args-until-success 'xref-backend-functions)) + +(cl-defgeneric xref-backend-definitions (backend identifier) + "Find definitions of IDENTIFIER. + +The result must be a list of xref objects. If IDENTIFIER +contains sufficient information to determine a unique definition, +return only that definition. If there are multiple possible +definitions, return all of them. If no definitions can be found, +return nil. + +IDENTIFIER can be any string returned by +`xref-backend-identifier-at-point', or from the table returned by +`xref-backend-identifier-completion-table'. + +To create an xref object, call `xref-make'.") + +(cl-defgeneric xref-backend-references (_backend identifier) + "Find references of IDENTIFIER. +The result must be a list of xref objects. If no references can +be found, return nil. + +The default implementation uses `semantic-symref-tool-alist' to +find a search tool; by default, this uses \"find | grep\" in the +current project's main and external roots." + (mapcan + (lambda (dir) + (xref-references-in-directory identifier dir)) + (let ((pr (project-current t))) + (cons + (xref--project-root pr) + (project-external-roots pr))))) + +(cl-defgeneric xref-backend-apropos (backend pattern) + "Find all symbols that match PATTERN string. +The second argument has the same meaning as in `apropos'. + +If BACKEND is implemented in Lisp, it can use +`xref-apropos-regexp' to convert the pattern to regexp.") + +(cl-defgeneric xref-backend-identifier-at-point (_backend) + "Return the relevant identifier at point. + +The return value must be a string, or nil meaning no identifier +at point found. + +If it's hard to determine the identifier precisely (e.g., because +it's a method call on unknown type), the implementation can +return a simple string (such as symbol at point) marked with a +special text property which e.g. `xref-backend-definitions' would +recognize and then delegate the work to an external process." + (let ((thing (thing-at-point 'symbol))) + (and thing (substring-no-properties thing)))) + +(cl-defgeneric xref-backend-identifier-completion-table (backend) + "Return the completion table for identifiers.") + +(cl-defgeneric xref-backend-identifier-completion-ignore-case (_backend) + "Return t if case is not significant in identifier completion." + completion-ignore-case) + + +;;; misc utilities +(defun xref--alistify (list key test) + "Partition the elements of LIST into an alist. +KEY extracts the key from an element and TEST is used to compare +keys." + (let ((alist '())) + (dolist (e list) + (let* ((k (funcall key e)) + (probe (cl-assoc k alist :test test))) + (if probe + (setcdr probe (cons e (cdr probe))) + (push (cons k (list e)) alist)))) + ;; Put them back in order. + (cl-loop for (key . value) in (reverse alist) + collect (cons key (reverse value))))) + +(defun xref--insert-propertized (props &rest strings) + "Insert STRINGS with text properties PROPS." + (let ((start (point))) + (apply #'insert strings) + (add-text-properties start (point) props))) + +(defun xref--search-property (property &optional backward) + "Search the next text range where text property PROPERTY is non-nil. +Return the value of PROPERTY. If BACKWARD is non-nil, search +backward." + (let ((next (if backward + #'previous-single-char-property-change + #'next-single-char-property-change)) + (start (point)) + (value nil)) + (while (progn + (goto-char (funcall next (point) property)) + (not (or (setq value (get-text-property (point) property)) + (eobp) + (bobp))))) + (cond (value) + (t (goto-char start) nil)))) + + +;;; Marker stack (M-. pushes, M-, pops) + +(defcustom xref-marker-ring-length 16 + "Length of the xref marker ring. +If this variable is not set through Customize, you must call +`xref-set-marker-ring-length' for changes to take effect." + :type 'integer + :initialize #'custom-initialize-default + :set #'xref-set-marker-ring-length) + +(defcustom xref-prompt-for-identifier '(not xref-find-definitions + xref-find-definitions-other-window + xref-find-definitions-other-frame) + "If non-nil, prompt for the identifier to find. + +When t, always prompt for the identifier name. + +When nil, prompt only when there's no value at point we can use, +or when the command has been called with the prefix argument. + +Otherwise, it's a list of xref commands which will always prompt, +with the identifier at point, if any, used as the default. +If the list starts with `not', the meaning of the rest of the +elements is negated: these commands will NOT prompt." + :type '(choice (const :tag "Always prompt for identifier" t) + (const :tag "Prompt if no identifier at point" nil) + (set :menu-tag "Prompt according to command" + :tag "Prompt according to command" + :value (not) + (const :tag "Except for commands listed below" not) + (repeat :inline t (symbol :tag "command"))))) + +(defcustom xref-after-jump-hook '(recenter + xref-pulse-momentarily) + "Functions called after jumping to an xref." + :type 'hook) + +(defcustom xref-after-return-hook '(xref-pulse-momentarily) + "Functions called after returning to a pre-jump location." + :type 'hook) + +(defcustom xref-after-update-hook nil + "Functions called after the xref buffer is updated." + :type 'hook + :version "28.1" + :package-version '(xref . "1.0.4")) + +(defvar xref--marker-ring (make-ring xref-marker-ring-length) + "Ring of markers to implement the marker stack.") + +(defun xref-set-marker-ring-length (var val) + "Set `xref-marker-ring-length'. +VAR is the symbol `xref-marker-ring-length' and VAL is the new +value." + (set-default var val) + (if (ring-p xref--marker-ring) + (ring-resize xref--marker-ring val))) + +(defun xref-push-marker-stack (&optional m) + "Add point M (defaults to `point-marker') to the marker stack." + (ring-insert xref--marker-ring (or m (point-marker)))) + +;;;###autoload +(defun xref-pop-marker-stack () + "Pop back to where \\[xref-find-definitions] was last invoked." + (interactive) + (let ((ring xref--marker-ring)) + (when (ring-empty-p ring) + (user-error "Marker stack is empty")) + (let ((marker (ring-remove ring 0))) + (switch-to-buffer (or (marker-buffer marker) + (user-error "The marked buffer has been deleted"))) + (goto-char (marker-position marker)) + (set-marker marker nil nil) + (run-hooks 'xref-after-return-hook)))) + +(defvar xref--current-item nil) + +(defun xref-pulse-momentarily () + (pcase-let ((`(,beg . ,end) + (save-excursion + (or + (let ((length (xref-match-length xref--current-item))) + (and length (cons (point) (+ (point) length)))) + (back-to-indentation) + (if (eolp) + (cons (line-beginning-position) (1+ (point))) + (cons (point) (line-end-position))))))) + (pulse-momentary-highlight-region beg end 'next-error))) + +;; etags.el needs this +(defun xref-clear-marker-stack () + "Discard all markers from the marker stack." + (let ((ring xref--marker-ring)) + (while (not (ring-empty-p ring)) + (let ((marker (ring-remove ring))) + (set-marker marker nil nil))))) + +;;;###autoload +(defun xref-marker-stack-empty-p () + "Return t if the marker stack is empty; nil otherwise." + (ring-empty-p xref--marker-ring)) + + + +(defun xref--goto-char (pos) + (cond + ((and (<= (point-min) pos) (<= pos (point-max)))) + (widen-automatically (widen)) + (t (user-error "Position is outside accessible part of buffer"))) + (goto-char pos)) + +(defun xref--goto-location (location) + "Set buffer and point according to xref-location LOCATION." + (let ((marker (xref-location-marker location))) + (set-buffer (marker-buffer marker)) + (xref--goto-char marker))) + +(defun xref-pop-to-location (item &optional action) + "Go to the location of ITEM and display the buffer. +ACTION controls how the buffer is displayed: + nil -- switch-to-buffer + `window' -- pop-to-buffer (other window) + `frame' -- pop-to-buffer (other frame) +If SELECT is non-nil, select the target window." + (let* ((marker (save-excursion + (xref-location-marker (xref-item-location item)))) + (buf (marker-buffer marker))) + (cl-ecase action + ((nil) (switch-to-buffer buf)) + (window (pop-to-buffer buf t)) + (frame (let ((pop-up-frames t)) (pop-to-buffer buf t)))) + (xref--goto-char marker)) + (let ((xref--current-item item)) + (run-hooks 'xref-after-jump-hook))) + + +;;; XREF buffer (part of the UI) + +;; The xref buffer is used to display a set of xrefs. +(defconst xref-buffer-name "*xref*" + "The name of the buffer to show xrefs.") + +(defface xref-file-header '((t :inherit compilation-info)) + "Face used to highlight file header in the xref buffer." + :version "27.1") + +(defface xref-line-number '((t :inherit compilation-line-number)) + "Face for displaying line numbers in the xref buffer." + :version "27.1") + +(defface xref-match '((t :inherit match)) + "Face used to highlight matches in the xref buffer." + :version "27.1") + +(defmacro xref--with-dedicated-window (&rest body) + `(let* ((xref-w (get-buffer-window xref-buffer-name)) + (xref-w-dedicated (window-dedicated-p xref-w))) + (unwind-protect + (progn + (when xref-w + (set-window-dedicated-p xref-w 'soft)) + ,@body) + (when xref-w + (set-window-dedicated-p xref-w xref-w-dedicated))))) + +(defvar-local xref--original-window-intent nil + "Original window-switching intent before xref buffer creation.") + +(defvar-local xref--original-window nil + "The original window this xref buffer was created from.") + +(defvar-local xref--fetcher nil + "The original function to call to fetch the list of xrefs.") + +(defun xref--show-pos-in-buf (pos buf) + "Goto and display position POS of buffer BUF in a window. +Honor `xref--original-window-intent', run `xref-after-jump-hook' +and finally return the window." + (let* ((pop-up-frames + (or (eq xref--original-window-intent 'frame) + pop-up-frames)) + (action + (cond ((eq xref--original-window-intent 'frame) + t) + ((eq xref--original-window-intent 'window) + `((xref--display-buffer-in-other-window) + (window . ,xref--original-window))) + ((and + (window-live-p xref--original-window) + (or (not (window-dedicated-p xref--original-window)) + (eq (window-buffer xref--original-window) buf))) + `((xref--display-buffer-in-window) + (window . ,xref--original-window)))))) + (with-selected-window (display-buffer buf action) + (xref--goto-char pos) + (run-hooks 'xref-after-jump-hook) + (selected-window)))) + +(defun xref--display-buffer-in-other-window (buffer alist) + (let ((window (assoc-default 'window alist))) + (cl-assert window) + (xref--with-dedicated-window + (with-selected-window window + (display-buffer buffer t))))) + +(defun xref--display-buffer-in-window (buffer alist) + (let ((window (assoc-default 'window alist))) + (cl-assert window) + (with-selected-window window + (display-buffer buffer '(display-buffer-same-window))))) + +(defun xref--show-location (location &optional select) + "Help `xref-show-xref' and `xref-goto-xref' do their job. +Go to LOCATION and if SELECT is non-nil select its window. If +SELECT is `quit', also quit the *xref* window." + (condition-case err + (let* ((marker (xref-location-marker location)) + (buf (marker-buffer marker)) + (xref-buffer (current-buffer))) + (cond (select + (if (eq select 'quit) (quit-window nil nil)) + (select-window + (with-current-buffer xref-buffer + (xref--show-pos-in-buf marker buf)))) + (t + (save-selected-window + (xref--with-dedicated-window + (xref--show-pos-in-buf marker buf)))))) + (user-error (message (error-message-string err))))) + +(defun xref-show-location-at-point () + "Display the source of xref at point in the appropriate window, if any." + (interactive) + (let* ((xref (xref--item-at-point)) + (xref--current-item xref)) + (when xref + (xref--show-location (xref-item-location xref))))) + +(defun xref-next-line-no-show () + "Move to the next xref but don't display its source." + (interactive) + (xref--search-property 'xref-item)) + +(defun xref-next-line () + "Move to the next xref and display its source in the appropriate window." + (interactive) + (xref-next-line-no-show) + (xref-show-location-at-point)) + +(defun xref-prev-line-no-show () + "Move to the previous xref but don't display its source." + (interactive) + (xref--search-property 'xref-item t)) + +(defun xref-prev-line () + "Move to the previous xref and display its source in the appropriate window." + (interactive) + (xref-prev-line-no-show) + (xref-show-location-at-point)) + +(defun xref-next-group () + "Move to the first item of the next xref group and display its source." + (interactive) + (xref--search-property 'xref-group) + (xref--search-property 'xref-item) + (xref-show-location-at-point)) + +(defun xref-prev-group () + "Move to the first item of the previous xref group and display its source." + (interactive) + ;; Search for the xref group of the current item, provided that the + ;; point is not already in an xref group. + (unless (plist-member (text-properties-at (point)) 'xref-group) + (xref--search-property 'xref-group t)) + ;; Search for the previous xref group. + (xref--search-property 'xref-group t) + (xref--search-property 'xref-item) + (xref-show-location-at-point)) + +(defun xref--item-at-point () + (get-text-property + (if (eolp) (1- (point)) (point)) + 'xref-item)) + +(defun xref-goto-xref (&optional quit) + "Jump to the xref on the current line and select its window. +If QUIT is non-nil (interactively, with prefix argument), also +quit the *xref* buffer." + (interactive "P") + (let* ((buffer (current-buffer)) + (xref (or (xref--item-at-point) + (user-error "No reference at point"))) + (xref--current-item xref)) + (xref--show-location (xref-item-location xref) (if quit 'quit t)) + (if (fboundp 'next-error-found) + (next-error-found buffer (current-buffer)) + ;; Emacs < 27 + (setq next-error-last-buffer buffer)))) + +(defun xref-quit-and-goto-xref () + "Quit *xref* buffer, then jump to xref on current line." + (interactive) + (xref-goto-xref t)) + +(defun xref-quit-and-pop-marker-stack () + "Quit *xref* buffer, then pop the xref marker stack." + (interactive) + (quit-window) + (xref-pop-marker-stack)) + +(defun xref-query-replace-in-results (from to) + "Perform interactive replacement of FROM with TO in all displayed xrefs. + +This command interactively replaces FROM with TO in the names of the +references displayed in the current *xref* buffer." + (interactive + (let ((fr (read-regexp "Xref query-replace (regexp)" ".*"))) + (list fr + (read-regexp (format "Xref query-replace (regexp) %s with: " fr))))) + (let* (item xrefs iter) + (save-excursion + (while (setq item (xref--search-property 'xref-item)) + (when (xref-match-length item) + (push item xrefs)))) + (unwind-protect + (progn + (goto-char (point-min)) + (setq iter (xref--buf-pairs-iterator (nreverse xrefs))) + (xref--query-replace-1 from to iter)) + (funcall iter :cleanup)))) + +(defun xref--buf-pairs-iterator (xrefs) + (let (chunk-done item next-pair file-buf pairs all-pairs) + (lambda (action) + (pcase action + (:next + (when (or xrefs next-pair) + (setq chunk-done nil) + (when next-pair + (setq file-buf (marker-buffer (car next-pair)) + pairs (list next-pair) + next-pair nil)) + (while (and (not chunk-done) + (setq item (pop xrefs))) + (save-excursion + (let* ((loc (xref-item-location item)) + (beg (xref-location-marker loc)) + (end (move-marker (make-marker) + (+ beg (xref-match-length item)) + (marker-buffer beg)))) + (let ((pair (cons beg end))) + (push pair all-pairs) + ;; Perform sanity check first. + (xref--goto-location loc) + (if (xref--outdated-p item) + (message "Search result out of date, skipping") + (cond + ((null file-buf) + (setq file-buf (marker-buffer beg)) + (push pair pairs)) + ((equal file-buf (marker-buffer beg)) + (push pair pairs)) + (t + (setq chunk-done t + next-pair pair)))))))) + (cons file-buf (nreverse pairs)))) + (:cleanup + (dolist (pair all-pairs) + (move-marker (car pair) nil) + (move-marker (cdr pair) nil))))))) + +(defun xref--outdated-p (item) + "Check that the match location at current position is up-to-date. +ITEMS is an xref item which " + ;; FIXME: The check should most likely be a generic function instead + ;; of the assumption that all matches' summaries relate to the + ;; buffer text in a particular way. + (let* ((summary (xref-item-summary item)) + ;; Sometimes buffer contents include ^M, and sometimes Grep + ;; output includes it, and they don't always match. + (strip (lambda (s) (if (string-match "\r\\'" s) + (substring-no-properties s 0 -1) + s))) + (stripped-summary (funcall strip summary)) + (lendpos (line-end-position)) + (check (lambda () + (let ((comparison-end + (+ (point) (length stripped-summary)))) + (and (>= lendpos comparison-end) + (equal stripped-summary + (buffer-substring-no-properties + (point) comparison-end))))))) + (not + (or + ;; Either summary contains match text and after + ;; (2nd+ match on the line)... + (funcall check) + ;; ...or it starts at bol, includes the match and after. + (and (< (point) (+ (line-beginning-position) + (length stripped-summary))) + (save-excursion + (forward-line 0) + (funcall check))))))) + +;; FIXME: Write a nicer UI. +(defun xref--query-replace-1 (from to iter) + (let* ((query-replace-lazy-highlight nil) + (continue t) + did-it-once buf-pairs pairs + current-beg current-end + ;; Counteract the "do the next match now" hack in + ;; `perform-replace'. And still, it'll report that those + ;; matches were "filtered out" at the end. + (isearch-filter-predicate + (lambda (beg end) + (and current-beg + (>= beg current-beg) + (<= end current-end)))) + (replace-re-search-function + (lambda (from &optional _bound noerror) + (let (found pair) + (while (and (not found) pairs) + (setq pair (pop pairs) + current-beg (car pair) + current-end (cdr pair)) + (goto-char current-beg) + (when (re-search-forward from current-end noerror) + (setq found t))) + found)))) + (while (and continue (setq buf-pairs (funcall iter :next))) + (if did-it-once + ;; Reuse the same window for subsequent buffers. + (switch-to-buffer (car buf-pairs)) + (xref--with-dedicated-window + (pop-to-buffer (car buf-pairs))) + (setq did-it-once t)) + (setq pairs (cdr buf-pairs)) + (setq continue + (perform-replace from to t t nil nil multi-query-replace-map))) + (unless did-it-once (user-error "No suitable matches here")) + (when (and continue (not buf-pairs)) + (message "All results processed")))) + +(defvar xref--xref-buffer-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "n") #'xref-next-line) + (define-key map (kbd "p") #'xref-prev-line) + (define-key map (kbd "N") #'xref-next-group) + (define-key map (kbd "P") #'xref-prev-group) + (define-key map (kbd "r") #'xref-query-replace-in-results) + (define-key map (kbd "RET") #'xref-goto-xref) + (define-key map (kbd "TAB") #'xref-quit-and-goto-xref) + (define-key map (kbd "C-o") #'xref-show-location-at-point) + ;; suggested by Johan Claesson "to further reduce finger movement": + (define-key map (kbd ".") #'xref-next-line) + (define-key map (kbd ",") #'xref-prev-line) + (define-key map (kbd "g") #'xref-revert-buffer) + (define-key map (kbd "M-,") #'xref-quit-and-pop-marker-stack) + map)) + +(define-derived-mode xref--xref-buffer-mode special-mode "XREF" + "Mode for displaying cross-references." + (setq buffer-read-only t) + (setq next-error-function #'xref--next-error-function) + (setq next-error-last-buffer (current-buffer)) + (setq imenu-prev-index-position-function + #'xref--imenu-prev-index-position) + (setq imenu-extract-index-name-function + #'xref--imenu-extract-index-name)) + +(defvar xref--transient-buffer-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "RET") #'xref-quit-and-goto-xref) + (set-keymap-parent map xref--xref-buffer-mode-map) + map)) + +(define-derived-mode xref--transient-buffer-mode + xref--xref-buffer-mode + "XREF Transient") + +(defun xref--imenu-prev-index-position () + "Move point to previous line in `xref' buffer. +This function is used as a value for +`imenu-prev-index-position-function'." + (if (bobp) + nil + (xref--search-property 'xref-group t))) + +(defun xref--imenu-extract-index-name () + "Return imenu name for line at point. +This function is used as a value for +`imenu-extract-index-name-function'. Point should be at the +beginning of the line." + (buffer-substring-no-properties (line-beginning-position) + (line-end-position))) + +(defun xref--next-error-function (n reset?) + (when reset? + (goto-char (point-min))) + (let ((backward (< n 0)) + (n (abs n)) + (xref nil)) + (if (= n 0) + (setq xref (get-text-property (point) 'xref-item)) + (dotimes (_ n) + (setq xref (xref--search-property 'xref-item backward)))) + (cond (xref + ;; Save the current position (when the buffer is visible, + ;; it gets reset to that window's point from time to time). + (let ((win (get-buffer-window (current-buffer)))) + (and win (set-window-point win (point)))) + (xref--show-location (xref-item-location xref) t)) + (t + (error "No %s xref" (if backward "previous" "next")))))) + +(defvar xref--button-map + (let ((map (make-sparse-keymap))) + (define-key map [mouse-1] #'xref-goto-xref) + (define-key map [mouse-2] #'xref--mouse-2) + map)) + +(defun xref--mouse-2 (event) + "Move point to the button and show the xref definition." + (interactive "e") + (mouse-set-point event) + (forward-line 0) + (or (get-text-property (point) 'xref-item) + (xref--search-property 'xref-item)) + (xref-show-location-at-point)) + +(defun xref--insert-xrefs (xref-alist) + "Insert XREF-ALIST in the current-buffer. +XREF-ALIST is of the form ((GROUP . (XREF ...)) ...), where +GROUP is a string for decoration purposes and XREF is an +`xref-item' object." + (require 'compile) ; For the compilation faces. + (cl-loop for ((group . xrefs) . more1) on xref-alist + for max-line-width = + (cl-loop for xref in xrefs + maximize (let ((line (xref-location-line + (oref xref location)))) + (length (and line (format "%d" line))))) + for line-format = (and max-line-width + (format "%%%dd: " max-line-width)) + with prev-group = nil + with prev-line = nil + do + (xref--insert-propertized '(face xref-file-header xref-group t) + group "\n") + (cl-loop for (xref . more2) on xrefs do + (with-slots (summary location) xref + (let* ((line (xref-location-line location)) + (prefix + (cond + ((not line) " ") + ((equal line prev-line) "") + (t (propertize (format line-format line) + 'face 'xref-line-number))))) + ;; Render multiple matches on the same line, together. + (when (and (equal prev-group group) + (not (equal prev-line line))) + (insert "\n")) + (xref--insert-propertized + (list 'xref-item xref + 'mouse-face 'highlight + 'keymap xref--button-map + 'help-echo + (concat "mouse-2: display in another window, " + "RET or mouse-1: follow reference")) + prefix summary) + (setq prev-line line + prev-group group)))) + (insert "\n")) + (run-hooks 'xref-after-update-hook)) + +(defun xref--analyze (xrefs) + "Find common filenames in XREFS. +Return an alist of the form ((FILENAME . (XREF ...)) ...)." + (xref--alistify xrefs + (lambda (x) + (xref-location-group (xref-item-location x))) + #'equal)) + +(defun xref--show-xref-buffer (fetcher alist) + (cl-assert (functionp fetcher)) + (let* ((xrefs + (or + (assoc-default 'fetched-xrefs alist) + (funcall fetcher))) + (xref-alist (xref--analyze xrefs)) + (dd default-directory)) + (with-current-buffer (get-buffer-create xref-buffer-name) + (setq default-directory dd) + (xref--xref-buffer-mode) + (xref--show-common-initialize xref-alist fetcher alist) + (pop-to-buffer (current-buffer)) + (current-buffer)))) + +(defun xref--project-root (project) + (if (fboundp 'project-root) + (project-root project) + (with-no-warnings + (car (project-roots project))))) + +(defun xref--show-common-initialize (xref-alist fetcher alist) + (setq buffer-undo-list nil) + (let ((inhibit-read-only t) + (buffer-undo-list t)) + (erase-buffer) + (xref--insert-xrefs xref-alist) + (goto-char (point-min)) + (setq xref--original-window (assoc-default 'window alist) + xref--original-window-intent (assoc-default 'display-action alist)) + (setq xref--fetcher fetcher))) + +(defun xref-revert-buffer () + "Refresh the search results in the current buffer." + (interactive) + (let ((inhibit-read-only t) + (buffer-undo-list t)) + (save-excursion + (condition-case err + (let ((alist (xref--analyze (funcall xref--fetcher)))) + (erase-buffer) + (xref--insert-xrefs alist)) + (user-error + (erase-buffer) + (insert + (propertize + (error-message-string err) + 'face 'error))))))) + +(defun xref-show-definitions-buffer (fetcher alist) + "Show the definitions list in a regular window. + +When only one definition found, jump to it right away instead." + (let ((xrefs (funcall fetcher))) + (cond + ((not (cdr xrefs)) + (xref-pop-to-location (car xrefs) + (assoc-default 'display-action alist))) + (t + (xref--show-xref-buffer fetcher + (cons (cons 'fetched-xrefs xrefs) + alist)))))) + +(define-obsolete-function-alias + 'xref--show-defs-buffer #'xref-show-definitions-buffer "28.1") + +(defun xref-show-definitions-buffer-at-bottom (fetcher alist) + "Show the definitions list in a window at the bottom. + +When there is more than one definition, split the selected window +and show the list in a small window at the bottom. And use a +local keymap that binds `RET' to `xref-quit-and-goto-xref'." + (let* ((xrefs (funcall fetcher)) + (dd default-directory) + ;; XXX: Make percentage customizable maybe? + (max-height (/ (window-height) 2)) + (size-fun (lambda (window) + (fit-window-to-buffer window max-height)))) + (cond + ((not (cdr xrefs)) + (xref-pop-to-location (car xrefs) + (assoc-default 'display-action alist))) + (t + (with-current-buffer (get-buffer-create xref-buffer-name) + (setq default-directory dd) + (xref--transient-buffer-mode) + (xref--show-common-initialize (xref--analyze xrefs) fetcher alist) + (pop-to-buffer (current-buffer) + `(display-buffer-in-direction . ((direction . below) + (window-height . ,size-fun)))) + (current-buffer)))))) + +(define-obsolete-function-alias 'xref--show-defs-buffer-at-bottom + #'xref-show-definitions-buffer-at-bottom "28.1") + +(defun xref-show-definitions-completing-read (fetcher alist) + "Let the user choose the target definition with completion. + +When there is more than one definition, let the user choose +between them by typing in the minibuffer with completion." + (let* ((xrefs (funcall fetcher)) + (xref-alist (xref--analyze xrefs)) + xref-alist-with-line-info + xref + (group-prefix-length + ;; FIXME: Groups are not always file names, but they often + ;; are. At least this shouldn't make the other kinds of + ;; groups look worse. + (let ((common-prefix (try-completion "" xref-alist))) + (if (> (length common-prefix) 0) + (length (file-name-directory common-prefix)) + 0)))) + + (cl-loop for ((group . xrefs) . more1) on xref-alist + do + (cl-loop for (xref . more2) on xrefs do + (with-slots (summary location) xref + (let* ((line (xref-location-line location)) + (line-fmt + (if line + (format #("%d:" 0 2 (face xref-line-number)) + line) + "")) + (group-fmt + (propertize + (substring group group-prefix-length) + 'face 'xref-file-header)) + (candidate + (format "%s:%s%s" group-fmt line-fmt summary))) + (push (cons candidate xref) xref-alist-with-line-info))))) + + (setq xref (if (not (cdr xrefs)) + (car xrefs) + (let* ((collection (reverse xref-alist-with-line-info)) + (ctable + (lambda (string pred action) + (cond + ((eq action 'metadata) + '(metadata . ((category . xref-location)))) + (t + (complete-with-action action collection string pred))))) + (def (caar collection))) + (cdr (assoc (completing-read "Choose definition: " + ctable nil t + nil nil + def) + collection))))) + + (xref-pop-to-location xref (assoc-default 'display-action alist)))) + +;; TODO: Can delete this alias before Emacs 28's release. +(define-obsolete-function-alias + 'xref--show-defs-minibuffer #'xref-show-definitions-completing-read "28.1") + + +(defcustom xref-show-xrefs-function 'xref--show-xref-buffer + "Function to display a list of search results. + +It should accept two arguments: FETCHER and ALIST. + +FETCHER is a function of no arguments that returns a list of xref +values. It must not depend on the current buffer or selected +window. + +ALIST can include, but limited to, the following keys: + +WINDOW for the window that was selected before the current +command was called. + +DISPLAY-ACTION indicates where the target location should be +displayed. The possible values are nil, `window' meaning the +other window, or `frame' meaning the other frame." + :type 'function) + +(defcustom xref-show-definitions-function 'xref-show-definitions-buffer + "Function to handle the definition search results. + +Accepts the same arguments as `xref-show-xrefs-function'. + +Generally, it is expected to jump to the definition if there's +only one, and otherwise provide some way to choose among the +definitions." + :type '(choice + (const :tag "Show a regular list of locations" + xref-show-definitions-buffer) + (const :tag "Show a \"transient\" list at the bottom of the window" + xref-show-definitions-buffer-at-bottom) + (const :tag "Choose the definition with completion" + xref-show-definitions-completing-read) + (function :tag "Custom function"))) + +(defvar xref--read-identifier-history nil) + +(defvar xref--read-pattern-history nil) + +(defun xref--show-xrefs (fetcher display-action &optional _always-show-list) + (xref--push-markers) + (unless (functionp fetcher) + ;; Old convention. + (let ((xrefs fetcher)) + (setq fetcher + (lambda () + (if (eq xrefs 'called-already) + (user-error "Refresh is not supported") + (prog1 + xrefs + (setq xrefs 'called-already))))))) + (funcall xref-show-xrefs-function fetcher + `((window . ,(selected-window)) + (display-action . ,display-action)))) + +(defun xref--show-defs (xrefs display-action) + (xref--push-markers) + (funcall xref-show-definitions-function xrefs + `((window . ,(selected-window)) + (display-action . ,display-action)))) + +(defun xref--push-markers () + (unless (region-active-p) (push-mark nil t)) + (xref-push-marker-stack)) + +(defun xref--prompt-p (command) + (or (eq xref-prompt-for-identifier t) + (if (eq (car xref-prompt-for-identifier) 'not) + (not (memq command (cdr xref-prompt-for-identifier))) + (memq command xref-prompt-for-identifier)))) + +(defun xref--read-identifier (prompt) + "Return the identifier at point or read it from the minibuffer." + (let* ((backend (xref-find-backend)) + (def (xref-backend-identifier-at-point backend)) + (completion-ignore-case + (xref-backend-identifier-completion-ignore-case backend))) + (cond ((or current-prefix-arg + (not def) + (xref--prompt-p this-command)) + (let ((id + (completing-read + (if def + (format "%s (default %s): " + (substring prompt 0 (string-match + "[ :]+\\'" prompt)) + def) + prompt) + (xref-backend-identifier-completion-table backend) + nil nil nil + 'xref--read-identifier-history def))) + (if (equal id "") + (or def (user-error "There is no default identifier")) + id))) + (t def)))) + + +;;; Commands + +(defun xref--find-xrefs (input kind arg display-action) + (xref--show-xrefs + (xref--create-fetcher input kind arg) + display-action)) + +(defun xref--find-definitions (id display-action) + (xref--show-defs + (xref--create-fetcher id 'definitions id) + display-action)) + +(defun xref--create-fetcher (input kind arg) + "Return an xref list fetcher function. + +It revisits the saved position and delegates the finding logic to +the xref backend method indicated by KIND and passes ARG to it." + (let* ((orig-buffer (current-buffer)) + (orig-position (point)) + (backend (xref-find-backend)) + (method (intern (format "xref-backend-%s" kind)))) + (lambda () + (save-excursion + ;; Xref methods are generally allowed to depend on the text + ;; around point, not just on their explicit arguments. + ;; + ;; There is only so much we can do, however, to recreate that + ;; context, given that the user is free to change the buffer + ;; contents freely in the meantime. + (when (buffer-live-p orig-buffer) + (set-buffer orig-buffer) + (ignore-errors (goto-char orig-position))) + (let ((xrefs (funcall method backend arg))) + (unless xrefs + (xref--not-found-error kind input)) + xrefs))))) + +(defun xref--not-found-error (kind input) + (user-error "No %s found for: %s" (symbol-name kind) input)) + +;;;###autoload +(defun xref-find-definitions (identifier) + "Find the definition of the identifier at point. +With prefix argument or when there's no identifier at point, +prompt for it. + +If sufficient information is available to determine a unique +definition for IDENTIFIER, display it in the selected window. +Otherwise, display the list of the possible definitions in a +buffer where the user can select from the list." + (interactive (list (xref--read-identifier "Find definitions of: "))) + (xref--find-definitions identifier nil)) + +;;;###autoload +(defun xref-find-definitions-other-window (identifier) + "Like `xref-find-definitions' but switch to the other window." + (interactive (list (xref--read-identifier "Find definitions of: "))) + (xref--find-definitions identifier 'window)) + +;;;###autoload +(defun xref-find-definitions-other-frame (identifier) + "Like `xref-find-definitions' but switch to the other frame." + (interactive (list (xref--read-identifier "Find definitions of: "))) + (xref--find-definitions identifier 'frame)) + +;;;###autoload +(defun xref-find-references (identifier) + "Find references to the identifier at point. +This command might prompt for the identifier as needed, perhaps +offering the symbol at point as the default. +With prefix argument, or if `xref-prompt-for-identifier' is t, +always prompt for the identifier. If `xref-prompt-for-identifier' +is nil, prompt only if there's no usable symbol at point." + (interactive (list (xref--read-identifier "Find references of: "))) + (xref--find-xrefs identifier 'references identifier nil)) + +;;;###autoload +(defun xref-find-definitions-at-mouse (event) + "Find the definition of identifier at or around mouse click. +This command is intended to be bound to a mouse event." + (interactive "e") + (let ((identifier + (save-excursion + (mouse-set-point event) + (xref-backend-identifier-at-point (xref-find-backend))))) + (if identifier + (xref-find-definitions identifier) + (user-error "No identifier here")))) + +(declare-function apropos-parse-pattern "apropos" (pattern)) + +;;;###autoload +(defun xref-find-apropos (pattern) + "Find all meaningful symbols that match PATTERN. +The argument has the same meaning as in `apropos'." + (interactive (list (read-string + "Search for pattern (word list or regexp): " + nil 'xref--read-pattern-history))) + (require 'apropos) + (let* ((newpat + (if (and (version< emacs-version "28.0.50") + (memq (xref-find-backend) '(elisp etags))) + ;; Handle backends in older Emacs. + (xref-apropos-regexp pattern) + ;; Delegate pattern handling to the backend fully. + ;; The old way didn't work for "external" backends. + pattern))) + (xref--find-xrefs pattern 'apropos newpat nil))) + +(defun xref-apropos-regexp (pattern) + "Return an Emacs regexp from PATTERN similar to `apropos'." + (apropos-parse-pattern + (if (string-equal (regexp-quote pattern) pattern) + ;; Split into words + (or (split-string pattern "[ \t]+" t) + (user-error "No word list given")) + pattern))) + + +;;; Key bindings + +;;;###autoload (define-key esc-map "." #'xref-find-definitions) +;;;###autoload (define-key esc-map "," #'xref-pop-marker-stack) +;;;###autoload (define-key esc-map "?" #'xref-find-references) +;;;###autoload (define-key esc-map [?\C-.] #'xref-find-apropos) +;;;###autoload (define-key ctl-x-4-map "." #'xref-find-definitions-other-window) +;;;###autoload (define-key ctl-x-5-map "." #'xref-find-definitions-other-frame) + + +;;; Helper functions + +(defvar xref-etags-mode--saved nil) + +(define-minor-mode xref-etags-mode + "Minor mode to make xref use etags again. + +Certain major modes install their own mechanisms for listing +identifiers and navigation. Turn this on to undo those settings +and just use etags." + :lighter "" + (if xref-etags-mode + (progn + (setq xref-etags-mode--saved xref-backend-functions) + (kill-local-variable 'xref-backend-functions)) + (setq-local xref-backend-functions xref-etags-mode--saved))) + +(declare-function semantic-symref-instantiate "semantic/symref") +(declare-function semantic-symref-perform-search "semantic/symref") +(declare-function grep-expand-template "grep") +(defvar ede-minor-mode) ;; ede.el + +;;;###autoload +(defun xref-references-in-directory (symbol dir) + "Find all references to SYMBOL in directory DIR. +Return a list of xref values. + +This function uses the Semantic Symbol Reference API, see +`semantic-symref-tool-alist' for details on which tools are used, +and when." + (cl-assert (directory-name-p dir)) + (require 'semantic/symref) + (defvar semantic-symref-tool) + + ;; Some symref backends use `ede-project-root-directory' as the root + ;; directory for the search, rather than `default-directory'. Since + ;; the caller has specified `dir', we bind `ede-minor-mode' to nil + ;; to force the backend to use `default-directory'. + (let* ((ede-minor-mode nil) + (default-directory dir) + ;; FIXME: Remove CScope and Global from the recognized tools? + ;; The current implementations interpret the symbol search as + ;; "find all calls to the given function", but not function + ;; definition. And they return nothing when passed a variable + ;; name, even a global one. + (semantic-symref-tool 'detect) + (case-fold-search nil) + (inst (semantic-symref-instantiate :searchfor symbol + :searchtype 'symbol + :searchscope 'subdirs + :resulttype 'line-and-text))) + (xref--convert-hits (semantic-symref-perform-search inst) + (format "\\_<%s\\_>" (regexp-quote symbol))))) + +(define-obsolete-function-alias + 'xref-collect-references + #'xref-references-in-directory + "27.1") + +;;;###autoload +(defun xref-matches-in-directory (regexp files dir ignores) + "Find all matches for REGEXP in directory DIR. +Return a list of xref values. +Only files matching some of FILES and none of IGNORES are searched. +FILES is a string with glob patterns separated by spaces. +IGNORES is a list of glob patterns for files to ignore." + ;; DIR can also be a regular file for now; let's not advertise that. + (grep-compute-defaults) + (defvar grep-find-template) + (defvar grep-highlight-matches) + (pcase-let* + ((grep-find-template (replace-regexp-in-string "<C>" "<C> -E" + grep-find-template t t)) + (grep-highlight-matches nil) + ;; TODO: Sanitize the regexp to remove Emacs-specific terms, + ;; so that Grep can search for the "relaxed" version. Can we + ;; do that reliably enough, without creating false negatives? + (command (xref--rgrep-command (xref--regexp-to-extended regexp) + files + (file-name-as-directory + (file-name-unquote + (file-local-name (expand-file-name dir)))) + ignores)) + (def default-directory) + (buf (get-buffer-create " *xref-grep*")) + (`(,grep-re ,file-group ,line-group . ,_) (car grep-regexp-alist)) + (status nil) + (hits nil)) + (with-current-buffer buf + (erase-buffer) + (setq default-directory def) + (setq status + (process-file-shell-command command nil t)) + (goto-char (point-min)) + ;; Can't use the exit status: Grep exits with 1 to mean "no + ;; matches found". Find exits with 1 if any of the invocations + ;; exit with non-zero. "No matches" and "Grep program not found" + ;; are all the same to it. + (when (and (/= (point-min) (point-max)) + (not (looking-at grep-re))) + (user-error "Search failed with status %d: %s" status (buffer-string))) + (while (re-search-forward grep-re nil t) + (push (list (string-to-number (match-string line-group)) + (match-string file-group) + (buffer-substring-no-properties (point) (line-end-position))) + hits))) + (xref--convert-hits (nreverse hits) regexp))) + +(define-obsolete-function-alias + 'xref-collect-matches + #'xref-matches-in-directory + "27.1") + +(declare-function tramp-tramp-file-p "tramp") +(declare-function tramp-file-local-name "tramp") + +;; TODO: Experiment with 'xargs -P4' (or any other number). +;; This speeds up either command, even more than rg's '-j4' does. +;; Ripgrep gets jumbled output, though, even with --line-buffered. +;; But Grep seems to be stable. Even without --line-buffered. +(defcustom xref-search-program-alist + '((grep + . + ;; '-s' because 'git ls-files' can output broken symlinks. + "xargs -0 grep <C> -snHE -e <R>") + (ripgrep + . + ;; Note: by default, ripgrep's output order is non-deterministic + ;; (https://github.com/BurntSushi/ripgrep/issues/152) + ;; because it does the search in parallel. You can use the template + ;; without the '| sort ...' part if GNU sort is not available on + ;; your system and/or stable ordering is not important to you. + ;; Note#2: '!*/' is there to filter out dirs (e.g. submodules). + "xargs -0 rg <C> -nH --no-messages -g '!*/' -e <R> | sort -t: -k1,1 -k2n,2" + )) + "Associative list mapping program identifiers to command templates. + +Program identifier should be a symbol, named after the search program. + +The command template must be a shell command (or usually a +pipeline) that will search the files based on the list of file +names that is piped from stdin, separated by null characters. +The template should have the following fields: + + <C> for extra arguments such as -i and --color + <R> for the regexp itself (in Extended format)" + :type '(repeat + (cons (symbol :tag "Program identifier") + (string :tag "Command template"))) + :version "28.1" + :package-version '(xref . "1.0.4")) + +(defcustom xref-search-program 'grep + "The program to use for regexp search inside files. + +This must reference a corresponding entry in `xref-search-program-alist'." + :type `(choice + (const :tag "Use Grep" grep) + (const :tag "Use ripgrep" ripgrep) + (symbol :tag "User defined")) + :version "28.1" + :package-version '(xref . "1.0.4")) + +;;;###autoload +(defun xref-matches-in-files (regexp files) + "Find all matches for REGEXP in FILES. +Return a list of xref values. +FILES must be a list of absolute file names." + (cl-assert (consp files)) + (require 'grep) + (defvar grep-highlight-matches) + (pcase-let* + ((output (get-buffer-create " *project grep output*")) + (`(,grep-re ,file-group ,line-group . ,_) (car grep-regexp-alist)) + (status nil) + (hits nil) + ;; Support for remote files. The assumption is that, if the + ;; first file is remote, they all are, and on the same host. + (dir (file-name-directory (car files))) + (remote-id (file-remote-p dir)) + ;; The 'auto' default would be fine too, but ripgrep can't handle + ;; the options we pass in that case. + (grep-highlight-matches nil) + (command (grep-expand-template (cdr + (or + (assoc + xref-search-program + xref-search-program-alist) + (user-error "Unknown search program `%s'" + xref-search-program))) + (xref--regexp-to-extended regexp)))) + (when remote-id + (require 'tramp) + (setq files (mapcar + (if (tramp-tramp-file-p dir) + #'tramp-file-local-name + #'file-local-name) + files))) + (when (file-name-quoted-p (car files)) + (setq files (mapcar #'file-name-unquote files))) + (with-current-buffer output + (erase-buffer) + (with-temp-buffer + (insert (mapconcat #'identity files "\0")) + (setq default-directory dir) + (setq status + (xref--process-file-region (point-min) + (point-max) + shell-file-name + output + nil + shell-command-switch + command))) + (goto-char (point-min)) + (when (and (/= (point-min) (point-max)) + (not (looking-at grep-re)) + ;; TODO: Show these matches as well somehow? + (not (looking-at "Binary file .* matches"))) + (user-error "Search failed with status %d: %s" status + (buffer-substring (point-min) (line-end-position)))) + (while (re-search-forward grep-re nil t) + (push (list (string-to-number (match-string line-group)) + (match-string file-group) + (buffer-substring-no-properties (point) (line-end-position))) + hits))) + (xref--convert-hits (nreverse hits) regexp))) + +(defun xref--process-file-region ( start end program + &optional buffer display + &rest args) + ;; FIXME: This branching shouldn't be necessary, but + ;; call-process-region *is* measurably faster, even for a program + ;; doing some actual work (for a period of time). Even though + ;; call-process-region also creates a temp file internally + ;; (https://lists.gnu.org/archive/html/emacs-devel/2019-01/msg00211.html). + (if (not (file-remote-p default-directory)) + (apply #'call-process-region + start end program nil buffer display args) + (let ((infile (make-temp-file "ppfr"))) + (unwind-protect + (progn + (write-region start end infile nil 'silent) + (apply #'process-file program infile buffer display args)) + (delete-file infile))))) + +(defun xref--rgrep-command (regexp files dir ignores) + (require 'find-dired) ; for `find-name-arg' + (defvar grep-find-template) + (defvar find-name-arg) + ;; `shell-quote-argument' quotes the tilde as well. + (cl-assert (not (string-match-p "\\`~" dir))) + (grep-expand-template + grep-find-template + regexp + (concat (shell-quote-argument "(") + " " find-name-arg " " + (mapconcat + #'shell-quote-argument + (split-string files) + (concat " -o " find-name-arg " ")) + " " + (shell-quote-argument ")")) + (shell-quote-argument dir) + (xref--find-ignores-arguments ignores dir))) + +(defun xref--find-ignores-arguments (ignores dir) + "Convert IGNORES and DIR to a list of arguments for 'find'. +IGNORES is a list of glob patterns. DIR is an absolute +directory, used as the root of the ignore globs." + (cl-assert (not (string-match-p "\\`~" dir))) + (if (not ignores) + "" + (concat + (shell-quote-argument "(") + " -path " + (mapconcat + (lambda (ignore) + (when (string-match-p "/\\'" ignore) + (setq ignore (concat ignore "*"))) + (shell-quote-argument (if (string-match "\\`\\./" ignore) + (replace-match dir t t ignore) + (if (string-prefix-p "*" ignore) + ignore + (concat "*/" ignore))))) + ignores + " -o -path ") + " " + (shell-quote-argument ")") + " -prune -o "))) + +(defun xref--regexp-to-extended (str) + (replace-regexp-in-string + ;; FIXME: Add tests. Move to subr.el, make a public function. + ;; Maybe error on Emacs-only constructs. + "\\(?:\\\\\\\\\\)*\\(?:\\\\[][]\\)?\\(?:\\[.+?\\]\\|\\(\\\\?[(){}|]\\)\\)" + (lambda (str) + (cond + ((not (match-beginning 1)) + str) + ((eq (length (match-string 1 str)) 2) + (concat (substring str 0 (match-beginning 1)) + (substring (match-string 1 str) 1 2))) + (t + (concat (substring str 0 (match-beginning 1)) + "\\" + (match-string 1 str))))) + str t t)) + +(defun xref--regexp-syntax-dependent-p (str) + "Return non-nil when STR depends on the buffer's syntax. +Such as the current syntax table and the applied syntax properties." + (let ((case-fold-search nil)) + (string-match-p (rx + (or string-start (not (in ?\\))) + (0+ (= 2 ?\\)) + ?\\ + (in ?b ?B ?< ?> ?w ?W ?_ ?s ?S)) + str))) + +(defvar xref--last-file-buffer nil) +(defvar xref--temp-buffer-file-name nil) + +(defun xref--convert-hits (hits regexp) + (let (xref--last-file-buffer + (tmp-buffer (generate-new-buffer " *xref-temp*"))) + (unwind-protect + (mapcan (lambda (hit) (xref--collect-matches hit regexp tmp-buffer)) + hits) + (kill-buffer tmp-buffer)))) + +(defun xref--collect-matches (hit regexp tmp-buffer) + (pcase-let* ((`(,line ,file ,text) hit) + (remote-id (file-remote-p default-directory)) + (file (and file (concat remote-id file))) + (buf (xref--find-file-buffer file)) + (syntax-needed (xref--regexp-syntax-dependent-p regexp))) + (if buf + (with-current-buffer buf + (save-excursion + (goto-char (point-min)) + (forward-line (1- line)) + (xref--collect-matches-1 regexp file line + (line-beginning-position) + (line-end-position) + syntax-needed))) + ;; Using the temporary buffer is both a performance and a buffer + ;; management optimization. + (with-current-buffer tmp-buffer + (erase-buffer) + (when (and syntax-needed + (not (equal file xref--temp-buffer-file-name))) + (insert-file-contents file nil 0 200) + ;; Can't (setq-local delay-mode-hooks t) because of + ;; bug#23272, but the performance penalty seems minimal. + (let ((buffer-file-name file) + (inhibit-message t) + message-log-max) + (ignore-errors + (set-auto-mode t))) + (setq-local xref--temp-buffer-file-name file) + (setq-local inhibit-read-only t) + (erase-buffer)) + (insert text) + (goto-char (point-min)) + (xref--collect-matches-1 regexp file line + (point) + (point-max) + syntax-needed))))) + +(defun xref--collect-matches-1 (regexp file line line-beg line-end syntax-needed) + (let (match-pairs matches) + (when syntax-needed + (syntax-propertize line-end)) + (while (and + ;; REGEXP might match an empty string. Or line. + (or (null match-pairs) + (> (point) line-beg)) + (re-search-forward regexp line-end t)) + (push (cons (match-beginning 0) + (match-end 0)) + match-pairs)) + (setq match-pairs (nreverse match-pairs)) + (while match-pairs + (let* ((beg-end (pop match-pairs)) + (beg-column (- (car beg-end) line-beg)) + (end-column (- (cdr beg-end) line-beg)) + (loc (xref-make-file-location file line beg-column)) + (summary (buffer-substring (if matches (car beg-end) line-beg) + (if match-pairs + (caar match-pairs) + line-end)))) + (when matches + (cl-decf beg-column (- (car beg-end) line-beg)) + (cl-decf end-column (- (car beg-end) line-beg))) + (add-face-text-property beg-column end-column 'xref-match + t summary) + (push (xref-make-match summary loc (- end-column beg-column)) + matches))) + (nreverse matches))) + +(defun xref--find-file-buffer (file) + (unless (equal (car xref--last-file-buffer) file) + (setq xref--last-file-buffer + ;; `find-buffer-visiting' is considerably slower, + ;; especially on remote files. + (cons file (get-file-buffer file)))) + (cdr xref--last-file-buffer)) + +(provide 'xref) + +;;; xref.el ends here diff --git a/emacs.d/elpa/xterm-color-20200605.2017/xterm-color-autoloads.el b/emacs.d/elpa/xterm-color-20200605.2017/xterm-color-autoloads.el new file mode 100644 index 0000000..4d97511 --- /dev/null +++ b/emacs.d/elpa/xterm-color-20200605.2017/xterm-color-autoloads.el @@ -0,0 +1,82 @@ +;;; xterm-color-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "xterm-color" "xterm-color.el" (0 0 0 0)) +;;; Generated autoloads from xterm-color.el + +(autoload 'xterm-color-filter-strip "xterm-color" "\ +Translate ANSI color sequences in STRING into text properties. +Return new STRING with text properties applied. + +In order to get maximum performance, this function strips text properties +if they are present in STRING. + +\(fn STRING)" nil nil) + +(autoload 'xterm-color-filter "xterm-color" "\ +Translate ANSI color sequences in STRING into text properties. +Return new STRING with text properties applied. + +This function checks if `xterm-color-preserve-properties' is non-nil +and only calls `xterm-color-filter-strip' on substrings that do not +have text properties applied (passing through the rest unmodified). +Preserving properties in this fashion is not very robust as there may +be situations where text properties are applied on ANSI data, which +will desync the state machine. + +Preserving properties works ok with and is really meant for eshell. + +This can be inserted into `comint-preoutput-filter-functions'. + +\(fn STRING)" nil nil) + +(autoload 'xterm-color-256 "xterm-color" "\ + + +\(fn COLOR)" nil nil) + +(autoload 'xterm-color-colorize-buffer "xterm-color" "\ +Apply `xterm-color-filter' to current buffer, and replace its contents. +Colors are applied using 'face, unless font-lock-mode is active, in +which case 'font-lock-face is used. Operation with font-lock mode active +is not recommended. + +If USE-OVERLAYS is non-nil, colors are applied to the buffer using overlays +instead of text properties. A C-u prefix arg causes overlays to be used. + +\(fn &optional USE-OVERLAYS)" t nil) + +(autoload 'xterm-color-clear-cache "xterm-color" "\ +Clear xterm color face attribute cache. +You may want to call this if you change `xterm-color-names' or +`xterm-color-names-bright' at runtime and you want to see the changes +take place in a pre-existing buffer that has had xterm-color initialized. + +Since the cache is buffer-local and created on-demand when needed, this has no +effect when called from a buffer that does not have a cache." t nil) + +(autoload 'xterm-color-test "xterm-color" "\ +Create, display and render a new buffer containing ANSI control sequences." t nil) + +(autoload 'xterm-color-test-raw "xterm-color" "\ +Create and display a new buffer containing ANSI SGR control sequences. +ANSI sequences are not processed. One can use a different Emacs package, +such as ansi-color.el to do so. This is really meant to be used for easy +comparisons/benchmarks with libraries that offer similar functionality." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "xterm-color" '("+xterm-color--table-256+" "xterm-color-"))) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; xterm-color-autoloads.el ends here diff --git a/emacs.d/elpa/xterm-color-20200605.2017/xterm-color-pkg.el b/emacs.d/elpa/xterm-color-20200605.2017/xterm-color-pkg.el new file mode 100644 index 0000000..dfa6653 --- /dev/null +++ b/emacs.d/elpa/xterm-color-20200605.2017/xterm-color-pkg.el @@ -0,0 +1,2 @@ +;;; Generated package description from xterm-color-20200605.2017/xterm-color.el -*- no-byte-compile: t -*- +(define-package "xterm-color" "20200605.2017" "ANSI, XTERM 256 and Truecolor support" '((emacs "24.4")) :commit "1a4012854c69a5cdaeb5a73d2ad705011892fca3" :authors '(("xristos" . "xristos@sdf.org")) :maintainer '("xristos" . "xristos@sdf.org") :keywords '("faces") :url "https://github.com/atomontage/xterm-color") diff --git a/emacs.d/elpa/xterm-color-20200605.2017/xterm-color.el b/emacs.d/elpa/xterm-color-20200605.2017/xterm-color.el new file mode 100644 index 0000000..e786513 --- /dev/null +++ b/emacs.d/elpa/xterm-color-20200605.2017/xterm-color.el @@ -0,0 +1,938 @@ +;;; xterm-color.el --- ANSI, XTERM 256 and Truecolor support -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2020 xristos@sdf.org +;; All rights reserved + +;; Modified: 2020-05-10 +;; Version: 2.0 +;; Package-Version: 20200605.2017 +;; Package-Commit: 1a4012854c69a5cdaeb5a73d2ad705011892fca3 +;; Author: xristos <xristos@sdf.org> +;; URL: https://github.com/atomontage/xterm-color +;; Package-Requires: ((emacs "24.4")) +;; Keywords: faces + +;; Redistribution and use in source and binary forms, with or without +;; modification, are permitted provided that the following conditions +;; are met: +;; +;; * Redistributions of source code must retain the above copyright +;; notice, this list of conditions and the following disclaimer. +;; +;; * Redistributions in binary form must reproduce the above +;; copyright notice, this list of conditions and the following +;; disclaimer in the documentation and/or other materials +;; provided with the distribution. +;; +;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +;; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +;; POSSIBILITY OF SUCH DAMAGE. + +;;; Commentary: +;; +;; Translate ANSI control sequences into text properties through state machine +;; emulation. This provides a far more accurate, comprehensive result than +;; `ansi-color.el' that is built-into Emacs, without compromising on performance. +;; +;; Please see README.org for documentation including example configurations. +;; +;;; Notes: +;; +;; Unsupported SGR attributes: 5 (slow blink), 6 (rapid blink), 8 (conceal), +;; 10 (primary font), 11-19 (alternative font), 20 (fraktur), 21 (double underline), +;; 25 (blink off), 29 (reveal), 52 (encircled), 60-65 (ideogram) +;; +;; Most of these can not be mapped to Emacs face properties. The rest may be +;; supported in a future release. +;; +;; Supported SGR attributes: Look at `xterm-color--dispatch-SGR'. +;; SGR attribute 1 is rendered as bright unless `xterm-color-use-bold-for-bright' +;; is non-nil which will, if current font has a bold variant, switch to bold. +;; SGR attributes 38 and 48 are supported in both their 256 color and truecolor +;; (24-bit) variants. + +;;; Test: +;; +;; M-x xterm-color-test +;; +;; In shell or eshell: +;; +;; perl tests/xterm-colortest && perl tests/256colors2.pl +;; +;; printf "\x1b[0;1;3;4;35;51mThis is only a test\x1b[0m\n" +;; +;; Comparison with ansi-color.el: +;; +;; M-x xterm-color-test-raw then M-x xterm-color-colorize-buffer +;; +;; and contrast with +;; +;; M-x xterm-color-test-raw then M-: (ansi-color-apply-on-region (point-min) (point-max)) +;; +;; Use `xterm-color--bench' for benchmarks during development. + +;;; Code: + +(require 'subr-x) +(require 'cl-lib) + +(defgroup xterm-color nil + "Translate ANSI control sequences to text properties." + :prefix "xterm-color-" + :group 'processes) + + +;;; +;;; CUSTOM +;;; + + +(defcustom xterm-color-debug nil + "If non-nil, print ANSI state machine debug information in *Messages*." + :type 'boolean + :group 'xterm-color) + +(defcustom xterm-color-use-bold-for-bright nil + "If non-nil, render bright foreground attribute as bold." + :type 'boolean + :group 'xterm-color) + +(defcustom xterm-color-names + ["#192033" ; black + "#A93F43" ; red + "#59963A" ; green + "#BE8A2D" ; yellow + "#4068A3" ; blue + "#7F60A7" ; magenta + "#4E9B9B" ; cyan + "#7E8A90"] ; white + "Default colors to use as regular ANSI colors." + :type '(vector string string string string string string string string) + :group 'xterm-color) + +(defcustom xterm-color-names-bright + ["#666666" ; black + "#EC6261" ; red + "#ADCF44" ; green + "#F0C649" ; yellow + "#63B4F6" ; blue + "#CB77F9" ; magenta + "#86D7DB" ; cyan + "#D3D2D1"] ; white + "Default colors to use as bright ANSI colors." + :type '(vector string string string string string string string string) + :group 'xterm-color) + + +;;; +;;; Buffer locals, used by state machine +;;; + + +(defvar-local xterm-color-preserve-properties nil + "If non-nil, preserve existing text properties on input about to be filtered. +Effectively this skips ANSI control sequence processing for input parts +that have text properties applied. This should be nil most of the time. +It is really meant for and works ok with eshell.") + +(defvar-local xterm-color-render t + "If non-nil, render SGR attributes. Otherwise, discard them. +The latter enables processing and filtering out ANSI control sequences, +without applying them to the text.") + +(defvar-local xterm-color--current-fg nil) + +(defvar-local xterm-color--current-bg nil) + +(defvar-local xterm-color--char-list nil + "List of characters that the current ANSI color applies to. +All characters are stored in reverse, LIFO, order.") + +(defvar-local xterm-color--CSI-list nil + "List of current ANSI CSI sequence bytes (characters). +All characters are stored in reverse, LIFO, order.") + +(defvar-local xterm-color--state :char + "Current state of ANSI state machine. + +Can be one of :char, :set-char, :ansi-esc, :ansi-csi, :ansi-osc, +:ansi-osc-esc.") + +(defvar-local xterm-color--attributes 0 + "Bitvector that keeps track of state machine attributes. + +These are: bright, italic, underline, strike-through, inverse-color, +frame, overline.") + +(defvar-local xterm-color--face-cache nil + "Cache for auto-generated face attributes.") + +(defvar-local xterm-color--truecolor-face-cache nil + "Cache for auto-generated face attributes.") + + +;;; +;;; Constants +;;; + + +(defconst +xterm-color--table-256+ [0 #x5f #x87 #xaf #xd7 #xff]) + + +;;; +;;; Internal API +;;; + +;; The face caching scheme requires an integer width of at least 56 bits +;; to cache faces derived from truecolor (24-bit) ANSI sequences. Truecolor +;; support is therefore disabled on e.g. machines with 32-bit integers. +(defvar xterm-color--support-truecolor (>= (1+ (floor (log most-positive-fixnum 2))) + 59)) + +(cl-defun xterm-color--string-properties (string) + (cl-loop + with pos = 0 and result do + (let ((next-pos (next-property-change pos string))) + (if next-pos + (progn + (push (list pos (text-properties-at pos string) (substring string pos next-pos)) result) + (setq pos next-pos)) + (push (list pos (text-properties-at pos string) (substring string pos)) result) + (cl-return-from xterm-color--string-properties (nreverse result)))))) + +(defun xterm-color--convert-text-properties-to-overlays (beg end) + "Transform face text properties between BEG and END, to equivalent overlays." + (save-excursion + (goto-char beg) + (let ((face-prop (if (or (get-text-property (point) 'font-lock-face) + (next-single-property-change (point) 'font-lock-face)) + 'font-lock-face 'face))) + (while (< (point) end) + (let* ((pos (point)) + (current-value (get-text-property pos face-prop)) + (next-change (next-single-property-change pos face-prop nil end))) + (when current-value + (let ((ov (make-overlay pos next-change))) + (overlay-put ov face-prop current-value) + (overlay-put ov 'xterm-color t))) + (goto-char next-change))) + (remove-text-properties beg end (list 'xterm-color nil face-prop nil))))) + +(defun xterm-color--message (format-string &rest args) + "Call `message' with FORMAT-STRING and ARGS. +Also see `xterm-color-debug'." + (when xterm-color-debug + (let ((message-truncate-lines t)) + (message "xterm-color: %s" (apply #'format format-string args)) + (message nil)))) + + +;;; +;;; SGR state machine +;;; + + +(cl-defmacro xterm-color--with-SGR-constants (&body body) + (declare (indent defun)) + `(cl-symbol-macrolet + ((+bright+ 1) + (+italic+ 2) + (+underline+ 4) + (+strike-through+ 8) + (+negative+ 16) + (+frame+ 32) + (+overline+ 64)) + ,@body)) + +(cl-defmacro xterm-color--create-SGR-table ((attrib SGR-list) &body body) + "Create an iteration/dispatch table based on provided rules that match SGR attributes. +For each attribute in SGR-LIST, check to see if it matches a rule in BODY and +evaluate the rule body if that is the case. + +ATTRIB must be a symbol that is bound to SGR-LIST attributes in BODY. +SGR-LIST must be a list of SGR attributes (integers) in LIFO order. +BODY must contain rules with each rule being a list of form: + + (:match (condition &key (skip 1)) rule-body-form..) + +CONDITION must be a Lisp form which is evaluated as part of a COND +condition clause. If it is an atom, it is rewritten to (eq CONDITION ATTRIB). +Otherwise it is used as is. As per COND statement, if CONDITION evaluates +to non-nil, rule body forms are evaluated as part of the body of the COND clause. + +SKIP, if given, must be an integer specifying the number of elements that +should be skipped before the next iteration. The default is 1, +going down SGR-LIST one element at a time." + (declare (indent defun)) + `(xterm-color--with-SGR-constants + (cl-macrolet + ;; The following macros should be used in rule bodies + ((set-a! (attr) `(setq xterm-color--attributes + (logior xterm-color--attributes ,attr))) + (unset-a! (attr) `(setq xterm-color--attributes + (logand xterm-color--attributes + (logand #xff (lognot ,attr))))) + + (set-f! (fg-color) `(setq xterm-color--current-fg ,fg-color)) + (set-b! (bg-color) `(setq xterm-color--current-bg ,bg-color)) + + (set-truecolor! (r g b current-color) + ;; A single integer must be able to + ;; hold and distinguish between: + ;; + ;; - 24bit truecolor values + ;; - ANSI colors + ;; - XTerm 256 colors + ;; + ;; The following packing scheme achieves that. + `(setq ,current-color + (logior (ash r 25) (ash g 17) (ash b 9) + #x100))) + + (reset! () `(setq xterm-color--current-fg nil + xterm-color--current-bg nil + xterm-color--attributes 0))) + (cl-loop + for ,attrib = (cl-first ,SGR-list) + while ,SGR-list do + (cond + ,@(cl-loop + for skip = 1 + for (tag (c . rest) . rule-body) in body + when (not (eq tag :match)) do + (error "Rule (%s (%s..)..) does not start with :match" tag c) + when rest do + (setq skip (plist-get rest :skip)) + (when (or (null skip) (cddr rest)) + (error "Rule (%s (%s..)..) has malformed arguments: %s" tag c rest)) + ;; Condition part of COND + collect `(,(if (atom c) `(eq ,c ,attrib) c) + ;; Body of COND + ,@rule-body + (setq ,SGR-list + ,(if (> skip 1) + `(nthcdr ,skip ,SGR-list) + `(cdr ,SGR-list))))) + (t (xterm-color--message "Not implemented SGR attribute %s" ,attrib) + (setq ,SGR-list (cdr ,SGR-list)))))))) + +(defsubst xterm-color--dispatch-SGR (SGR-list) + "Update state machine based on SGR-LIST (list of SGR attributes /integers)." + (xterm-color--create-SGR-table (elem SGR-list) + (:match (0) (reset!)) ; RESET everything + (:match ((<= 30 elem 37)) (set-f! (- elem 30))) ; ANSI FG color + (:match ((<= 40 elem 47)) (set-b! (- elem 40))) ; ANSI BG color + (:match (39) (set-f! nil)) ; RESET FG color (switch to default) + (:match (49) (set-b! nil)) ; RESET BG color (switch to default) + (:match (1) (set-a! +bright+)) + (:match (2) (unset-a! +bright+)) + (:match (22) (unset-a! +bright+)) + + (:match ((and (eq 38 (cl-first SGR-list)) + (eq 2 (cl-second SGR-list))) ; Truecolor (24-bit) FG color + :skip 5) + (when xterm-color--support-truecolor + (if-let ((r (cl-third SGR-list)) + (g (cl-fourth SGR-list)) + (b (cl-fifth SGR-list))) + (if (or (> r 255) (> g 255) (> b 255)) + (xterm-color--message "SGR 38;2;%s;%s;%s exceeds range" + r g b) + (set-truecolor! r g b xterm-color--current-fg)) + (xterm-color--message "SGR 38;2;%s;%s;%s error, expected 38;2;R;G;B" + r g b)))) + (:match ((and (eq 38 (cl-first SGR-list)) + (eq 5 (cl-second SGR-list))) + :skip 3) ; XTERM 256 FG color + (if-let ((color (cl-third SGR-list))) + (if (> color 255) + (xterm-color--message "SGR 38;5;%s exceeds range" color) + (set-f! color)) + (xterm-color--message "SGR 38;5;%s error, expected 38;5;COLOR" + color))) + + (:match ((and (eq 48 (cl-first SGR-list)) + (eq 2 (cl-second SGR-list))) ; Truecolor (24-bit) BG color + :skip 5) + (when xterm-color--support-truecolor + (if-let ((r (cl-third SGR-list)) + (g (cl-fourth SGR-list)) + (b (cl-fifth SGR-list))) + (if (or (> r 255) (> g 255) (> b 255)) + (xterm-color--message "SGR 48;2;%s;%s;%s exceeds range" + r g b) + (set-truecolor! r g b xterm-color--current-bg)) + (xterm-color--message "SGR 48;2;%s;%s;%s error, expected 48;2;R;G;B" + r g b)))) + + (:match ((and (eq 48 (cl-first SGR-list)) + (eq 5 (cl-second SGR-list))) + :skip 3) ; XTERM 256 BG color + (if-let ((color (cl-third SGR-list))) + (if (> color 255) + (xterm-color--message "SGR 48;5;%s exceeds range" color) + (set-b! color)) + (xterm-color--message "SGR 48;5;%s error, expected 48;5;COLOR" + color))) + (:match ((<= 90 elem 97)) ; AIXTERM hi-intensity FG + ;; Rather than setting bright, which would be wrong, + ;; rescale color to fall within 8-15 so that it gets + ;; mapped to xterm-color-names-bright by xterm-color-256 + (set-f! (- elem 82))) + ;; Same for BG, rescale to 8-15 + (:match ((<= 100 elem 107)) (set-b! (- elem 92))) ; AIXTERM hi-intensity BG + + (:match (51) (set-a! +frame+)) + (:match (53) (set-a! +overline+)) + (:match (54) (unset-a! +frame+)) + (:match (55) (unset-a! +overline+)) + (:match (4) (set-a! +underline+)) + (:match (24) (unset-a! +underline+)) + (:match (3) (set-a! +italic+)) + (:match (23) (unset-a! +italic+)) + (:match (9) (set-a! +strike-through+)) + (:match (29) (unset-a! +strike-through+)) + (:match (7) (set-a! +negative+)) + (:match (27) (unset-a! +negative+)))) + +(defsubst xterm-color--SGR-attributes (list) + "Convert LIFO list of SGR characters to FIFO list of SGR attributes (integers). + +Returns FIFO list of SGR attributes or nil on errors. + +Characters must be in the ASCII set 0-9 (decimal 48 to 57) and are converted +to integer digits by subtracting 48 from each character. E.g. Character 48 +is converted to integer digit 0, character 49 to integer digit1.. +Character 59 (;) is not converted but signifies that all accumulated integer +digits should be reversed and combined into a single integer (SGR attribute). + +Examples: + +Given (48) return (0) +Given (59) return (0 0) +Given (48 49 50) return (210) +Given (48 49 50 59 50 50 59 48 49) return (10 22 210)" + (cl-loop + with mul = 1 and n = 0 and ret + for c in list do + (if (/= 59 c) + (let ((e (- c 48))) + (unless (<= 0 e 9) + (xterm-color--message "Invalid SGR attribute %s" c) + (cl-return)) + (cl-incf n (* mul e)) + (setq mul (* mul 10))) + (push n ret) + (setq n 0 mul 1)) + finally return (push n ret))) + + +;;; +;;; CSI state machine +;;; + + +(defsubst xterm-color--dispatch-CSI () + "Update state machine based on CSI parameters collected so far. +Parameters are taken from `xterm-color--CSI-list' which stores them +in LIFO order." + (let* ((csi xterm-color--CSI-list) + (term (car csi)) ; final parameter, terminator + (params (cdr csi))) ; rest of parameters, LIFO order + (setq xterm-color--CSI-list nil) + (cond ((eq ?m term) + ;; SGR + (let ((SGR-list (if (null params) '(0) + (xterm-color--SGR-attributes params)))) + (when SGR-list + (xterm-color--dispatch-SGR SGR-list)))) + (t + (xterm-color--message "%s CSI not implemented" csi))))) + +(defmacro xterm-color--with-ANSI-macro-helpers (&rest body) + (declare (indent defun)) + `(xterm-color--with-SGR-constants + (cl-symbol-macrolet ((fg xterm-color--current-fg) + (bg xterm-color--current-bg) + (attrs xterm-color--attributes) + (bold-bright xterm-color-use-bold-for-bright)) + (cl-macrolet + ((out! (x) `(push ,x result)) + (push-char! (c) `(push ,c xterm-color--char-list)) + (push-csi! (c) `(push ,c xterm-color--CSI-list)) + (state! (s) `(setq state ,s)) + (graphics? () `(or fg bg (/= attrs 0))) + (has? (attr) `(/= (logand ,attr attrs) 0)) + (fmt-24bit (color) `(format "#%06x" ,color)) + (fmt-256 (color) `(xterm-color-256 ,color)) + + ;; Unpacks a packed truecolor value (as stored in + ;; `xterm-color--current-fg' and `xterm-color--current-fg'. + (unpack (color) `(ash ,color -9)) + + ;; To avoid hash collisions, a different packing scheme is used + ;; for hash table keys. It can encode two colors (foreground + ;; and background) that can either be truecolor 24bit or XTerm 256 + ;; color 8bit. XTerm 256 color values subsume ANSI colors, a + ;; separate encoding scheme is not needed. + ;; + ;; The scheme used also accounts for the combination of a truecolor + ;; with an XTerm 256 color as part of the same hashed entry. Since + ;; two different hash tables are used to work around 32bit Emacs + ;; limited integer range, two packing schemes are needed: + ;; + ;; High< 25 bits >Low + ;; ATTR[7 bits]BG[9 bits]FG[9 bits] where BG and FG are each + ;; encoded as the 8bit color value shifted left by 1 and combined + ;; with a flag bit which is set when the color is present. + ;; + ;; High< 59 bits >Low + ;; ATTR[7 bits]BG[26 bits]FG[26 bits] where BG and FG are each + ;; encoded as the 24bit (RGB) or 8bit color value shifted left by + ;; 2 and combined with 2 flag bits that are set when the value + ;; is 24bit (high bit) and when the color is present (low bit). + (pack-256 (color) `(if ,color (logior (ash ,color 1) 1) 0)) + (pack-24bit (color) `(if ,color + (if (> ,color 255) + (logior (ash (unpack ,color) 2) 3) + (logior (ash ,color 2) 1)) + 0)) + ;; If at least one of foreground / background color is a 24bit + ;; truecolor value: Second packing scheme with + ;; `xterm-color--truecolor-face-cache' is used. + ;; + ;; Every other case, including when no colors are present: + ;; First packing scheme with `xterm-color--face-cache' is used. + (pack-key-into (k) `(cond ((or (and fg (> fg 255)) + (and bg (> bg 255))) + ;; At least one truecolor 24bit value + (setq ,k (logior (ash attrs 52) + (ash (pack-24bit bg) 26) + (pack-24bit fg))) + xterm-color--truecolor-face-cache) + (t ;; No truecolor 24bit value + (setq ,k (logior (ash attrs 18) + (ash (pack-256 bg) 9) + (pack-256 fg))) + xterm-color--face-cache))) + + (face! (k v) `(setq plistf (plist-put plistf ,k ,v))) + (make-color-fg () `(if (and bold-bright + (< fg 256) + (or (has? +bright+) (<= 8 fg 15))) + (progn (face! :weight 'bold) + (face! :foreground + (fmt-256 (if (<= 8 fg) (- fg 8) fg)))) + (face! :foreground + (if (> fg 255) + (fmt-24bit (unpack fg)) + (fmt-256 (if (and (<= fg 7) (has? +bright+)) + (+ fg 8) + fg)))))) + (make-color-bg () `(face! :background (cond ((> bg 255) (fmt-24bit (unpack bg))) + (t (fmt-256 bg))))) + (make-face () `(let* (k + (table (pack-key-into k))) + (or (gethash k table) + (let (plistf) + (when (has? +italic+) (face! :slant 'italic)) + (when (has? +underline+) (face! :underline t)) + (when (has? +strike-through+) (face! :strike-through t)) + (when (has? +negative+) (face! :inverse-video t)) + (when (has? +overline+) (face! :overline t)) + (when (has? +frame+) (face! :box t)) + + (cond (fg (make-color-fg)) + (t (when (and bold-bright (has? +bright+)) + (face! :weight 'bold)))) + + (when bg (make-color-bg)) + (puthash k plistf table))))) + (maybe-fontify () '(when xterm-color--char-list + (let ((s (concat (nreverse xterm-color--char-list)))) + (when (and xterm-color-render (graphics?)) + (add-text-properties + 0 (length s) + (list 'xterm-color t + (if font-lock-mode 'font-lock-face 'face) + (make-face)) + s)) + (out! s)) + (setq xterm-color--char-list nil)))) + ,@body)))) + + +;;; +;;; Exports +;;; + + +;;;###autoload +(defun xterm-color-filter-strip (string) + "Translate ANSI color sequences in STRING into text properties. +Return new STRING with text properties applied. + +In order to get maximum performance, this function strips text properties +if they are present in STRING." + (unless xterm-color--face-cache + (setq xterm-color--face-cache + (make-hash-table :weakness 'value))) + (unless xterm-color--truecolor-face-cache + (setq xterm-color--truecolor-face-cache + (make-hash-table :weakness 'value))) + (xterm-color--with-ANSI-macro-helpers + (cl-loop + with state = xterm-color--state and result + for char across string do + (cond + ((eq state :char) + (cond + ((eq char 27) ; ESC + (maybe-fontify) + (state! :ansi-esc)) + (t + (if (graphics?) + (push-char! char) + (out! (list char)))))) + ((eq state :ansi-esc) + (cond ((eq char ?\[) + (state! :ansi-csi)) + ((eq char ?\]) + (state! :ansi-osc)) + ((or (eq char ?\() + (eq char ?\))) + (state! :set-char)) + (t + (push-char! char) + (state! :char)))) + ((eq state :ansi-csi) + (push-csi! char) + (when (and (>= char #x40) + (<= char #x7e)) + (xterm-color--dispatch-CSI) + (state! :char))) + ((eq state :ansi-osc) + ;; OSC sequences are skipped + (cond ((eq char 7) + (state! :char)) + ((eq char 27) + ;; ESC + (state! :ansi-osc-esc)))) + ((eq state :ansi-osc-esc) + (cond ((eq char ?\\) + (state! :char)) + (t (state! :ansi-osc)))) + ((eq state :set-char) + (xterm-color--message "%s SET-CHAR not implemented" char) + (state! :char))) + finally return + (progn (when (eq state :char) (maybe-fontify)) + (setq xterm-color--state state) + (apply 'concat (nreverse result)))))) + +;;;###autoload +(defun xterm-color-filter (string) + "Translate ANSI color sequences in STRING into text properties. +Return new STRING with text properties applied. + +This function checks if `xterm-color-preserve-properties' is non-nil +and only calls `xterm-color-filter-strip' on substrings that do not +have text properties applied (passing through the rest unmodified). +Preserving properties in this fashion is not very robust as there may +be situations where text properties are applied on ANSI data, which +will desync the state machine. + +Preserving properties works ok with and is really meant for eshell. + +This can be inserted into `comint-preoutput-filter-functions'." + (if (not xterm-color-preserve-properties) + (xterm-color-filter-strip string) + (cl-loop + with result + for (_ props substring) in (xterm-color--string-properties string) do + (push (if props substring (xterm-color-filter-strip substring)) + result) + finally return (apply 'concat (nreverse result))))) + +;;;###autoload +(defun xterm-color-256 (color) + (cond ((and (>= color 232) + (<= color 255)) + ;; Grayscale + (let ((val (+ 8 (* (- color 232) 10)))) + (format "#%02x%02x%02x" val val val))) + ((<= color 7) + ;; Normal ANSI color + (aref xterm-color-names color)) + ((and (>= color 8) + (<= color 15)) + ;; Bright ANSI color + (aref xterm-color-names-bright (- color 8))) + (t (let* ((color (- color 16)) + (red (/ color 36)) + (color (mod color 36)) + (green (/ color 6)) + (color (mod color 6)) + (blue color)) + ;; XTERM 256 color + (format "#%02x%02x%02x" + (aref +xterm-color--table-256+ red) + (aref +xterm-color--table-256+ green) + (aref +xterm-color--table-256+ blue)))))) + + +;;; +;;; Interactive +;;; + + +;;;###autoload +(cl-defun xterm-color-colorize-buffer (&optional use-overlays) + "Apply `xterm-color-filter' to current buffer, and replace its contents. +Colors are applied using 'face, unless font-lock-mode is active, in +which case 'font-lock-face is used. Operation with font-lock mode active +is not recommended. + +If USE-OVERLAYS is non-nil, colors are applied to the buffer using overlays +instead of text properties. A C-u prefix arg causes overlays to be used." + (interactive "P") + (let ((read-only-p buffer-read-only)) + (when read-only-p + (unless (y-or-n-p "Buffer is read only, continue colorizing? ") + (cl-return-from xterm-color-colorize-buffer)) + (read-only-mode -1)) + (insert (xterm-color-filter (delete-and-extract-region (point-min) (point-max)))) + (when (and xterm-color-render use-overlays) + (xterm-color--convert-text-properties-to-overlays (point-min) (point-max))) + (goto-char (point-min)) + (when read-only-p (read-only-mode 1)))) + +;;;###autoload +(defun xterm-color-clear-cache () + "Clear xterm color face attribute cache. +You may want to call this if you change `xterm-color-names' or +`xterm-color-names-bright' at runtime and you want to see the changes +take place in a pre-existing buffer that has had xterm-color initialized. + +Since the cache is buffer-local and created on-demand when needed, this has no +effect when called from a buffer that does not have a cache." + (interactive) + (and xterm-color--face-cache + (clrhash xterm-color--face-cache) + (xterm-color--message "Cleared face attribute cache")) + (and xterm-color--truecolor-face-cache + (clrhash xterm-color--truecolor-face-cache) + (xterm-color--message "Cleared truecolor face attribute cache"))) + + +;;; +;;; Tests +;;; + + +(defmacro xterm-color--bench (path &optional repetitions) + `(benchmark-run-compiled ,repetitions + (with-temp-buffer + (insert-file-contents-literally ,path) + (xterm-color-colorize-buffer)))) + +(defvar xterm-color--test-do-filter t) + +(cl-defmacro xterm-color--with-tests (&body body) + `(cl-labels ((ansi-filter (msg &rest args) + (insert + (if xterm-color--test-do-filter + (xterm-color-filter + (apply #'format msg args)) + (apply #'format msg args)))) + (test (name &rest attribs) + (ansi-filter "\x1b[0;%smThis is only a test!\x1b[0m\t --[ %s\n" + (mapconcat #'identity attribs ";") + name))) + ,@body)) + +(defun xterm-color--test-ansi () + (xterm-color--with-tests + (let ((test-attributes + '(("1" . "bright") + ("51" . "frame") + ("3" . "italic") + ("4" . "underline") + ("7" . "negative") + ("9" . "strike through") + ("53" . "overline") + ("1;51" . "bright + frame") + ("1;3" . "bright + italic") + ("1;4" . "bright + underline") + ("1;7" . "bright + negative") + ("1;9" . "bright + strike through") + ("1;53" . "bright + overline")))) + + ;; Attributes (no color) + (insert "* ANSI attributes (default colors)\n") + + (if xterm-color-use-bold-for-bright + (insert " Expect: Bold instead of bright") + (insert " Expect: Bright not to be rendered since no foreground color is set")) + (insert "\n\n") + + (cl-loop for (attrib . name) in test-attributes + do (test name attrib) + finally (insert "\n")) + + (insert "* ANSI attributes (blue foreground)\n") + + (if xterm-color-use-bold-for-bright + (insert " Expect: Bold instead of bright") + (insert " Expect: Bright rendered as bright color")) + (insert "\n\n") + + (cl-loop for (attrib . name) in test-attributes + do (test name "34" attrib) + finally (insert "\n")) + + (insert "* ANSI attributes (blue background)\n") + + (if xterm-color-use-bold-for-bright + (insert " Expect: Bold instead of bright") + (insert " Expect: Bright not to be rendered since no foreground color is set")) + (insert "\n\n") + + (cl-loop for (attrib . name) in test-attributes + do (test name "44" attrib) + finally (insert "\n")) + + (insert "* ANSI attributes (AIXTERM blue foreground)\n") + + (if xterm-color-use-bold-for-bright + (insert " Expect: Bold instead of bright") + (insert " Expect: Bright color everywhere due to AIXTERM")) + (insert "\n\n") + + (cl-loop for (attrib . name) in test-attributes + do (test name "94" attrib) + finally (insert "\n")) + + (insert "* ANSI attributes (AIXTERM red background)\n") + (insert " Expect: Bright background color due to AIXTERM\n") + (if xterm-color-use-bold-for-bright + (insert " Expect: Bold instead of bright for foreground\n\n") + (insert "\n")) + + (cl-loop for (attrib . name) in test-attributes + do (test name "101" attrib) + finally (insert "\n")) + + (insert "* Misc\n") + (if xterm-color-use-bold-for-bright + (progn + (insert " Expect: Bold instead of bright\n") + (insert " Otherwise bright rendered as normal intensity\n\n")) + (insert "\n")) + + (insert "; Resetting FG color should not affect other SGR bits\n") + (ansi-filter "Default \x1b[34;1mBright blue\x1b[39m Reset-fg-color \x1b[34mBlue (bright)\x1b[0m\n\n") + (insert "; AIXTERM bright color should not set bright SGR bit\n") + (ansi-filter "Default \x1b[94mBright blue\x1b[34m Switch-to-blue (normal)\x1b[0m\n") + (insert "\n")))) + +(defun xterm-color--test-xterm () + (xterm-color--with-tests + ;; System colors + (cl-loop for color from 40 to 47 + do (ansi-filter "\x1b[0;%sm " color) + finally (ansi-filter "\x1b[0m * ANSI system colors\n")) + + ;; Normal ANSI colors mapped to XTERM + (cl-loop for color from 0 to 7 + do (ansi-filter "\x1b[48;5;%sm " color) + finally (ansi-filter "\x1b[0m * ANSI colors mapped to XTERM\n")) + + ;; Bright ANSI colors mapped to XTERM + (cl-loop for color from 8 to 15 + do (ansi-filter "\x1b[48;5;%sm " color) + finally (ansi-filter "\x1b[0m * ANSI bright colors mapped to XTERM\n\n")) + + ;; XTERM 256 color cubes + (insert "* XTERM 256 color cubes\n\n") + + (cl-loop for green from 0 to 5 do + (cl-loop for red from 0 to 5 do + (cl-loop for blue from 0 to 5 + for color = (+ 16 (* 36 red) (* green 6) blue) + do (ansi-filter "\x1b[48;5;%sm \x1b[0m" color)) + (ansi-filter "\x1b[0m ")) + (insert "\n")) + + ;; Truecolor color ramps + (insert "\n") + (insert "* Truecolor\n\n") + (cond (xterm-color--support-truecolor + ;; Adapted from: https://gist.github.com/XVilka/8346728 + (cl-loop + with steps = 77 + for c from 0 below steps + for r = (- 255 (* c (/ 255 steps))) + for g = (* c (/ 510 steps)) + for b = (* c (/ 255 steps)) do + (when (> g 255) (setq g (- 510 g))) + (ansi-filter "\x1b[48;2;%s;%s;%sm \x1b[m" r g b))) + (t + (insert "Truecolor is not supported on Emacs 32bit"))) + + (insert "\n\n") + (insert "* XTERM color grayscale ramp\n\n") + + (cl-loop for color from 232 to 255 + do (ansi-filter "\x1b[48;5;%sm " color) + finally (ansi-filter "\x1b[0m\n\n")))) + +;;;###autoload +(defun xterm-color-test () + "Create, display and render a new buffer containing ANSI control sequences." + (interactive) + (let* ((name (generate-new-buffer-name "*xterm-color-test*")) + (buf (get-buffer-create name))) + (switch-to-buffer buf)) + + (xterm-color--test-xterm) + + (let ((xterm-color-use-bold-for-bright nil)) + (xterm-color--test-ansi)) + (xterm-color-clear-cache) + + (insert "; Temporarily setting `xterm-color-use-bold-for-bright' to T\n") + (insert "; Current font needs to have a bold variant for following tests\n\n") + + (let ((xterm-color-use-bold-for-bright t)) + (xterm-color--test-ansi)) + + (setq buffer-read-only t) + (goto-char (point-min))) + +;;;###autoload +(defun xterm-color-test-raw () + "Create and display a new buffer containing ANSI SGR control sequences. +ANSI sequences are not processed. One can use a different Emacs package, +such as ansi-color.el to do so. This is really meant to be used for easy +comparisons/benchmarks with libraries that offer similar functionality." + (interactive) + (let* ((name (generate-new-buffer-name "*xterm-color-test-raw*")) + (buf (get-buffer-create name))) + (switch-to-buffer buf)) + + (let (xterm-color--test-do-filter) + (xterm-color--test-xterm) + (xterm-color--test-ansi)) + (goto-char (point-min))) + +(provide 'xterm-color) +;;; xterm-color.el ends here |