lsp-clojure.el (23655B)
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 string)) 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