config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

lsp-clojure.el (23638B)


      1 ;;; lsp-clojure.el --- Clojure Client settings -*- lexical-binding: t; -*-
      2 
      3 ;; Copyright (C) 2019  Benedek Fazekas
      4 
      5 ;; Author: Benedek Fazekas <benedek.fazekas@gmail.com>
      6 ;; Keywords: languages,tools
      7 
      8 ;; This program is free software; you can redistribute it and/or modify
      9 ;; it under the terms of the GNU General Public License as published by
     10 ;; the Free Software Foundation, either version 3 of the License, or
     11 ;; (at your option) any later version.
     12 
     13 ;; This program is distributed in the hope that it will be useful,
     14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16 ;; GNU General Public License for more details.
     17 
     18 ;; You should have received a copy of the GNU General Public License
     19 ;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
     20 
     21 ;;; Commentary:
     22 
     23 ;; lsp-clojure client
     24 
     25 ;;; Code:
     26 
     27 (require 'lsp-mode)
     28 (require 'lsp-protocol)
     29 (require 'cl-lib)
     30 (require 'lsp-semantic-tokens)
     31 
     32 (defgroup lsp-clojure nil
     33   "LSP support for Clojure."
     34   :link '(url-link "https://github.com/snoe/clojure-lsp")
     35   :group 'lsp-mode
     36   :tag "Lsp Clojure")
     37 
     38 (define-obsolete-variable-alias 'lsp-clojure-server-command
     39   'lsp-clojure-custom-server-command  "lsp-mode 8.0.0")
     40 
     41 (defcustom lsp-clojure-custom-server-command nil
     42   "The clojure-lisp server command."
     43   :group 'lsp-clojure
     44   :risky t
     45   :type '(repeat string))
     46 
     47 (defcustom lsp-clojure-server-download-url
     48   (format "https://github.com/clojure-lsp/clojure-lsp/releases/latest/download/clojure-lsp-native-%s.zip"
     49           (let ((arch (car (split-string system-configuration "-"))))
     50             (pcase system-type
     51               ('gnu/linux (concat "linux-"
     52                                   (cond
     53                                    ((string= "x86_64" arch) "amd64")
     54                                    (t arch))))
     55               ('darwin (concat "macos-"
     56                                (cond
     57                                 ((string= "x86_64" arch) "amd64")
     58                                 (t arch))))
     59               ('windows-nt "windows-amd64"))))
     60   "Automatic download url for lsp-clojure."
     61   :type 'string
     62   :group 'lsp-clojure
     63   :package-version '(lsp-mode . "8.0.0"))
     64 
     65 (defcustom lsp-clojure-server-store-path
     66   (f-join lsp-server-install-dir
     67           "clojure"
     68           (if (eq system-type 'windows-nt)
     69               "clojure-lsp.exe"
     70             "clojure-lsp"))
     71   "The path to the file in which `clojure-lsp' will be stored."
     72   :type 'file
     73   :group 'lsp-clojure
     74   :package-version '(lsp-mode . "8.0.0"))
     75 
     76 (defcustom lsp-clojure-trace-enable nil
     77   "Enable trace logs between client and clojure-lsp server."
     78   :group 'lsp-clojure
     79   :type 'boolean)
     80 
     81 (defcustom lsp-clojure-workspace-dir (expand-file-name (locate-user-emacs-file "workspace/"))
     82   "LSP clojure workspace directory."
     83   :group 'lsp-clojure
     84   :risky t
     85   :type 'directory)
     86 
     87 (defcustom lsp-clojure-workspace-cache-dir (expand-file-name ".cache/" lsp-clojure-workspace-dir)
     88   "LSP clojure workspace cache directory."
     89   :group 'lsp-clojure
     90   :risky t
     91   :type 'directory)
     92 
     93 (defcustom lsp-clojure-library-dirs (list lsp-clojure-workspace-cache-dir
     94                                           (expand-file-name "~/.gitlibs/libs"))
     95   "LSP clojure dirs that should be considered library folders."
     96   :group 'lsp-clojure
     97   :type 'list)
     98 
     99 (defcustom lsp-clojure-test-tree-position-params nil
    100   "The optional test tree position params.
    101 Defaults to side following treemacs default."
    102   :type 'alist
    103   :group 'lsp-clojure)
    104 
    105 (defcustom lsp-clojure-project-tree-position-params nil
    106   "The optional project tree position params.
    107 Defaults to side following treemacs default."
    108   :type 'alist
    109   :group 'lsp-clojure)
    110 
    111 ;; Internal
    112 
    113 (lsp-interface
    114  (Clojure:CursorInfoParams (:textDocument :position) nil))
    115 
    116 (lsp-dependency
    117  'clojure-lsp
    118  `(:download :url lsp-clojure-server-download-url
    119    :decompress :zip
    120    :store-path lsp-clojure-server-store-path
    121    :set-executable? t)
    122  '(:system "clojure-lsp"))
    123 
    124 ;; Refactorings
    125 
    126 (defun lsp-clojure--execute-command (command &optional args)
    127   "Send an executeCommand request for COMMAND with ARGS."
    128   (lsp--cur-workspace-check)
    129   (lsp-send-execute-command command (apply #'vector args)))
    130 
    131 (defun lsp-clojure--refactoring-call (refactor-name &rest additional-args)
    132   "Send an executeCommand request for REFACTOR-NAME with ADDITIONAL-ARGS.
    133 If there are more arguments expected after the line and column numbers."
    134   (lsp--cur-workspace-check)
    135   (lsp-clojure--execute-command refactor-name (cl-list* (lsp--buffer-uri)
    136                                                         (- (line-number-at-pos) 1) ;; clojure-lsp expects line numbers to start at 0
    137                                                         (current-column)
    138                                                         additional-args)))
    139 
    140 (defun lsp-clojure-add-import-to-namespace (import-name)
    141   "Add to IMPORT-NAME to :import form."
    142   (interactive "MImport name: ")
    143   (lsp-clojure--refactoring-call "add-import-to-namespace" import-name))
    144 
    145 (defun lsp-clojure-add-missing-libspec ()
    146   "Apply add-missing-libspec refactoring at point."
    147   (interactive)
    148   (lsp-clojure--refactoring-call "add-missing-libspec"))
    149 
    150 (defun lsp-clojure-clean-ns ()
    151   "Apply clean-ns refactoring at point."
    152   (interactive)
    153   (lsp-clojure--refactoring-call "clean-ns"))
    154 
    155 (defun lsp-clojure-cycle-coll ()
    156   "Apply cycle-coll refactoring at point."
    157   (interactive)
    158   (lsp-clojure--refactoring-call "cycle-coll"))
    159 
    160 (defun lsp-clojure-cycle-privacy ()
    161   "Apply cycle-privacy refactoring at point."
    162   (interactive)
    163   (lsp-clojure--refactoring-call "cycle-privacy"))
    164 
    165 (defun lsp-clojure-expand-let ()
    166   "Apply expand-let refactoring at point."
    167   (interactive)
    168   (lsp-clojure--refactoring-call "expand-let"))
    169 
    170 (defun lsp-clojure-extract-function (function-name)
    171   "Move form at point into a new function named FUNCTION-NAME."
    172   (interactive "MFunction name: ") ;; Name of the function
    173   (lsp-clojure--refactoring-call "extract-function" function-name))
    174 
    175 (defun lsp-clojure-inline-symbol ()
    176   "Apply inline-symbol refactoring at point."
    177   (interactive)
    178   (lsp-clojure--refactoring-call "inline-symbol"))
    179 
    180 (defun lsp-clojure-introduce-let (binding-name)
    181   "Move form at point into a new let binding as BINDING-NAME."
    182   (interactive "MBinding name: ") ;; Name of the let binding
    183   (lsp-clojure--refactoring-call "introduce-let" binding-name))
    184 
    185 (defun lsp-clojure-move-to-let (binding-name)
    186   "Move form at point into nearest existing let binding as BINDING-NAME."
    187   (interactive "MBinding name: ") ;; Name of the let binding
    188   (lsp-clojure--refactoring-call "move-to-let" binding-name))
    189 
    190 (defun lsp-clojure-thread-first ()
    191   "Apply thread-first refactoring at point."
    192   (interactive)
    193   (lsp-clojure--refactoring-call "thread-first"))
    194 
    195 (defun lsp-clojure-thread-first-all ()
    196   "Apply thread-first-all refactoring at point."
    197   (interactive)
    198   (lsp-clojure--refactoring-call "thread-first-all"))
    199 
    200 (defun lsp-clojure-thread-last ()
    201   "Apply thread-last refactoring at point."
    202   (interactive)
    203   (lsp-clojure--refactoring-call "thread-last"))
    204 
    205 (defun lsp-clojure-thread-last-all ()
    206   "Apply thread-last-all refactoring at point."
    207   (interactive)
    208   (lsp-clojure--refactoring-call "thread-last-all"))
    209 
    210 (defun lsp-clojure-unwind-all ()
    211   "Apply unwind-all refactoring at point."
    212   (interactive)
    213   (lsp-clojure--refactoring-call "unwind-all"))
    214 
    215 (defun lsp-clojure-unwind-thread ()
    216   "Apply unwind-thread refactoring at point."
    217   (interactive)
    218   (lsp-clojure--refactoring-call "unwind-thread"))
    219 
    220 (defun lsp-clojure-create-function ()
    221   "Apply create-function refactoring at point."
    222   (interactive)
    223   (lsp-clojure--refactoring-call "create-function"))
    224 
    225 (defun lsp-clojure-create-test ()
    226   "Apply create-test refactoring at point."
    227   (interactive)
    228   (lsp-clojure--refactoring-call "create-test"))
    229 
    230 (defun lsp-clojure-sort-map ()
    231   "Apply sort-map refactoring at point."
    232   (interactive)
    233   (lsp-clojure--refactoring-call "sort-map"))
    234 
    235 (defun lsp-clojure-move-coll-entry-up ()
    236   "Apply move coll entry up refactoring at point."
    237   (interactive)
    238   (lsp-clojure--refactoring-call "move-coll-entry-up"))
    239 
    240 (defun lsp-clojure-move-coll-entry-down ()
    241   "Apply move coll entry down refactoring at point."
    242   (interactive)
    243   (lsp-clojure--refactoring-call "move-coll-entry-down"))
    244 
    245 (defun lsp-clojure-forward-slurp ()
    246   "Apply forward slurp refactoring at point."
    247   (interactive)
    248   (lsp-clojure--refactoring-call "forward-slurp"))
    249 
    250 (defun lsp-clojure-forward-barf ()
    251   "Apply forward barf refactoring at point."
    252   (interactive)
    253   (lsp-clojure--refactoring-call "forward-barf"))
    254 
    255 (defun lsp-clojure-backward-slurp ()
    256   "Apply backward slurp refactoring at point."
    257   (interactive)
    258   (lsp-clojure--refactoring-call "backward-slurp"))
    259 
    260 (defun lsp-clojure-backward-barf ()
    261   "Apply backward slurp refactoring at point."
    262   (interactive)
    263   (lsp-clojure--refactoring-call "backward-barf"))
    264 
    265 (defun lsp-clojure-move-form (dest-filename)
    266   "Apply move-form refactoring at point to DEST-FILENAME."
    267   (interactive
    268    (list (or (read-file-name "Move form to: ")
    269              (user-error "No filename selected. Aborting"))))
    270   (lsp-clojure--refactoring-call "move-form" (expand-file-name dest-filename)))
    271 
    272 (defun lsp-clojure-server-info ()
    273   "Request server info."
    274   (interactive)
    275   (lsp--cur-workspace-check)
    276   (lsp-notify "clojure/serverInfo/log" nil))
    277 
    278 (defvar lsp-clojure-server-buffer-name "*lsp-clojure-server-log*")
    279 
    280 (defun lsp-clojure--server-log-revert-function (original-file-log-buffer &rest _)
    281   "Spit contents to ORIGINAL-FILE-LOG-BUFFER."
    282   (with-current-buffer (get-buffer-create lsp-clojure-server-buffer-name)
    283     (erase-buffer)
    284     (insert (with-current-buffer original-file-log-buffer (buffer-string)))
    285     (goto-char (point-max))
    286     (read-only-mode)))
    287 
    288 (defun lsp-clojure-server-log ()
    289   "Open a buffer with the server logs."
    290   (interactive)
    291   (lsp--cur-workspace-check)
    292   (let* ((log-path (-> (lsp--json-serialize (lsp-request "clojure/serverInfo/raw" nil))
    293                        (lsp--read-json)
    294                        (lsp-get :log-path))))
    295     (with-current-buffer (find-file log-path)
    296       (read-only-mode)
    297       (goto-char (point-max)))))
    298 
    299 (defun lsp-clojure-server-info-raw ()
    300   "Request server info raw data."
    301   (interactive)
    302   (lsp--cur-workspace-check)
    303   (message "%s" (lsp--json-serialize (lsp-request "clojure/serverInfo/raw" nil))))
    304 
    305 (defun lsp-clojure-cursor-info ()
    306   "Request cursor info at point."
    307   (interactive)
    308   (lsp--cur-workspace-check)
    309   (lsp-notify "clojure/cursorInfo/log"
    310               (lsp-make-clojure-cursor-info-params
    311                :textDocument (lsp-make-text-document-identifier :uri (lsp--buffer-uri))
    312                :position (lsp-make-position :line (- (line-number-at-pos) 1)
    313                                             :character (current-column)))))
    314 
    315 (defun lsp-clojure-resolve-macro-as ()
    316   "Ask to user how the unresolved macro should be resolved."
    317   (interactive)
    318   (lsp--cur-workspace-check)
    319   (lsp-clojure--execute-command "resolve-macro-as"
    320                                 (list (lsp--buffer-uri)
    321                                       (- (line-number-at-pos) 1) ;; clojure-lsp expects line numbers to start at 0
    322                                       (current-column))))
    323 
    324 (defun lsp-clojure--ensure-dir (path)
    325   "Ensure that directory PATH exists."
    326   (unless (file-directory-p path)
    327     (make-directory path t)))
    328 
    329 (defun lsp-clojure--get-metadata-location (file-location)
    330   "Given a FILE-LOCATION return the file containing the metadata for the file."
    331   (format "%s.%s.metadata"
    332           (file-name-directory file-location)
    333           (file-name-base file-location)))
    334 
    335 (defun lsp-clojure--file-in-jar (uri)
    336   "Check URI for a valid jar and include it in workspace."
    337   (string-match "^\\(jar\\|zip\\):\\(file:.+\\)!/\\(.+\\)" uri)
    338   (let* ((ns-path (match-string 3 uri))
    339          (ns (s-replace "/" "." ns-path))
    340          (file-location (concat lsp-clojure-workspace-cache-dir ns)))
    341     (unless (file-readable-p file-location)
    342       (lsp-clojure--ensure-dir (file-name-directory file-location))
    343       (with-lsp-workspace (lsp-find-workspace 'clojure-lsp nil)
    344         (let ((content (lsp-send-request (lsp-make-request "clojure/dependencyContents" (list :uri uri)))))
    345           (with-temp-file file-location
    346             (insert content))
    347           (with-temp-file (lsp-clojure--get-metadata-location file-location)
    348             (insert uri)))))
    349     file-location))
    350 
    351 (defun lsp-clojure--server-executable-path ()
    352   "Return the clojure-lsp server command."
    353   (or (executable-find "clojure-lsp")
    354       (lsp-package-path 'clojure-lsp)))
    355 
    356 (lsp-defun lsp-clojure--show-references ((&Command :arguments? args))
    357   "Show references for command with ARGS.
    358 ARGS is a vector which the first element is the uri, the second the line
    359 and the third the column."
    360   (lsp-show-xrefs
    361    (lsp--locations-to-xref-items
    362     (lsp-request "textDocument/references"
    363                  (lsp--make-reference-params
    364                   (lsp--text-document-position-params
    365                    (list :uri (seq-elt args 0))
    366                    (list :line (1- (seq-elt args 1))
    367                          :character (1- (seq-elt args 2)))))))
    368    nil
    369    t))
    370 
    371 ;; Test tree
    372 
    373 (defvar-local lsp-clojure--test-tree-data nil)
    374 (defconst lsp-clojure--test-tree-buffer-name "*Clojure Test Tree*")
    375 
    376 (defvar treemacs-position)
    377 (defvar treemacs-width)
    378 (declare-function lsp-treemacs-render "ext:lsp-treemacs" (tree title expand-depth &optional buffer-name right-click-actions clear-cache?))
    379 (declare-function lsp-treemacs--open-file-in-mru "ext:lsp-treemacs" (file))
    380 
    381 (defun lsp-clojure--test-tree-ret-action (uri range)
    382   "Build the ret action for an item in the test tree view.
    383 URI is the source of the item.
    384 RANGE is the range of positions to where this item should point."
    385   (interactive)
    386   (lsp-treemacs--open-file-in-mru (lsp--uri-to-path uri))
    387   (goto-char (lsp--position-to-point (lsp:range-start range)))
    388   (run-hooks 'xref-after-jump-hook))
    389 
    390 (lsp-defun lsp-clojure--test-tree-data->tree (uri (&clojure-lsp:TestTreeNode :name :range :kind :children?))
    391   "Builds a test tree.
    392 URI is the source of the test tree.
    393 NODE is the node with all test children data."
    394   (-let* ((icon (cl-case kind
    395                   (1 'namespace)
    396                   (2 'method)
    397                   (3 'field)))
    398           (base-tree (list :key name
    399                            :label name
    400                            :icon icon
    401                            :ret-action (lambda (&rest _) (lsp-clojure--test-tree-ret-action uri range))
    402                            :uri uri)))
    403     (if (seq-empty-p children?)
    404         base-tree
    405       (plist-put base-tree :children (seq-map (-partial #'lsp-clojure--test-tree-data->tree uri) children?)))))
    406 
    407 (lsp-defun lsp-clojure--render-test-tree ((&clojure-lsp:TestTreeParams :uri :tree))
    408   "Render a test tree view for current test tree buffer data."
    409   (save-excursion
    410     (lsp-treemacs-render
    411      (list (lsp-clojure--test-tree-data->tree uri tree))
    412      "Clojure Test Tree"
    413      t
    414      lsp-clojure--test-tree-buffer-name)))
    415 
    416 (defun lsp-clojure--show-test-tree (ignore-focus?)
    417   "Show a test tree for current buffer.
    418 Focus on it if IGNORE-FOCUS? is nil."
    419   (if lsp-clojure--test-tree-data
    420       (-let* ((tree-buffer (lsp-clojure--render-test-tree lsp-clojure--test-tree-data))
    421               (position-params (or lsp-clojure-test-tree-position-params
    422                                    `((side . ,treemacs-position)
    423                                      (slot . 2)
    424                                      (window-width . ,treemacs-width))))
    425               (window (display-buffer-in-side-window tree-buffer position-params)))
    426         (unless ignore-focus?
    427           (select-window window)
    428           (set-window-dedicated-p window t)))
    429     (unless ignore-focus?
    430       (lsp-log "No Clojure test tree data found."))))
    431 
    432 (lsp-defun lsp-clojure--handle-test-tree (_workspace (notification &as &clojure-lsp:TestTreeParams :uri))
    433   "Test tree notification handler for workspace WORKSPACE.
    434 NOTIFICATION is the test tree notification data received from server.
    435 It updates the test tree view data."
    436   (when (require 'lsp-treemacs nil t)
    437     (when-let (buffer (find-buffer-visiting (lsp--uri-to-path uri)))
    438       (with-current-buffer buffer
    439         (setq lsp-clojure--test-tree-data notification)
    440         (when (get-buffer-window lsp-clojure--test-tree-buffer-name)
    441           (lsp-clojure--show-test-tree t))))))
    442 
    443 ;;;###autoload
    444 (defun lsp-clojure-show-test-tree (ignore-focus?)
    445   "Show a test tree and focus on it if IGNORE-FOCUS? is nil."
    446   (interactive "P")
    447   (if (require 'lsp-treemacs nil t)
    448       (lsp-clojure--show-test-tree ignore-focus?)
    449     (error "The package lsp-treemacs is not installed")))
    450 
    451 ;; Project Tree
    452 
    453 (defconst lsp-clojure--project-tree-buffer-name "*Clojure Project Tree*")
    454 
    455 (defun lsp-clojure--project-tree-type->icon (type)
    456   "Convert the project tree type TYPE to icon."
    457   (cl-case type
    458     (1 'project)
    459     (2 'folder)
    460     (3 'library)
    461     (4 'jar)
    462     (5 'namespace)
    463     (6 'class)
    464     (7 'method)
    465     (8 'variable)
    466     (9 'interface)))
    467 
    468 (defun lsp-clojure--project-tree-ret-action (uri range)
    469   "Build the ret action for an item in the project tree view.
    470 URI is the source of the item."
    471   (interactive)
    472   (lsp-treemacs--open-file-in-mru (lsp--uri-to-path uri))
    473   (goto-char (lsp--position-to-point (lsp:range-start range)))
    474   (run-hooks 'xref-after-jump-hook))
    475 
    476 (lsp-defun lsp-clojure--project-tree-children-data->tree (buffer current-node &optional _ callback)
    477   "Builds a project tree considering CURRENT-NODE."
    478   (with-current-buffer buffer
    479     (lsp-request-async
    480      "clojure/workspace/projectTree/nodes"
    481      current-node
    482      (-lambda ((&clojure-lsp:ProjectTreeNode :nodes?))
    483        (funcall
    484         callback
    485         (-map
    486          (-lambda ((node &as &clojure-lsp:ProjectTreeNode :id? :name :type :uri? :range? :detail? :final?))
    487            (-let ((label (if detail?
    488                              (format "%s %s" name (propertize detail? 'face 'lsp-details-face))
    489                            name)))
    490              `(:label ,label
    491                :key ,(or id? name)
    492                :icon ,(lsp-clojure--project-tree-type->icon type)
    493                ,@(unless final?
    494                    (list :children-async  (-partial #'lsp-clojure--project-tree-children-data->tree buffer node)))
    495                ,@(when uri?
    496                    (list :uri uri?
    497                          :ret-action (lambda (&rest _)
    498                                        (interactive)
    499                                        (lsp-clojure--project-tree-ret-action uri? range?)))))))
    500          nodes?)))
    501      :mode 'detached)))
    502 
    503 (defun lsp-clojure--project-tree-data->tree ()
    504   "Builds a project tree considering CURRENT-NODE."
    505   (-let* (((&clojure-lsp:ProjectTreeNode :id? :name :nodes? :uri?) (lsp-request "clojure/workspace/projectTree/nodes" nil))
    506           (buffer (current-buffer)))
    507     (list :key (or id? name)
    508           :label name
    509           :icon "clj"
    510           :children (seq-map (-lambda ((node &as &clojure-lsp:ProjectTreeNode :id? :name :type :uri?))
    511                                (list :key (or id? name)
    512                                      :label name
    513                                      :icon (lsp-clojure--project-tree-type->icon type)
    514                                      :children-async (-partial #'lsp-clojure--project-tree-children-data->tree buffer node)
    515                                      :uri uri?))
    516                              nodes?)
    517           :uri uri?)))
    518 
    519 (defun lsp-clojure--render-project-tree ()
    520   "Render a project tree view."
    521   (save-excursion
    522     (lsp-treemacs-render
    523      (list (lsp-clojure--project-tree-data->tree))
    524      "Clojure Project Tree"
    525      nil
    526      lsp-clojure--project-tree-buffer-name
    527      nil
    528      t)))
    529 
    530 (defun lsp-clojure--show-project-tree (ignore-focus?)
    531   "Show a project tree for current project.
    532 Focus on it if IGNORE-FOCUS? is nil."
    533   (-let* ((tree-buffer (lsp-clojure--render-project-tree))
    534           (position-params (or lsp-clojure-project-tree-position-params
    535                                `((side . ,treemacs-position)
    536                                  (slot . 2)
    537                                  (window-width . ,treemacs-width))))
    538           (window (display-buffer-in-side-window tree-buffer position-params)))
    539     (unless ignore-focus?
    540       (select-window window)
    541       (set-window-dedicated-p window t))))
    542 
    543 ;;;###autoload
    544 (defun lsp-clojure-show-project-tree (ignore-focus?)
    545   "Show a project tree with source-paths and dependencies.
    546 Focus on it if IGNORE-FOCUS? is nil."
    547   (interactive "P")
    548   (if (require 'lsp-treemacs nil t)
    549       (lsp-clojure--show-project-tree ignore-focus?)
    550     (error "The package lsp-treemacs is not installed")))
    551 
    552 (defun lsp-clojure--build-command ()
    553   "Build clojure-lsp start command."
    554   (let* ((base-command (or lsp-clojure-custom-server-command
    555                            (-some-> (lsp-clojure--server-executable-path) list))))
    556     (if lsp-clojure-trace-enable
    557         (-map-last #'stringp
    558                    (lambda (command)
    559                      (concat command " --trace"))
    560                    base-command)
    561       base-command)))
    562 
    563 (lsp-register-client
    564  (make-lsp-client
    565   :download-server-fn (lambda (_client callback error-callback _update?)
    566                         (lsp-package-ensure 'clojure-lsp callback error-callback))
    567   :semantic-tokens-faces-overrides '(:types (("macro" . font-lock-keyword-face)
    568                                              ("keyword" . clojure-keyword-face)
    569                                              ("event" . default)))
    570   :new-connection (lsp-stdio-connection
    571                    #'lsp-clojure--build-command
    572                    #'lsp-clojure--build-command)
    573   :major-modes '(clojure-mode clojurec-mode clojurescript-mode
    574                  clojure-ts-mode clojure-ts-clojurec-mode clojure-ts-clojurescript-mode)
    575   :library-folders-fn (lambda (_workspace) lsp-clojure-library-dirs)
    576   :uri-handlers (lsp-ht ("jar" #'lsp-clojure--file-in-jar))
    577   :action-handlers (lsp-ht ("code-lens-references" #'lsp-clojure--show-references))
    578   :notification-handlers (lsp-ht ("clojure/textDocument/testTree" #'lsp-clojure--handle-test-tree))
    579   :initialization-options '(:dependency-scheme "jar"
    580                             :show-docs-arity-on-same-line? t)
    581   :custom-capabilities `((experimental . ((testTree . ,(and (require 'lsp-treemacs nil t) t)))))
    582   :server-id 'clojure-lsp))
    583 
    584 (lsp-consistency-check lsp-clojure)
    585 
    586 ;; For debugging
    587 
    588 (declare-function cider-connect-clj "ext:cider" (params))
    589 
    590 (defun lsp-clojure-nrepl-connect ()
    591   "Connect to the running nrepl debug server of clojure-lsp."
    592   (interactive)
    593   (let ((info (lsp-clojure-server-info-raw)))
    594     (save-match-data
    595       (when (functionp 'cider-connect-clj)
    596         (when-let (port (and (string-match "\"port\":\\([0-9]+\\)" info)
    597                              (match-string 1 info)))
    598           (cider-connect-clj `(:host "localhost"
    599                                :port ,port)))))))
    600 
    601 ;; Cider integration
    602 
    603 (defun lsp-clojure-semantic-tokens-refresh (&rest _)
    604   "Force refresh semantic tokens."
    605   (when-let ((workspace (and lsp-semantic-tokens-enable
    606                              (lsp-find-workspace 'clojure-lsp (buffer-file-name)))))
    607     (--each (lsp--workspace-buffers workspace)
    608       (when (lsp-buffer-live-p it)
    609         (lsp-with-current-buffer it
    610           (lsp-semantic-tokens--enable))))))
    611 
    612 (with-eval-after-load 'cider
    613   (when lsp-semantic-tokens-enable
    614     ;; refresh tokens as cider flush font-faces after disconnected
    615     (add-hook 'cider-mode-hook #'lsp-clojure-semantic-tokens-refresh)))
    616 
    617 (provide 'lsp-clojure)
    618 ;;; lsp-clojure.el ends here