config

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

lsp-mode.el (430695B)


      1 ;;; lsp-mode.el --- LSP mode                              -*- lexical-binding: t; -*-
      2 
      3 ;; Copyright (C) 2020-2024 emacs-lsp maintainers
      4 
      5 ;; Author: Vibhav Pant, Fangrui Song, Ivan Yonchovski
      6 ;; Keywords: languages
      7 ;; Package-Requires: ((emacs "27.1") (dash "2.18.0") (f "0.20.0") (ht "2.3") (spinner "1.7.3") (markdown-mode "2.3") (lv "0") (eldoc "1.11"))
      8 ;; Version: 9.0.1
      9 
     10 ;; URL: https://github.com/emacs-lsp/lsp-mode
     11 ;; This program is free software; you can redistribute it and/or modify
     12 ;; it under the terms of the GNU General Public License as published by
     13 ;; the Free Software Foundation, either version 3 of the License, or
     14 ;; (at your option) any later version.
     15 
     16 ;; This program is distributed in the hope that it will be useful,
     17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     19 ;; GNU General Public License for more details.
     20 
     21 ;; You should have received a copy of the GNU General Public License
     22 ;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
     23 
     24 ;;; Commentary:
     25 
     26 ;; Emacs client/library for the Language Server Protocol
     27 
     28 ;;; Code:
     29 
     30 (require 'cl-generic)
     31 (require 'cl-lib)
     32 (require 'compile)
     33 (require 'dash)
     34 (require 'epg)
     35 (require 'ewoc)
     36 (require 'f)
     37 (require 'filenotify)
     38 (require 'files)
     39 (require 'ht)
     40 (require 'imenu)
     41 (require 'inline)
     42 (require 'json)
     43 (require 'lv)
     44 (require 'markdown-mode)
     45 (require 'network-stream)
     46 (require 'pcase)
     47 (require 'rx)
     48 (require 's)
     49 (require 'seq)
     50 (require 'spinner)
     51 (require 'subr-x)
     52 (require 'tree-widget)
     53 (require 'url-parse)
     54 (require 'url-util)
     55 (require 'widget)
     56 (require 'xref)
     57 (require 'minibuffer)
     58 (require 'help-mode)
     59 (require 'lsp-protocol)
     60 
     61 (defgroup lsp-mode nil
     62   "Language Server Protocol client."
     63   :group 'tools
     64   :tag "Language Server (lsp-mode)")
     65 
     66 (declare-function evil-set-command-property "ext:evil-common")
     67 (declare-function projectile-project-root "ext:projectile")
     68 (declare-function yas-expand-snippet "ext:yasnippet")
     69 (declare-function dap-mode "ext:dap-mode")
     70 (declare-function dap-auto-configure-mode "ext:dap-mode")
     71 
     72 (defvar yas-inhibit-overlay-modification-protection)
     73 (defvar yas-indent-line)
     74 (defvar yas-wrap-around-region)
     75 (defvar yas-also-auto-indent-first-line)
     76 (defvar dap-auto-configure-mode)
     77 (defvar dap-ui-menu-items)
     78 (defvar company-minimum-prefix-length)
     79 
     80 (defconst lsp--message-type-face
     81   `((1 . ,compilation-error-face)
     82     (2 . ,compilation-warning-face)
     83     (3 . ,compilation-message-face)
     84     (4 . ,compilation-info-face)))
     85 
     86 (defconst lsp--errors
     87   '((-32700 "Parse Error")
     88     (-32600 "Invalid Request")
     89     (-32601 "Method not Found")
     90     (-32602 "Invalid Parameters")
     91     (-32603 "Internal Error")
     92     (-32099 "Server Start Error")
     93     (-32000 "Server End Error")
     94     (-32002 "Server Not Initialized")
     95     (-32001 "Unknown Error Code")
     96     (-32800 "Request Cancelled"))
     97   "Alist of error codes to user friendly strings.")
     98 
     99 (defconst lsp--empty-ht (make-hash-table))
    100 
    101 (eval-and-compile
    102   (defun dash-expand:&lsp-wks (key source)
    103     `(,(intern-soft (format "lsp--workspace-%s" (eval key))) ,source))
    104 
    105   (defun dash-expand:&lsp-cln (key source)
    106     `(,(intern-soft (format "lsp--client-%s" (eval key))) ,source)))
    107 
    108 (define-obsolete-variable-alias 'lsp-print-io 'lsp-log-io "lsp-mode 6.1")
    109 
    110 (defcustom lsp-log-io nil
    111   "If non-nil, log all messages from the language server to a *lsp-log* buffer."
    112   :group 'lsp-mode
    113   :type 'boolean)
    114 
    115 (defcustom lsp-log-io-allowlist-methods '()
    116   "The methods to filter before print to lsp-log-io."
    117   :group 'lsp-mode
    118   :type '(repeat string)
    119   :package-version '(lsp-mode . "9.0.0"))
    120 
    121 (defcustom lsp-log-max message-log-max
    122   "Maximum number of lines to keep in the log buffer.
    123 If nil, disable message logging.  If t, log messages but don’t truncate
    124 the buffer when it becomes large."
    125   :group 'lsp-mode
    126   :type '(choice (const :tag "Disable" nil)
    127                  (integer :tag "lines")
    128                  (const :tag "Unlimited" t))
    129   :package-version '(lsp-mode . "6.1"))
    130 
    131 (defcustom lsp-io-messages-max t
    132   "Maximum number of messages that can be locked in a `lsp-io' buffer."
    133   :group 'lsp-mode
    134   :type '(choice (const :tag "Unlimited" t)
    135                  (integer :tag "Messages"))
    136   :package-version '(lsp-mode . "6.1"))
    137 
    138 (defcustom lsp-keep-workspace-alive t
    139   "If non nil keep workspace alive when the last workspace buffer is closed."
    140   :group 'lsp-mode
    141   :type 'boolean)
    142 
    143 (defcustom lsp-enable-snippet t
    144   "Enable/disable snippet completion support."
    145   :group 'lsp-completion
    146   :type 'boolean)
    147 
    148 (defcustom lsp-enable-folding t
    149   "Enable/disable code folding support."
    150   :group 'lsp-mode
    151   :type 'boolean
    152   :package-version '(lsp-mode . "6.1"))
    153 
    154 (define-obsolete-variable-alias 'lsp-enable-semantic-highlighting 'lsp-semantic-tokens-enable "lsp-mode 8.0.0")
    155 
    156 (defcustom lsp-semantic-tokens-enable nil
    157   "Enable/disable support for semantic tokens.
    158 As defined by the Language Server Protocol 3.16."
    159   :group 'lsp-semantic-tokens
    160   :type 'boolean)
    161 
    162 (defcustom lsp-folding-range-limit nil
    163   "The maximum number of folding ranges to receive from the language server."
    164   :group 'lsp-mode
    165   :type '(choice (const :tag "No limit." nil)
    166                  (integer :tag "Number of lines."))
    167   :package-version '(lsp-mode . "6.1"))
    168 
    169 (defcustom lsp-folding-line-folding-only nil
    170   "If non-nil, only fold complete lines."
    171   :group 'lsp-mode
    172   :type 'boolean
    173   :package-version '(lsp-mode . "6.1"))
    174 
    175 (defcustom lsp-client-packages
    176   '( ccls lsp-actionscript lsp-ada lsp-angular lsp-ansible lsp-asm lsp-astro
    177      lsp-autotools lsp-awk lsp-bash lsp-beancount lsp-bufls lsp-clangd
    178      lsp-clojure lsp-cmake lsp-cobol lsp-credo lsp-crystal lsp-csharp lsp-css
    179      lsp-cucumber lsp-cypher lsp-d lsp-dart lsp-dhall lsp-docker lsp-dockerfile
    180      lsp-earthly lsp-elixir lsp-elm lsp-emmet lsp-erlang lsp-eslint lsp-fortran lsp-fsharp
    181      lsp-gdscript lsp-gleam lsp-glsl lsp-go lsp-golangci-lint lsp-grammarly
    182      lsp-graphql lsp-groovy lsp-hack lsp-haskell lsp-haxe lsp-idris lsp-java
    183      lsp-javascript lsp-jq lsp-json lsp-kotlin lsp-latex lsp-lisp lsp-ltex
    184      lsp-lua lsp-magik lsp-markdown lsp-marksman lsp-mdx lsp-meson lsp-metals lsp-mint
    185      lsp-mojo lsp-move lsp-mssql lsp-nginx lsp-nim lsp-nix lsp-nushell lsp-ocaml
    186      lsp-openscad lsp-pascal lsp-perl lsp-perlnavigator lsp-php lsp-pls
    187      lsp-purescript lsp-pwsh lsp-pyls lsp-pylsp lsp-pyright lsp-python-ms
    188      lsp-qml lsp-r lsp-racket lsp-remark lsp-rf lsp-rubocop lsp-ruby-lsp
    189      lsp-ruby-syntax-tree lsp-ruff-lsp lsp-rust lsp-semgrep lsp-shader
    190      lsp-solargraph lsp-solidity lsp-sonarlint lsp-sorbet lsp-sourcekit
    191      lsp-sql lsp-sqls lsp-steep lsp-svelte lsp-tailwindcss lsp-terraform
    192      lsp-tex lsp-tilt lsp-toml lsp-trunk lsp-ttcn3 lsp-typeprof lsp-v
    193      lsp-vala lsp-verilog lsp-vetur lsp-vhdl lsp-vimscript lsp-volar lsp-wgsl
    194      lsp-xml lsp-yaml lsp-yang lsp-zig)
    195   "List of the clients to be automatically required."
    196   :group 'lsp-mode
    197   :type '(repeat symbol))
    198 
    199 (defcustom lsp-progress-via-spinner t
    200   "If non-nil, display LSP $/progress reports via a spinner in the modeline."
    201   :group 'lsp-mode
    202   :type 'boolean)
    203 
    204 (defcustom lsp-progress-spinner-type 'progress-bar
    205   "Holds the type of spinner to be used in the mode-line.
    206 Takes a value accepted by `spinner-start'."
    207   :group 'lsp-mode
    208   :type `(choice :tag "Choose a spinner by name"
    209                  ,@(mapcar (lambda (c) (list 'const (car c)))
    210                            spinner-types)))
    211 
    212 (defvar-local lsp-use-workspace-root-for-server-default-directory nil
    213   "Use `lsp-workspace-root' for `default-directory' when starting LSP process.")
    214 
    215 (defvar-local lsp--cur-workspace nil)
    216 
    217 (defvar-local lsp--cur-version 0)
    218 (defvar-local lsp--virtual-buffer-connections nil)
    219 (defvar-local lsp--virtual-buffer nil)
    220 (defvar lsp--virtual-buffer-mappings (ht))
    221 
    222 (defvar lsp--uri-file-prefix (pcase system-type
    223                                (`windows-nt "file:///")
    224                                (_ "file://"))
    225   "Prefix for a file-uri.")
    226 
    227 (defvar-local lsp-buffer-uri nil
    228   "If set, return it instead of calculating it using `buffer-file-name'.")
    229 
    230 (define-error 'lsp-error "Unknown lsp-mode error")
    231 (define-error 'lsp-empty-response-error
    232   "Empty response from the language server" 'lsp-error)
    233 (define-error 'lsp-timed-out-error
    234   "Timed out while waiting for a response from the language server" 'lsp-error)
    235 (define-error 'lsp-capability-not-supported
    236   "Capability not supported by the language server" 'lsp-error)
    237 (define-error 'lsp-file-scheme-not-supported
    238   "Unsupported file scheme" 'lsp-error)
    239 (define-error 'lsp-client-already-exists-error
    240   "A client with this server-id already exists" 'lsp-error)
    241 (define-error 'lsp-no-code-actions
    242   "No code actions" 'lsp-error)
    243 
    244 (defcustom lsp-auto-guess-root nil
    245   "Automatically guess the project root using projectile/project.
    246 Do *not* use this setting unless you are familiar with `lsp-mode'
    247 internals and you are sure that all of your projects are
    248 following `projectile'/`project.el' conventions."
    249   :group 'lsp-mode
    250   :type 'boolean)
    251 
    252 (defcustom lsp-guess-root-without-session nil
    253   "Ignore the session file when calculating the project root.
    254 You almost always want to set lsp-auto-guess-root too.
    255 Do *not* use this setting unless you are familiar with `lsp-mode'
    256 internals and you are sure that all of your projects are
    257 following `projectile'/`project.el' conventions."
    258   :group 'lsp-mode
    259   :type 'boolean)
    260 
    261 (defcustom lsp-restart 'interactive
    262   "Defines how server-exited events must be handled."
    263   :group 'lsp-mode
    264   :type '(choice (const interactive)
    265                  (const auto-restart)
    266                  (const ignore)))
    267 
    268 (defcustom lsp-session-file (expand-file-name (locate-user-emacs-file ".lsp-session-v1"))
    269   "File where session information is stored."
    270   :group 'lsp-mode
    271   :type 'file)
    272 
    273 (defcustom lsp-auto-configure t
    274   "Auto configure `lsp-mode' main features.
    275 When set to t `lsp-mode' will auto-configure completion,
    276 code-actions, breadcrumb, `flycheck', `flymake', `imenu', symbol highlighting,
    277 lenses, links, and so on.
    278 
    279 For finer granularity you may use `lsp-enable-*' properties."
    280   :group 'lsp-mode
    281   :type 'boolean
    282   :package-version '(lsp-mode . "6.1"))
    283 
    284 (defcustom lsp-disabled-clients nil
    285   "A list of disabled/blocklisted clients.
    286 Each entry in the list can be either:
    287 a symbol, the server-id for the LSP client, or
    288 a cons pair (MAJOR-MODE . CLIENTS), where MAJOR-MODE is the major-mode,
    289 and CLIENTS is either a client or a list of clients.
    290 
    291 This option can also be used as a file- or directory-local variable to
    292 disable a language server for individual files or directories/projects
    293 respectively."
    294   :group 'lsp-mode
    295   :type '(repeat (symbol))
    296   :safe 'listp
    297   :package-version '(lsp-mode . "6.1"))
    298 
    299 (defvar lsp-clients (make-hash-table :test 'eql)
    300   "Hash table server-id -> client.
    301 It contains all of the clients that are currently registered.")
    302 
    303 (defvar lsp-enabled-clients nil
    304   "List of clients allowed to be used for projects.
    305 When nil, all registered clients are considered candidates.")
    306 
    307 (defvar lsp-last-id 0
    308   "Last request id.")
    309 
    310 (defcustom lsp-before-initialize-hook nil
    311   "List of functions to be called before a Language Server has been initialized
    312 for a new workspace."
    313   :type 'hook
    314   :group 'lsp-mode)
    315 
    316 (defcustom lsp-after-initialize-hook nil
    317   "List of functions to be called after a Language Server has been initialized
    318 for a new workspace."
    319   :type 'hook
    320   :group 'lsp-mode)
    321 
    322 (defcustom lsp-before-open-hook nil
    323   "List of functions to be called before a new file with LSP support is opened."
    324   :type 'hook
    325   :group 'lsp-mode)
    326 
    327 (defcustom lsp-after-open-hook nil
    328   "List of functions to be called after a new file with LSP support is opened."
    329   :type 'hook
    330   :group 'lsp-mode)
    331 
    332 (defcustom lsp-enable-file-watchers t
    333   "If non-nil lsp-mode will watch the files in the workspace if
    334 the server has requested that."
    335   :type 'boolean
    336   :group 'lsp-mode
    337   :package-version '(lsp-mode . "6.1"))
    338 ;;;###autoload(put 'lsp-enable-file-watchers 'safe-local-variable #'booleanp)
    339 
    340 (define-obsolete-variable-alias 'lsp-file-watch-ignored 'lsp-file-watch-ignored-directories "8.0.0")
    341 
    342 (defcustom lsp-file-watch-ignored-directories
    343   '(; SCM tools
    344     "[/\\\\]\\.git\\'"
    345     "[/\\\\]\\.github\\'"
    346     "[/\\\\]\\.gitlab\\'"
    347     "[/\\\\]\\.circleci\\'"
    348     "[/\\\\]\\.hg\\'"
    349     "[/\\\\]\\.bzr\\'"
    350     "[/\\\\]_darcs\\'"
    351     "[/\\\\]\\.svn\\'"
    352     "[/\\\\]_FOSSIL_\\'"
    353     ;; IDE or build tools
    354     "[/\\\\]\\.idea\\'"
    355     "[/\\\\]\\.ensime_cache\\'"
    356     "[/\\\\]\\.eunit\\'"
    357     "[/\\\\]node_modules"
    358     "[/\\\\]\\.yarn\\'"
    359     "[/\\\\]\\.fslckout\\'"
    360     "[/\\\\]\\.tox\\'"
    361     "[/\\\\]\\.nox\\'"
    362     "[/\\\\]dist\\'"
    363     "[/\\\\]dist-newstyle\\'"
    364     "[/\\\\]\\.stack-work\\'"
    365     "[/\\\\]\\.bloop\\'"
    366     "[/\\\\]\\.metals\\'"
    367     "[/\\\\]target\\'"
    368     "[/\\\\]\\.ccls-cache\\'"
    369     "[/\\\\]\\.vs\\'"
    370     "[/\\\\]\\.vscode\\'"
    371     "[/\\\\]\\.venv\\'"
    372     "[/\\\\]\\.mypy_cache\\'"
    373     "[/\\\\]\\.pytest_cache\\'"
    374     ;; Swift Package Manager
    375     "[/\\\\]\\.build\\'"
    376     ;; Python
    377     "[/\\\\]__pycache__\\'"
    378     ;; Autotools output
    379     "[/\\\\]\\.deps\\'"
    380     "[/\\\\]build-aux\\'"
    381     "[/\\\\]autom4te.cache\\'"
    382     "[/\\\\]\\.reference\\'"
    383     ;; Bazel
    384     "[/\\\\]bazel-[^/\\\\]+\\'"
    385     ;; CSharp
    386     "[/\\\\]\\.cache[/\\\\]lsp-csharp\\'"
    387     "[/\\\\]\\.meta\\'"
    388     "[/\\\\]\\.nuget\\'"
    389     ;; Unity
    390     "[/\\\\]Library\\'"
    391     ;; Clojure
    392     "[/\\\\]\\.lsp\\'"
    393     "[/\\\\]\\.clj-kondo\\'"
    394     "[/\\\\]\\.shadow-cljs\\'"
    395     "[/\\\\]\\.babel_cache\\'"
    396     "[/\\\\]\\.cpcache\\'"
    397     "[/\\\\]\\checkouts\\'"
    398     ;; Gradle
    399     "[/\\\\]\\.gradle\\'"
    400     ;; Maven
    401     "[/\\\\]\\.m2\\'"
    402     ;; .Net Core build-output
    403     "[/\\\\]bin/Debug\\'"
    404     "[/\\\\]obj\\'"
    405     ;; OCaml and Dune
    406     "[/\\\\]_opam\\'"
    407     "[/\\\\]_build\\'"
    408     ;; Elixir
    409     "[/\\\\]\\.elixir_ls\\'"
    410     ;; Elixir Credo
    411     "[/\\\\]\\.elixir-tools\\'"
    412     ;; terraform and terragrunt
    413     "[/\\\\]\\.terraform\\'"
    414     "[/\\\\]\\.terragrunt-cache\\'"
    415     ;; nix-direnv
    416     "[/\\\\]\\result"
    417     "[/\\\\]\\result-bin"
    418     "[/\\\\]\\.direnv\\'")
    419   "List of regexps matching directory paths which won't be monitored when
    420 creating file watches. Customization of this variable is only honored at
    421 the global level or at a root of an lsp workspace."
    422   :group 'lsp-mode
    423   :type '(repeat string)
    424   :package-version '(lsp-mode . "8.0.0"))
    425 
    426 (define-obsolete-function-alias 'lsp-file-watch-ignored 'lsp-file-watch-ignored-directories "7.0.1")
    427 
    428 (defun lsp-file-watch-ignored-directories ()
    429   lsp-file-watch-ignored-directories)
    430 
    431 ;; Allow lsp-file-watch-ignored-directories as a file or directory-local variable
    432 ;;;###autoload(put 'lsp-file-watch-ignored-directories 'safe-local-variable 'lsp--string-listp)
    433 
    434 (defcustom lsp-file-watch-ignored-files
    435   '(
    436     ;; Flycheck tempfiles
    437     "[/\\\\]flycheck_[^/\\\\]+\\'"
    438     ;; lockfiles
    439     "[/\\\\]\\.#[^/\\\\]+\\'"
    440     ;; backup files
    441     "[/\\\\][^/\\\\]+~\\'" )
    442   "List of regexps matching files for which change events will
    443 not be sent to the server.
    444 
    445 This setting has no impact on whether a file-watch is created for
    446 a directory; it merely prevents notifications pertaining to
    447 matched files from being sent to the server.  To prevent a
    448 file-watch from being created for a directory, customize
    449 `lsp-file-watch-ignored-directories'
    450 
    451 Customization of this variable is only honored at the global
    452 level or at a root of an lsp workspace."
    453   :group 'lsp-mode
    454   :type '(repeat string)
    455   :package-version '(lsp-mode . "8.0.0"))
    456 
    457 ;; Allow lsp-file-watch-ignored-files as a file or directory-local variable
    458 ;;;###autoload(put 'lsp-file-watch-ignored-files 'safe-local-variable 'lsp--string-listp)
    459 
    460 (defcustom lsp-after-uninitialized-functions nil
    461   "List of functions to be called after a Language Server has been uninitialized."
    462   :type 'hook
    463   :group 'lsp-mode
    464   :package-version '(lsp-mode . "6.3"))
    465 
    466 (defconst lsp--sync-full 1)
    467 (defconst lsp--sync-incremental 2)
    468 
    469 (defcustom lsp-debounce-full-sync-notifications t
    470   "If non-nil debounce full sync events.
    471 This flag affects only servers which do not support incremental updates."
    472   :type 'boolean
    473   :group 'lsp-mode
    474   :package-version '(lsp-mode . "6.1"))
    475 
    476 (defcustom lsp-debounce-full-sync-notifications-interval 1.0
    477   "Time to wait before sending full sync synchronization after buffer modification."
    478   :type 'float
    479   :group 'lsp-mode
    480   :package-version '(lsp-mode . "6.1"))
    481 
    482 (defvar lsp--stderr-index 0)
    483 
    484 (defvar lsp--delayed-requests nil)
    485 (defvar lsp--delay-timer nil)
    486 
    487 (defcustom lsp-document-sync-method nil
    488   "How to sync the document with the language server."
    489   :type '(choice (const :tag "Documents are synced by always sending the full content of the document." lsp--sync-full)
    490                  (const :tag "Documents are synced by always sending incremental changes to the document." lsp--sync-incremental)
    491                  (const :tag "Use the method recommended by the language server." nil))
    492   :group 'lsp-mode)
    493 
    494 (defcustom lsp-auto-execute-action t
    495   "Auto-execute single action."
    496   :type 'boolean
    497   :group 'lsp-mode)
    498 
    499 (defcustom lsp-enable-links t
    500   "If non-nil, all references to links in a file will be made clickable, if
    501 supported by the language server."
    502   :type 'boolean
    503   :group 'lsp-mode
    504   :package-version '(lsp-mode . "6.1"))
    505 
    506 (defcustom lsp-enable-imenu t
    507   "If non-nil, automatically enable `imenu' integration when server provides
    508 `textDocument/documentSymbol'."
    509   :type 'boolean
    510   :group 'lsp-mode
    511   :package-version '(lsp-mode . "6.2"))
    512 
    513 (defcustom lsp-enable-dap-auto-configure t
    514   "If non-nil, enable `dap-auto-configure-mode`."
    515   :type 'boolean
    516   :group 'lsp-mode
    517   :package-version '(lsp-mode . "7.0"))
    518 
    519 (defcustom lsp-eldoc-enable-hover t
    520   "If non-nil, `eldoc' will display hover info when it is present."
    521   :type 'boolean
    522   :group 'lsp-mode)
    523 
    524 (defcustom lsp-eldoc-render-all nil
    525   "Display all of the info returned by document/onHover.
    526 If this is set to nil, `eldoc' will show only the symbol information."
    527   :type 'boolean
    528   :group 'lsp-mode)
    529 
    530 (define-obsolete-variable-alias 'lsp-enable-completion-at-point
    531   'lsp-completion-enable "lsp-mode 7.0.1")
    532 
    533 (defcustom lsp-completion-enable t
    534   "Enable `completion-at-point' integration."
    535   :type 'boolean
    536   :group 'lsp-completion)
    537 
    538 (defcustom lsp-enable-symbol-highlighting t
    539   "Highlight references of the symbol at point."
    540   :type 'boolean
    541   :group 'lsp-mode)
    542 
    543 (defcustom lsp-enable-xref t
    544   "Enable xref integration."
    545   :type 'boolean
    546   :group 'lsp-mode)
    547 
    548 (defcustom lsp-references-exclude-definition nil
    549   "If non-nil, exclude declarations when finding references."
    550   :type 'boolean
    551   :group 'lsp-mode)
    552 
    553 (defcustom lsp-enable-indentation t
    554   "Indent regions using the file formatting functionality provided by the
    555 language server."
    556   :type 'boolean
    557   :group 'lsp-mode)
    558 
    559 (defcustom lsp-enable-on-type-formatting t
    560   "Enable `textDocument/onTypeFormatting' integration."
    561   :type 'boolean
    562   :group 'lsp-mode)
    563 
    564 (defcustom lsp-enable-text-document-color t
    565   "Enable `textDocument/documentColor' integration."
    566   :type 'boolean
    567   :group 'lsp-mode)
    568 
    569 (defcustom lsp-before-save-edits t
    570   "If non-nil, `lsp-mode' will apply edits suggested by the language server
    571 before saving a document."
    572   :type 'boolean
    573   :group 'lsp-mode)
    574 
    575 (defcustom lsp-after-apply-edits-hook nil
    576   "Hooks to run when text edit is applied.
    577 It contains the operation source."
    578   :type 'hook
    579   :group 'lsp-mode
    580   :package-version '(lsp-mode . "8.0.0"))
    581 
    582 (defcustom lsp-apply-edits-after-file-operations t
    583   "Whether to apply edits returned by server after file operations if any.
    584 Applicable only if server supports workspace.fileOperations for operations:
    585 `workspace/willRenameFiles', `workspace/willCreateFiles' and
    586 `workspace/willDeleteFiles'."
    587   :group 'lsp-mode
    588   :type 'boolean)
    589 
    590 (defcustom lsp-modeline-code-actions-enable t
    591   "Whether to show code actions on modeline."
    592   :type 'boolean
    593   :group 'lsp-modeline)
    594 
    595 (defcustom lsp-modeline-diagnostics-enable t
    596   "Whether to show diagnostics on modeline."
    597   :type 'boolean
    598   :group 'lsp-modeline)
    599 
    600 (defcustom lsp-modeline-workspace-status-enable t
    601   "Whether to show workspace status on modeline."
    602   :type 'boolean
    603   :group 'lsp-modeline
    604   :package-version '(lsp-mode . "8.0.0"))
    605 
    606 (defcustom lsp-headerline-breadcrumb-enable t
    607   "Whether to enable breadcrumb on headerline."
    608   :type 'boolean
    609   :group 'lsp-headerline)
    610 
    611 (defcustom lsp-configure-hook nil
    612   "Hooks to run when `lsp-configure-buffer' is called."
    613   :type 'hook
    614   :group 'lsp-mode)
    615 
    616 (defcustom lsp-unconfigure-hook nil
    617   "Hooks to run when `lsp-unconfig-buffer' is called."
    618   :type 'hook
    619   :group 'lsp-mode)
    620 
    621 (defcustom lsp-after-diagnostics-hook nil
    622   "Hooks to run after diagnostics are received.
    623 Note: it runs only if the receiving buffer is open. Use
    624 `lsp-diagnostics-updated-hook'if you want to be notified when
    625 diagnostics have changed."
    626   :type 'hook
    627   :group 'lsp-mode)
    628 
    629 (define-obsolete-variable-alias 'lsp-after-diagnostics-hook
    630   'lsp-diagnostics-updated-hook "lsp-mode 6.4")
    631 
    632 (defcustom lsp-diagnostics-updated-hook nil
    633   "Hooks to run after diagnostics are received."
    634   :type 'hook
    635   :group 'lsp-mode)
    636 
    637 (define-obsolete-variable-alias 'lsp-workspace-folders-changed-hook
    638   'lsp-workspace-folders-changed-functions "lsp-mode 6.3")
    639 
    640 (defcustom lsp-workspace-folders-changed-functions nil
    641   "Hooks to run after the folders has changed.
    642 The hook will receive two parameters list of added and removed folders."
    643   :type 'hook
    644   :group 'lsp-mode)
    645 
    646 (define-obsolete-variable-alias 'lsp-eldoc-hook 'eldoc-documentation-functions "lsp-mode 9.0.0")
    647 
    648 (defcustom lsp-before-apply-edits-hook nil
    649   "Hooks to run before applying edits."
    650   :type 'hook
    651   :group 'lsp-mode)
    652 
    653 (defgroup lsp-imenu nil
    654   "LSP Imenu."
    655   :group 'lsp-mode
    656   :tag "LSP Imenu")
    657 
    658 (defcustom lsp-imenu-show-container-name t
    659   "Display the symbol's container name in an imenu entry."
    660   :type 'boolean
    661   :group 'lsp-imenu)
    662 
    663 (defcustom lsp-imenu-container-name-separator "/"
    664   "Separator string to use to separate the container name from the symbol while
    665 displaying imenu entries."
    666   :type 'string
    667   :group 'lsp-imenu)
    668 
    669 (defcustom lsp-imenu-sort-methods '(kind name)
    670   "How to sort the imenu items.
    671 
    672 The value is a list of `kind' `name' or `position'.  Priorities
    673 are determined by the index of the element."
    674   :type '(repeat (choice (const name)
    675                          (const position)
    676                          (const kind)))
    677   :group 'lsp-imenu)
    678 
    679 (defcustom lsp-imenu-index-symbol-kinds nil
    680   "Which symbol kinds to show in imenu."
    681   :type '(repeat (choice (const :tag "Miscellaneous" nil)
    682                          (const :tag "File" File)
    683                          (const :tag "Module" Module)
    684                          (const :tag "Namespace" Namespace)
    685                          (const :tag "Package" Package)
    686                          (const :tag "Class" Class)
    687                          (const :tag "Method" Method)
    688                          (const :tag "Property" Property)
    689                          (const :tag "Field" Field)
    690                          (const :tag "Constructor" Constructor)
    691                          (const :tag "Enum" Enum)
    692                          (const :tag "Interface" Interface)
    693                          (const :tag "Function" Function)
    694                          (const :tag "Variable" Variable)
    695                          (const :tag "Constant" Constant)
    696                          (const :tag "String" String)
    697                          (const :tag "Number" Number)
    698                          (const :tag "Boolean" Boolean)
    699                          (const :tag "Array" Array)
    700                          (const :tag "Object" Object)
    701                          (const :tag "Key" Key)
    702                          (const :tag "Null" Null)
    703                          (const :tag "Enum Member" EnumMember)
    704                          (const :tag "Struct" Struct)
    705                          (const :tag "Event" Event)
    706                          (const :tag "Operator" Operator)
    707                          (const :tag "Type Parameter" TypeParameter)))
    708   :group 'lsp-imenu)
    709 
    710 ;; vibhavp: Should we use a lower value (5)?
    711 (defcustom lsp-response-timeout 10
    712   "Number of seconds to wait for a response from the language server before
    713 timing out. Nil if no timeout."
    714   :type '(choice
    715           (number :tag "Seconds")
    716           (const :tag "No timeout" nil))
    717   :group 'lsp-mode)
    718 
    719 (defcustom lsp-tcp-connection-timeout 2
    720   "The timeout for tcp connection in seconds."
    721   :type 'number
    722   :group 'lsp-mode
    723   :package-version '(lsp-mode . "6.2"))
    724 
    725 (defconst lsp--imenu-compare-function-alist
    726   (list (cons 'name #'lsp--imenu-compare-name)
    727         (cons 'kind #'lsp--imenu-compare-kind)
    728         (cons 'position #'lsp--imenu-compare-line-col))
    729   "An alist of (METHOD . FUNCTION).
    730 METHOD is one of the symbols accepted by
    731 `lsp-imenu-sort-methods'.
    732 
    733 FUNCTION takes two hash tables representing DocumentSymbol.  It
    734 returns a negative number, 0, or a positive number indicating
    735 whether the first parameter is less than, equal to, or greater
    736 than the second parameter.")
    737 
    738 (defcustom lsp-diagnostic-clean-after-change nil
    739   "When non-nil, clean the diagnostics on change.
    740 
    741 Note that when that setting is nil, `lsp-mode' will show stale
    742 diagnostics until server publishes the new set of diagnostics"
    743   :type 'boolean
    744   :group 'lsp-diagnostics
    745   :package-version '(lsp-mode . "7.0.1"))
    746 
    747 (defcustom lsp-server-trace nil
    748   "Request tracing on the server side.
    749 The actual trace output at each level depends on the language server in use.
    750 Changes take effect only when a new session is started."
    751   :type '(choice (const :tag "Disabled" "off")
    752                  (const :tag "Messages only" "messages")
    753                  (const :tag "Verbose" "verbose")
    754                  (const :tag "Default (disabled)" nil))
    755   :group 'lsp-mode
    756   :package-version '(lsp-mode . "6.1"))
    757 
    758 (defcustom lsp-auto-touch-files t
    759   "If non-nil ensure the files exist before sending
    760 `textDocument/didOpen' notification."
    761   :type 'boolean
    762   :group 'lsp-mode
    763   :package-version '(lsp-mode . "9.0.0"))
    764 
    765 (defvar lsp-language-id-configuration
    766   '(("\\(^CMakeLists\\.txt\\|\\.cmake\\)\\'" . "cmake")
    767     ("\\(^Dockerfile\\(?:\\..*\\)?\\|\\.[Dd]ockerfile\\)\\'" . "dockerfile")
    768     ("\\.astro$" . "astro")
    769     ("\\.cs\\'" . "csharp")
    770     ("\\.css$" . "css")
    771     ("\\.cypher$" . "cypher")
    772     ("Earthfile" . "earthfile")
    773     ("\\.ebuild$" . "shellscript")
    774     ("\\.go\\'" . "go")
    775     ("\\.html$" . "html")
    776     ("\\.hx$" . "haxe")
    777     ("\\.hy$" . "hy")
    778     ("\\.java\\'" . "java")
    779     ("\\.jq$"  . "jq")
    780     ("\\.js$" . "javascript")
    781     ("\\.json$" . "json")
    782     ("\\.jsonc$" . "jsonc")
    783     ("\\.jsonnet$" . "jsonnet")
    784     ("\\.jsx$" . "javascriptreact")
    785     ("\\.lua$" . "lua")
    786     ("\\.mdx\\'" . "mdx")
    787     ("\\.nu$" . "nushell")
    788     ("\\.php$" . "php")
    789     ("\\.ps[dm]?1\\'" . "powershell")
    790     ("\\.rs\\'" . "rust")
    791     ("\\.spec\\'" . "rpm-spec")
    792     ("\\.sql$" . "sql")
    793     ("\\.svelte$" . "svelte")
    794     ("\\.toml\\'" . "toml")
    795     ("\\.ts$" . "typescript")
    796     ("\\.tsx$" . "typescriptreact")
    797     ("\\.ttcn3$" . "ttcn3")
    798     ("\\.vue$" . "vue")
    799     ("\\.xml$" . "xml")
    800     ("\\ya?ml$" . "yaml")
    801     ("^PKGBUILD$" . "shellscript")
    802     ("^go\\.mod\\'" . "go.mod")
    803     ("^settings\\.json$" . "jsonc")
    804     ("^yang\\.settings$" . "jsonc")
    805     ("^meson\\(_options\\.txt\\|\\.\\(build\\|format\\)\\)\\'" . "meson")
    806     (ada-mode . "ada")
    807     (ada-ts-mode . "ada")
    808     (gpr-mode . "gpr")
    809     (gpr-ts-mode . "gpr")
    810     (awk-mode . "awk")
    811     (awk-ts-mode . "awk")
    812     (nxml-mode . "xml")
    813     (sql-mode . "sql")
    814     (vimrc-mode . "vim")
    815     (vimscript-ts-mode . "vim")
    816     (sh-mode . "shellscript")
    817     (bash-ts-mode . "shellscript")
    818     (ebuild-mode . "shellscript")
    819     (pkgbuild-mode . "shellscript")
    820     (envrc-file-mode . "shellscript")
    821     (scala-mode . "scala")
    822     (scala-ts-mode . "scala")
    823     (julia-mode . "julia")
    824     (julia-ts-mode . "julia")
    825     (clojure-mode . "clojure")
    826     (clojurec-mode . "clojure")
    827     (clojurescript-mode . "clojurescript")
    828     (clojure-ts-mode . "clojure")
    829     (clojure-ts-clojurec-mode . "clojure")
    830     (clojure-ts-clojurescript-mode . "clojurescript")
    831     (java-mode . "java")
    832     (java-ts-mode . "java")
    833     (jdee-mode . "java")
    834     (groovy-mode . "groovy")
    835     (python-mode . "python")
    836     (python-ts-mode . "python")
    837     (cython-mode . "python")
    838     ("\\(\\.mojo\\|\\.🔥\\)\\'" . "mojo")
    839     (lsp--render-markdown . "markdown")
    840     (move-mode . "move")
    841     (rust-mode . "rust")
    842     (rust-ts-mode . "rust")
    843     (rustic-mode . "rust")
    844     (kotlin-mode . "kotlin")
    845     (kotlin-ts-mode . "kotlin")
    846     (css-mode . "css")
    847     (css-ts-mode . "css")
    848     (less-mode . "less")
    849     (less-css-mode . "less")
    850     (lua-mode . "lua")
    851     (lua-ts-mode . "lua")
    852     (sass-mode . "sass")
    853     (ssass-mode . "sass")
    854     (scss-mode . "scss")
    855     (scad-mode . "openscad")
    856     (xml-mode . "xml")
    857     (c-mode . "c")
    858     (c-ts-mode . "c")
    859     (c++-mode . "cpp")
    860     (c++-ts-mode . "cpp")
    861     (cuda-mode . "cuda")
    862     (objc-mode . "objective-c")
    863     (html-mode . "html")
    864     (html-ts-mode . "html")
    865     (sgml-mode . "html")
    866     (mhtml-mode . "html")
    867     (mint-mode . "mint")
    868     (go-dot-mod-mode . "go.mod")
    869     (go-mod-ts-mode . "go.mod")
    870     (go-mode . "go")
    871     (go-ts-mode . "go")
    872     (graphql-mode . "graphql")
    873     (haskell-mode . "haskell")
    874     (hack-mode . "hack")
    875     (php-mode . "php")
    876     (php-ts-mode . "php")
    877     (powershell-mode . "powershell")
    878     (powershell-mode . "PowerShell")
    879     (powershell-ts-mode . "powershell")
    880     (json-mode . "json")
    881     (json-ts-mode . "json")
    882     (jsonc-mode . "jsonc")
    883     (rjsx-mode . "javascript")
    884     (js2-mode . "javascript")
    885     (js-mode . "javascript")
    886     (js-ts-mode . "javascript")
    887     (typescript-mode . "typescript")
    888     (typescript-ts-mode . "typescript")
    889     (tsx-ts-mode . "typescriptreact")
    890     (svelte-mode . "svelte")
    891     (fsharp-mode . "fsharp")
    892     (reason-mode . "reason")
    893     (caml-mode . "ocaml")
    894     (tuareg-mode . "ocaml")
    895     (swift-mode . "swift")
    896     (elixir-mode . "elixir")
    897     (elixir-ts-mode . "elixir")
    898     (heex-ts-mode . "elixir")
    899     (conf-javaprop-mode . "spring-boot-properties")
    900     (yaml-mode . "yaml")
    901     (yaml-ts-mode . "yaml")
    902     (ruby-mode . "ruby")
    903     (enh-ruby-mode . "ruby")
    904     (ruby-ts-mode . "ruby")
    905     (fortran-mode . "fortran")
    906     (f90-mode . "fortran")
    907     (elm-mode . "elm")
    908     (dart-mode . "dart")
    909     (erlang-mode . "erlang")
    910     (dockerfile-mode . "dockerfile")
    911     (dockerfile-ts-mode . "dockerfile")
    912     (csharp-mode . "csharp")
    913     (csharp-tree-sitter-mode . "csharp")
    914     (csharp-ts-mode . "csharp")
    915     (plain-tex-mode . "plaintex")
    916     (context-mode . "context")
    917     (cypher-mode . "cypher")
    918     (latex-mode . "latex")
    919     (LaTeX-mode . "latex")
    920     (v-mode . "v")
    921     (vhdl-mode . "vhdl")
    922     (vhdl-ts-mode . "vhdl")
    923     (verilog-mode . "verilog")
    924     (terraform-mode . "terraform")
    925     (ess-julia-mode . "julia")
    926     (ess-r-mode . "r")
    927     (crystal-mode . "crystal")
    928     (nim-mode . "nim")
    929     (dhall-mode . "dhall")
    930     (cmake-mode . "cmake")
    931     (cmake-ts-mode . "cmake")
    932     (purescript-mode . "purescript")
    933     (gdscript-mode . "gdscript")
    934     (gdscript-ts-mode . "gdscript")
    935     (perl-mode . "perl")
    936     (cperl-mode . "perl")
    937     (robot-mode . "robot")
    938     (racket-mode . "racket")
    939     (nix-mode . "nix")
    940     (nix-ts-mode . "Nix")
    941     (prolog-mode . "prolog")
    942     (vala-mode . "vala")
    943     (actionscript-mode . "actionscript")
    944     (d-mode . "d")
    945     (zig-mode . "zig")
    946     (text-mode . "plaintext")
    947     (markdown-mode . "markdown")
    948     (gfm-mode . "markdown")
    949     (beancount-mode . "beancount")
    950     (conf-toml-mode . "toml")
    951     (toml-ts-mode . "toml")
    952     (org-mode . "org")
    953     (org-journal-mode . "org")
    954     (nginx-mode . "nginx")
    955     (magik-mode . "magik")
    956     (magik-ts-mode . "magik")
    957     (idris-mode . "idris")
    958     (idris2-mode . "idris2")
    959     (gleam-mode . "gleam")
    960     (gleam-ts-mode . "gleam")
    961     (graphviz-dot-mode . "dot")
    962     (tiltfile-mode . "tiltfile")
    963     (solidity-mode . "solidity")
    964     (bibtex-mode . "bibtex")
    965     (rst-mode . "restructuredtext")
    966     (glsl-mode . "glsl")
    967     (shader-mode . "shaderlab")
    968     (wgsl-mode . "wgsl")
    969     (jq-mode . "jq")
    970     (jq-ts-mode . "jq")
    971     (protobuf-mode . "protobuf")
    972     (nushell-mode . "nushell")
    973     (nushell-ts-mode . "nushell")
    974     (meson-mode . "meson")
    975     (yang-mode . "yang"))
    976   "Language id configuration.")
    977 
    978 (defvar lsp--last-active-workspaces nil
    979   "Keep track of last active workspace.
    980 We want to try the last workspace first when jumping into a library
    981 directory")
    982 
    983 (defvar lsp-method-requirements
    984   '(("textDocument/callHierarchy" :capability :callHierarchyProvider)
    985     ("textDocument/codeAction" :capability :codeActionProvider)
    986     ("codeAction/resolve"
    987      :check-command (lambda (workspace)
    988                       (with-lsp-workspace workspace
    989                         (lsp:code-action-options-resolve-provider?
    990                          (lsp--capability-for-method "textDocument/codeAction")))))
    991     ("textDocument/codeLens" :capability :codeLensProvider)
    992     ("textDocument/completion" :capability :completionProvider)
    993     ("completionItem/resolve"
    994      :check-command (lambda (wk)
    995                       (with-lsp-workspace wk
    996                         (lsp:completion-options-resolve-provider?
    997                          (lsp--capability-for-method "textDocument/completion")))))
    998     ("textDocument/declaration" :capability :declarationProvider)
    999     ("textDocument/definition" :capability :definitionProvider)
   1000     ("textDocument/documentColor" :capability :colorProvider)
   1001     ("textDocument/documentLink" :capability :documentLinkProvider)
   1002     ("textDocument/inlayHint" :capability :inlayHintProvider)
   1003     ("textDocument/documentHighlight" :capability :documentHighlightProvider)
   1004     ("textDocument/documentSymbol" :capability :documentSymbolProvider)
   1005     ("textDocument/foldingRange" :capability :foldingRangeProvider)
   1006     ("textDocument/formatting" :capability :documentFormattingProvider)
   1007     ("textDocument/hover" :capability :hoverProvider)
   1008     ("textDocument/implementation" :capability :implementationProvider)
   1009     ("textDocument/linkedEditingRange" :capability :linkedEditingRangeProvider)
   1010     ("textDocument/onTypeFormatting" :capability :documentOnTypeFormattingProvider)
   1011     ("textDocument/prepareRename"
   1012      :check-command (lambda (workspace)
   1013                       (with-lsp-workspace workspace
   1014                         (lsp:rename-options-prepare-provider?
   1015                          (lsp--capability-for-method "textDocument/rename")))))
   1016     ("textDocument/rangeFormatting" :capability :documentRangeFormattingProvider)
   1017     ("textDocument/references" :capability :referencesProvider)
   1018     ("textDocument/rename" :capability :renameProvider)
   1019     ("textDocument/selectionRange" :capability :selectionRangeProvider)
   1020     ("textDocument/semanticTokens" :capability :semanticTokensProvider)
   1021     ("textDocument/semanticTokensFull"
   1022      :check-command (lambda (workspace)
   1023                       (with-lsp-workspace workspace
   1024                         (lsp-get (lsp--capability :semanticTokensProvider) :full))))
   1025     ("textDocument/semanticTokensFull/Delta"
   1026      :check-command (lambda (workspace)
   1027                       (with-lsp-workspace workspace
   1028                         (let ((capFull (lsp-get (lsp--capability :semanticTokensProvider) :full)))
   1029                           (and (not (booleanp capFull)) (lsp-get capFull :delta))))))
   1030     ("textDocument/semanticTokensRangeProvider"
   1031      :check-command (lambda (workspace)
   1032                       (with-lsp-workspace workspace
   1033                         (lsp-get (lsp--capability :semanticTokensProvider) :range))))
   1034     ("textDocument/signatureHelp" :capability :signatureHelpProvider)
   1035     ("textDocument/typeDefinition" :capability :typeDefinitionProvider)
   1036     ("textDocument/typeHierarchy" :capability :typeHierarchyProvider)
   1037     ("workspace/executeCommand" :capability :executeCommandProvider)
   1038     ("workspace/symbol" :capability :workspaceSymbolProvider))
   1039 
   1040   "Map methods to requirements.
   1041 It is used by request-sending functions to determine which server
   1042 must be used for handling a particular message.")
   1043 
   1044 (defconst lsp--file-change-type
   1045   `((created . 1)
   1046     (changed . 2)
   1047     (deleted . 3)))
   1048 
   1049 (defconst lsp--watch-kind
   1050   `((create . 1)
   1051     (change . 2)
   1052     (delete . 4)))
   1053 
   1054 (defvar lsp-window-body-width 40
   1055   "Window body width when rendering doc.")
   1056 
   1057 (defface lsp-face-highlight-textual
   1058   '((t :inherit highlight))
   1059   "Face used for textual occurrences of symbols."
   1060   :group 'lsp-mode)
   1061 
   1062 (defface lsp-face-highlight-read
   1063   '((t :inherit highlight :underline t))
   1064   "Face used for highlighting symbols being read."
   1065   :group 'lsp-mode)
   1066 
   1067 (defface lsp-face-highlight-write
   1068   '((t :inherit highlight :weight bold))
   1069   "Face used for highlighting symbols being written to."
   1070   :group 'lsp-mode)
   1071 
   1072 (define-obsolete-variable-alias 'lsp-lens-auto-enable
   1073   'lsp-lens-enable "lsp-mode 7.0.1")
   1074 
   1075 (defcustom lsp-lens-enable t
   1076   "Auto enable lenses if server supports."
   1077   :group 'lsp-lens
   1078   :type 'boolean
   1079   :package-version '(lsp-mode . "6.3"))
   1080 
   1081 (defcustom lsp-symbol-highlighting-skip-current nil
   1082   "If non-nil skip current symbol when setting symbol highlights."
   1083   :group 'lsp-mode
   1084   :type 'boolean)
   1085 
   1086 (defcustom lsp-file-watch-threshold 1000
   1087   "Show warning if the files to watch are more than.
   1088 Set to nil to disable the warning."
   1089   :type 'number
   1090   :group 'lsp-mode)
   1091 ;;;###autoload(put 'lsp-file-watch-threshold 'safe-local-variable (lambda (i) (or (numberp i) (not i))))
   1092 
   1093 (defvar lsp-custom-markup-modes
   1094   '((rust-mode "no_run" "rust,no_run" "rust,ignore" "rust,should_panic"))
   1095   "Mode to uses with markdown code blocks.
   1096 They are added to `markdown-code-lang-modes'")
   1097 
   1098 (defcustom lsp-signature-render-documentation t
   1099   "Display signature documentation in `eldoc'."
   1100   :type 'boolean
   1101   :group 'lsp-mode
   1102   :package-version '(lsp-mode . "6.2"))
   1103 
   1104 (defcustom lsp-signature-auto-activate '(:on-trigger-char :on-server-request)
   1105   "Auto activate signature conditions."
   1106   :type '(repeat (choice (const :tag "On trigger chars pressed." :on-trigger-char)
   1107                          (const :tag "After selected completion." :after-completion)
   1108                          (const :tag "When the server has sent show signature help." :on-server-request)))
   1109   :group 'lsp-mode
   1110   :package-version '(lsp-mode . "6.2"))
   1111 
   1112 (defcustom lsp-signature-doc-lines 20
   1113   "If number, limit the number of lines to show in the docs."
   1114   :type 'number
   1115   :group 'lsp-mode
   1116   :package-version '(lsp-mode . "6.3"))
   1117 
   1118 (defcustom lsp-signature-function 'lsp-lv-message
   1119   "The function used for displaying signature info.
   1120 It will be called with one param - the signature info. When
   1121 called with nil the signature info must be cleared."
   1122   :type 'function
   1123   :group 'lsp-mode
   1124   :package-version '(lsp-mode . "6.3"))
   1125 
   1126 (defcustom lsp-keymap-prefix "s-l"
   1127   "LSP-mode keymap prefix."
   1128   :group 'lsp-mode
   1129   :type 'string
   1130   :package-version '(lsp-mode . "6.3"))
   1131 
   1132 (defvar-local lsp--buffer-workspaces ()
   1133   "List of the buffer workspaces.")
   1134 
   1135 (defvar-local lsp--buffer-deferred nil
   1136   "Whether buffer was loaded via `lsp-deferred'.")
   1137 
   1138 (defvar lsp--session nil
   1139   "Contain the `lsp-session' for the current Emacs instance.")
   1140 
   1141 (defvar lsp--tcp-port 10000)
   1142 
   1143 (defvar lsp--client-packages-required nil
   1144   "If nil, `lsp-client-packages' are yet to be required.")
   1145 
   1146 (defvar lsp--tcp-server-port 0
   1147   "The server socket which is opened when using `lsp-tcp-server' (a server
   1148 socket is opened in Emacs and the language server connects to it).  The
   1149 default value of 0 ensures that a random high port is used. Set it to a positive
   1150 integer to use a specific port.")
   1151 
   1152 (defvar lsp--tcp-server-wait-seconds 10
   1153   "Wait this amount of time for the client to connect to our server socket
   1154 when using `lsp-tcp-server'.")
   1155 
   1156 (defvar-local lsp--document-symbols nil
   1157   "The latest document symbols.")
   1158 
   1159 (defvar-local lsp--document-selection-range-cache nil
   1160   "The document selection cache.")
   1161 
   1162 (defvar-local lsp--document-symbols-request-async nil
   1163   "If non-nil, request document symbols asynchronously.")
   1164 
   1165 (defvar-local lsp--document-symbols-tick -1
   1166   "The value of `buffer-chars-modified-tick' when document
   1167   symbols were last retrieved.")
   1168 
   1169 (defvar-local lsp--have-document-highlights nil
   1170   "Set to `t' on symbol highlighting, cleared on
   1171 `lsp--cleanup-highlights-if-needed'. Checking a separately
   1172 defined flag is substantially faster than unconditionally
   1173 calling `remove-overlays'.")
   1174 
   1175 ;; Buffer local variable for storing number of lines.
   1176 (defvar lsp--log-lines)
   1177 
   1178 (defvar-local lsp--eldoc-saved-message nil)
   1179 
   1180 (defvar lsp--on-change-timer nil)
   1181 (defvar lsp--on-idle-timer nil)
   1182 
   1183 (defvar-local lsp--signature-last nil)
   1184 (defvar-local lsp--signature-last-index nil)
   1185 (defvar lsp--signature-last-buffer nil)
   1186 
   1187 (defvar-local lsp--virtual-buffer-point-max nil)
   1188 
   1189 (cl-defmethod lsp-execute-command (_server _command _arguments)
   1190   "Ask SERVER to execute COMMAND with ARGUMENTS.")
   1191 
   1192 (defun lsp-elt (sequence n)
   1193   "Return Nth element of SEQUENCE or nil if N is out of range."
   1194   (cond
   1195    ((listp sequence) (elt sequence n))
   1196    ((arrayp sequence)
   1197     (and (> (length sequence) n) (aref sequence n)))
   1198    (t (and (> (length sequence) n) (elt sequence n)))))
   1199 
   1200 ;; define seq-first and seq-rest for older emacs
   1201 (defun lsp-seq-first (sequence)
   1202   "Return the first element of SEQUENCE."
   1203   (lsp-elt sequence 0))
   1204 
   1205 (defun lsp-seq-rest (sequence)
   1206   "Return a sequence of the elements of SEQUENCE except the first one."
   1207   (seq-drop sequence 1))
   1208 
   1209 ;;;###autoload
   1210 (defun lsp--string-listp (sequence)
   1211   "Return t if all elements of SEQUENCE are strings, else nil."
   1212   (not (seq-find (lambda (x) (not (stringp x))) sequence)))
   1213 
   1214 (defun lsp--string-vector-p (candidate)
   1215   "Returns true if CANDIDATE is a vector data structure and
   1216 every element of it is of type string, else nil."
   1217   (and
   1218    (vectorp candidate)
   1219    (seq-every-p #'stringp candidate)))
   1220 
   1221 (make-obsolete 'lsp--string-vector-p nil "lsp-mode 8.0.0")
   1222 
   1223 (defun lsp--editable-vector-match (widget value)
   1224   "Function for `lsp-editable-vector' :match."
   1225   ;; Value must be a list or a vector and all the members must match the type.
   1226   (and (or (listp value) (vectorp value))
   1227        (length (cdr (lsp--editable-vector-match-inline widget value)))))
   1228 
   1229 (defun lsp--editable-vector-match-inline (widget value)
   1230   "Value for `lsp-editable-vector' :match-inline."
   1231   (let ((type (nth 0 (widget-get widget :args)))
   1232         (ok t)
   1233         found)
   1234     (while (and value ok)
   1235       (let ((answer (widget-match-inline type value)))
   1236         (if answer
   1237             (let ((head (if (vectorp answer) (aref answer 0) (car answer)))
   1238                   (tail (if (vectorp answer) (seq-drop 1 answer) (cdr answer))))
   1239               (setq found (append found head)
   1240                     value tail))
   1241           (setq ok nil))))
   1242     (cons found value)))
   1243 
   1244 (defun lsp--editable-vector-value-to-external (_widget internal-value)
   1245   "Convert the internal list value to a vector."
   1246   (if (listp internal-value)
   1247       (apply 'vector internal-value)
   1248     internal-value))
   1249 
   1250 (defun lsp--editable-vector-value-to-internal (_widget external-value)
   1251   "Convert the external vector value to a list."
   1252   (if (vectorp external-value)
   1253       (append external-value nil)
   1254     external-value))
   1255 
   1256 (define-widget 'lsp--editable-vector 'editable-list
   1257   "A subclass of `editable-list' that accepts and returns a
   1258 vector instead of a list."
   1259   :value-to-external 'lsp--editable-vector-value-to-external
   1260   :value-to-internal 'lsp--editable-vector-value-to-internal
   1261   :match 'lsp--editable-vector-match
   1262   :match-inline 'lsp--editable-vector-match-inline)
   1263 
   1264 (define-widget 'lsp-repeatable-vector 'lsp--editable-vector
   1265   "A variable length homogeneous vector."
   1266   :tag "Repeat"
   1267   :format "%{%t%}:\n%v%i\n")
   1268 
   1269 (define-widget 'lsp-string-vector 'lazy
   1270   "A vector of zero or more elements, every element of which is a string.
   1271 Appropriate for any language-specific `defcustom' that needs to
   1272 serialize as a JSON array of strings.
   1273 
   1274 Deprecated. Use `lsp-repeatable-vector' instead. "
   1275   :offset 4
   1276   :tag "Vector"
   1277   :type '(lsp-repeatable-vector string))
   1278 
   1279 (make-obsolete 'lsp-string-vector nil "lsp-mode 8.0.0")
   1280 
   1281 (defvar lsp--show-message t
   1282   "If non-nil, show debug message from `lsp-mode'.")
   1283 
   1284 (defun lsp--message  (format &rest args)
   1285   "Wrapper for `message'
   1286 
   1287 We `inhibit-message' the message when the cursor is in the
   1288 minibuffer and when emacs version is before emacs 27 due to the
   1289 fact that we often use `lsp--info', `lsp--warn' and `lsp--error'
   1290 in async context and the call to these function is removing the
   1291 minibuffer prompt. The issue with async messages is already fixed
   1292 in emacs 27.
   1293 
   1294 See #2049"
   1295   (when lsp--show-message
   1296     (let ((inhibit-message (or inhibit-message
   1297                                (and (minibufferp)
   1298                                     (version< emacs-version "27.0")))))
   1299       (apply #'message format args))))
   1300 
   1301 (defun lsp--info (format &rest args)
   1302   "Display lsp info message with FORMAT with ARGS."
   1303   (lsp--message "%s :: %s" (propertize "LSP" 'face 'success) (apply #'format format args)))
   1304 
   1305 (defun lsp--warn (format &rest args)
   1306   "Display lsp warn message with FORMAT with ARGS."
   1307   (lsp--message "%s :: %s" (propertize "LSP" 'face 'warning) (apply #'format format args)))
   1308 
   1309 (defun lsp--error (format &rest args)
   1310   "Display lsp error message with FORMAT with ARGS."
   1311   (lsp--message "%s :: %s" (propertize "LSP" 'face 'error) (apply #'format format args)))
   1312 
   1313 (defun lsp-log (format &rest args)
   1314   "Log message to the ’*lsp-log*’ buffer.
   1315 
   1316 FORMAT and ARGS i the same as for `message'."
   1317   (when lsp-log-max
   1318     (let ((log-buffer (get-buffer "*lsp-log*"))
   1319           (inhibit-read-only t))
   1320       (unless log-buffer
   1321         (setq log-buffer (get-buffer-create "*lsp-log*"))
   1322         (with-current-buffer log-buffer
   1323           (buffer-disable-undo)
   1324           (view-mode 1)
   1325           (set (make-local-variable 'lsp--log-lines) 0)))
   1326       (with-current-buffer log-buffer
   1327         (save-excursion
   1328           (let* ((message (apply 'format format args))
   1329                  ;; Count newlines in message.
   1330                  (newlines (1+ (cl-loop with start = 0
   1331                                         for count from 0
   1332                                         while (string-match "\n" message start)
   1333                                         do (setq start (match-end 0))
   1334                                         finally return count))))
   1335             (goto-char (point-max))
   1336 
   1337             ;; in case the buffer is not empty insert before last \n to preserve
   1338             ;; the point position(in case it is in the end)
   1339             (if (eq (point) (point-min))
   1340                 (progn
   1341                   (insert "\n")
   1342                   (backward-char))
   1343               (backward-char)
   1344               (insert "\n"))
   1345             (insert message)
   1346 
   1347             (setq lsp--log-lines (+ lsp--log-lines newlines))
   1348 
   1349             (when (and (integerp lsp-log-max) (> lsp--log-lines lsp-log-max))
   1350               (let ((to-delete (- lsp--log-lines lsp-log-max)))
   1351                 (goto-char (point-min))
   1352                 (forward-line to-delete)
   1353                 (delete-region (point-min) (point))
   1354                 (setq lsp--log-lines lsp-log-max)))))))))
   1355 
   1356 (defalias 'lsp-message 'lsp-log)
   1357 
   1358 (defalias 'lsp-ht 'ht)
   1359 
   1360 (defalias 'lsp-file-local-name 'file-local-name)
   1361 
   1362 (defun lsp-f-canonical (file-name)
   1363   "Return the canonical FILE-NAME, without a trailing slash."
   1364   (directory-file-name (expand-file-name file-name)))
   1365 
   1366 (defalias 'lsp-canonical-file-name 'lsp-f-canonical)
   1367 
   1368 (defun lsp-f-same? (path-a path-b)
   1369   "Return t if PATH-A and PATH-B are references to the same file.
   1370 Symlinks are not followed."
   1371   (when (and (f-exists? path-a)
   1372              (f-exists? path-b))
   1373     (equal
   1374      (lsp-f-canonical (directory-file-name (f-expand path-a)))
   1375      (lsp-f-canonical (directory-file-name (f-expand path-b))))))
   1376 
   1377 (defun lsp-f-parent (path)
   1378   "Return the parent directory to PATH.
   1379 Symlinks are not followed."
   1380   (let ((parent (file-name-directory
   1381                  (directory-file-name (f-expand path default-directory)))))
   1382     (unless (lsp-f-same? path parent)
   1383       (if (f-relative? path)
   1384           (f-relative parent)
   1385         (directory-file-name parent)))))
   1386 
   1387 (defun lsp-f-ancestor-of? (path-a path-b)
   1388   "Return t if PATH-A is an ancestor of PATH-B.
   1389 Symlinks are not followed."
   1390   (unless (lsp-f-same? path-a path-b)
   1391     (s-prefix? (concat (lsp-f-canonical path-a) (f-path-separator))
   1392                (lsp-f-canonical path-b))))
   1393 
   1394 (defun lsp--merge-results (results method)
   1395   "Merge RESULTS by filtering the empty hash-tables and merging
   1396 the lists according to METHOD."
   1397   (pcase (--map (if (vectorp it)
   1398                     (append it nil) it)
   1399                 (-filter #'identity results))
   1400     (`() ())
   1401     ;; only one result - simply return it
   1402     (`(,fst) fst)
   1403     ;; multiple results merge it based on strategy
   1404     (results
   1405      (pcase method
   1406        ("textDocument/hover" (pcase (seq-filter
   1407                                      (-compose #'not #'lsp-empty?)
   1408                                      results)
   1409                                (`(,hover) hover)
   1410                                (hovers (lsp-make-hover
   1411                                         :contents
   1412                                         (-mapcat
   1413                                          (-lambda ((&Hover :contents))
   1414                                            (if (and (sequencep contents)
   1415                                                     (not (stringp contents)))
   1416                                                (append contents ())
   1417                                              (list contents)))
   1418                                          hovers)))))
   1419        ("textDocument/completion"
   1420         (lsp-make-completion-list
   1421          :is-incomplete (seq-some
   1422                          #'lsp:completion-list-is-incomplete
   1423                          results)
   1424          :items (cl-mapcan (lambda (it) (append (if (lsp-completion-list? it)
   1425                                                     (lsp:completion-list-items it)
   1426                                                   it)
   1427                                                 nil))
   1428                            results)))
   1429        ("completionItem/resolve"
   1430         (let ((item (cl-first results)))
   1431           (when-let ((details (seq-filter #'identity
   1432                                           (seq-map #'lsp:completion-item-detail? results))))
   1433             (lsp:set-completion-item-detail?
   1434              item
   1435              (string-join details " ")))
   1436           (when-let ((docs (seq-filter #'identity
   1437                                        (seq-map #'lsp:completion-item-documentation? results))))
   1438             (lsp:set-completion-item-documentation?
   1439              item
   1440              (lsp-make-markup-content
   1441               :kind (or (seq-some (lambda (it)
   1442                                     (when (equal (lsp:markup-content-kind it)
   1443                                                  lsp/markup-kind-markdown)
   1444                                       lsp/markup-kind-markdown))
   1445                                   docs)
   1446                         lsp/markup-kind-plain-text)
   1447               :value (string-join (seq-map (lambda (doc)
   1448                                              (or (lsp:markup-content-value doc)
   1449                                                  (and (stringp doc) doc)))
   1450                                            docs)
   1451                                   "\n"))))
   1452           (when-let ((edits (seq-filter #'identity
   1453                                         (seq-map #'lsp:completion-item-additional-text-edits? results))))
   1454             (lsp:set-completion-item-additional-text-edits?
   1455              item
   1456              (cl-mapcan (lambda (it) (if (seqp it) it (list it))) edits)))
   1457           item))
   1458        (_ (cl-mapcan (lambda (it) (if (seqp it) it (list it))) results))))))
   1459 
   1460 (defun lsp--spinner-start ()
   1461   "Start spinner indication."
   1462   (condition-case _err (spinner-start (lsp-progress-spinner-type)) (error)))
   1463 
   1464 (defun lsp--propertize (str type)
   1465   "Propertize STR as per TYPE."
   1466   (propertize str 'face (alist-get type lsp--message-type-face)))
   1467 
   1468 (defun lsp-workspaces ()
   1469   "Return the lsp workspaces associated with the current project."
   1470   (if lsp--cur-workspace (list lsp--cur-workspace) lsp--buffer-workspaces))
   1471 
   1472 (defun lsp--completing-read (prompt collection transform-fn &optional predicate
   1473                                     require-match initial-input
   1474                                     hist def inherit-input-method)
   1475   "Wrap `completing-read' to provide transformation function and disable sort.
   1476 
   1477 TRANSFORM-FN will be used to transform each of the items before displaying.
   1478 
   1479 PROMPT COLLECTION PREDICATE REQUIRE-MATCH INITIAL-INPUT HIST DEF
   1480 INHERIT-INPUT-METHOD will be proxied to `completing-read' without changes."
   1481   (let* ((col (--map (cons (funcall transform-fn it) it) collection))
   1482          (completion (completing-read prompt
   1483                                       (lambda (string pred action)
   1484                                         (if (eq action 'metadata)
   1485                                             `(metadata (display-sort-function . identity))
   1486                                           (complete-with-action action col string pred)))
   1487                                       predicate require-match initial-input hist
   1488                                       def inherit-input-method)))
   1489     (cdr (assoc completion col))))
   1490 
   1491 (defconst lsp--system-arch (lambda ()
   1492                              (setq lsp--system-arch
   1493                                    (pcase system-type
   1494                                      ('windows-nt
   1495                                       (pcase system-configuration
   1496                                         ((rx bol "x86_64-") 'x64)
   1497                                         (_ 'x86)))
   1498                                      ('darwin
   1499                                       (pcase system-configuration
   1500                                         ((rx "aarch64-") 'arm64)
   1501                                         (_ 'x64)))
   1502                                      ('gnu/linux
   1503                                        (pcase system-configuration
   1504                                          ((rx bol "x86_64") 'x64)
   1505                                          ((rx bol (| "i386" "i886")) 'x32)))
   1506                                      (_
   1507                                       (pcase system-configuration
   1508                                         ((rx bol "x86_64") 'x64)
   1509                                         ((rx bol (| "i386" "i886")) 'x32))))))
   1510   "Return the system architecture of `Emacs'.
   1511 Special values:
   1512   `x64'       64bit
   1513   `x32'       32bit
   1514   `arm64'     ARM 64bit")
   1515 
   1516 (defmacro lsp-with-current-buffer (buffer-id &rest body)
   1517   (declare (indent 1) (debug t))
   1518   `(if-let ((wcb (plist-get ,buffer-id :with-current-buffer)))
   1519        (with-lsp-workspaces (plist-get ,buffer-id :workspaces)
   1520          (funcall wcb (lambda () ,@body)))
   1521      (with-current-buffer ,buffer-id
   1522        ,@body)))
   1523 
   1524 (defvar lsp--throw-on-input nil
   1525   "Make `lsp-*-while-no-input' throws `input' on interrupted.")
   1526 
   1527 (defmacro lsp--catch (tag bodyform &rest handlers)
   1528   "Catch TAG thrown in BODYFORM.
   1529 The return value from TAG will be handled in HANDLERS by `pcase'."
   1530   (declare (debug (form form &rest (pcase-PAT body))) (indent 2))
   1531   (let ((re-sym (make-symbol "re")))
   1532     `(let ((,re-sym (catch ,tag ,bodyform)))
   1533        (pcase ,re-sym
   1534          ,@handlers))))
   1535 
   1536 (defmacro lsp--while-no-input (&rest body)
   1537   "Wrap BODY in `while-no-input' and respecting `non-essential'.
   1538 If `lsp--throw-on-input' is set, will throw if input is pending, else
   1539 return value of `body' or nil if interrupted."
   1540   (declare (debug t) (indent 0))
   1541   `(if non-essential
   1542        (let ((res (while-no-input ,@body)))
   1543          (cond
   1544           ((and lsp--throw-on-input (equal res t))
   1545            (throw 'input :interrupted))
   1546           ((booleanp res) nil)
   1547           (t res)))
   1548      ,@body))
   1549 
   1550 ;; A ‘lsp--client’ object describes the client-side behavior of a language
   1551 ;; server.  It is used to start individual server processes, each of which is
   1552 ;; represented by a ‘lsp--workspace’ object.  Client objects are normally
   1553 ;; created using ‘lsp-define-stdio-client’ or ‘lsp-define-tcp-client’.  Each
   1554 ;; workspace refers to exactly one client, but there can be multiple workspaces
   1555 ;; for a single client.
   1556 (cl-defstruct lsp--client
   1557   ;; ‘language-id’ is a function that receives a buffer as a single argument
   1558   ;; and should return the language identifier for that buffer.  See
   1559   ;; https://microsoft.github.io/language-server-protocol/specification#textdocumentitem
   1560   ;; for a list of language identifiers.  Also consult the documentation for
   1561   ;; the language server represented by this client to find out what language
   1562   ;; identifiers it supports or expects.
   1563   (language-id nil)
   1564 
   1565   ;; ‘add-on?’ when set to t the server will be started no matter whether there
   1566   ;; is another server handling the same mode.
   1567   (add-on? nil)
   1568   ;; ‘new-connection’ is a function that should start a language server process
   1569   ;; and return a cons (COMMAND-PROCESS . COMMUNICATION-PROCESS).
   1570   ;; COMMAND-PROCESS must be a process object representing the server process
   1571   ;; just started.  COMMUNICATION-PROCESS must be a process (including pipe and
   1572   ;; network processes) that ‘lsp-mode’ uses to communicate with the language
   1573   ;; server using the language server protocol.  COMMAND-PROCESS and
   1574   ;; COMMUNICATION-PROCESS may be the same process; in that case
   1575   ;; ‘new-connection’ may also return that process as a single
   1576   ;; object. ‘new-connection’ is called with two arguments, FILTER and
   1577   ;; SENTINEL.  FILTER should be used as process filter for
   1578   ;; COMMUNICATION-PROCESS, and SENTINEL should be used as process sentinel for
   1579   ;; COMMAND-PROCESS.
   1580   (new-connection nil)
   1581 
   1582   ;; ‘ignore-regexps’ is a list of regexps.  When a data packet from the
   1583   ;; language server matches any of these regexps, it will be ignored.  This is
   1584   ;; intended for dealing with language servers that output non-protocol data.
   1585   (ignore-regexps nil)
   1586 
   1587   ;; ‘ignore-messages’ is a list of regexps.  When a message from the language
   1588   ;; server matches any of these regexps, it will be ignored.  This is useful
   1589   ;; for filtering out unwanted messages; such as servers that send nonstandard
   1590   ;; message types, or extraneous log messages.
   1591   (ignore-messages nil)
   1592 
   1593   ;; ‘notification-handlers’ is a hash table mapping notification method names
   1594   ;; (strings) to functions handling the respective notifications.  Upon
   1595   ;; receiving a notification, ‘lsp-mode’ will call the associated handler
   1596   ;; function passing two arguments, the ‘lsp--workspace’ object and the
   1597   ;; deserialized notification parameters.
   1598   (notification-handlers (make-hash-table :test 'equal))
   1599 
   1600   ;; ‘request-handlers’ is a hash table mapping request method names
   1601   ;; (strings) to functions handling the respective notifications.  Upon
   1602   ;; receiving a request, ‘lsp-mode’ will call the associated handler function
   1603   ;; passing two arguments, the ‘lsp--workspace’ object and the deserialized
   1604   ;; request parameters.
   1605   (request-handlers (make-hash-table :test 'equal))
   1606 
   1607   ;; ‘response-handlers’ is a hash table mapping integral JSON-RPC request
   1608   ;; identifiers for pending asynchronous requests to functions handling the
   1609   ;; respective responses.  Upon receiving a response from the language server,
   1610   ;; ‘lsp-mode’ will call the associated response handler function with a
   1611   ;; single argument, the deserialized response parameters.
   1612   (response-handlers (make-hash-table :test 'eql))
   1613 
   1614   ;; ‘prefix-function’ is called for getting the prefix for completion.
   1615   ;; The function takes no parameter and returns a cons (start . end) representing
   1616   ;; the start and end bounds of the prefix. If it's not set, the client uses a
   1617   ;; default prefix function."
   1618   (prefix-function nil)
   1619 
   1620   ;; Contains mapping of scheme to the function that is going to be used to load
   1621   ;; the file.
   1622   (uri-handlers (make-hash-table :test #'equal))
   1623 
   1624   ;; ‘action-handlers’ is a hash table mapping action to a handler function. It
   1625   ;; can be used in `lsp-execute-code-action' to determine whether the action
   1626   ;; current client is interested in executing the action instead of sending it
   1627   ;; to the server.
   1628   (action-handlers (make-hash-table :test 'equal))
   1629 
   1630   ;; `action-filter' can be set to a function that modifies any incoming
   1631   ;; `CodeAction' in place before it is executed. The return value is ignored.
   1632   ;; This can be used to patch up broken code action requests before they are
   1633   ;; sent back to the LSP server. See `lsp-fix-code-action-booleans' for an
   1634   ;; example of a function that can be useful here.
   1635   (action-filter nil)
   1636 
   1637   ;; major modes supported by the client.
   1638   major-modes
   1639   ;; Function that will be called to decide if this language client
   1640   ;; should manage a particular buffer. The function will be passed
   1641   ;; the file name and major mode to inform the decision. Setting
   1642   ;; `activation-fn' will override `major-modes', if
   1643   ;; present.
   1644   activation-fn
   1645   ;; Break the tie when major-mode is supported by multiple clients.
   1646   (priority 0)
   1647   ;; Unique identifier for representing the client object.
   1648   server-id
   1649   ;; defines whether the client supports multi root workspaces.
   1650   multi-root
   1651   ;; Initialization options or a function that returns initialization options.
   1652   initialization-options
   1653   ;; `semantic-tokens-faces-overrides’ is a plist that can be used to extend, or
   1654   ;; completely replace, the faces used for semantic highlighting on a
   1655   ;; client-by-client basis.
   1656   ;;
   1657   ;; It recognizes four members, all of which are optional: `:types’ and
   1658   ;; `:modifiers’, respectively, should be face definition lists akin to
   1659   ;; `:lsp-semantic-token-faces’. If specified, each of these face lists will be
   1660   ;; merged with the default face definition list.
   1661   ;;
   1662   ;; Alternatively, if the plist members `:discard-default-types’ or
   1663   ;; `:discard-default-modifiers' are non-nil, the default `:type' or `:modifiers'
   1664   ;; face definitions will be replaced entirely by their respective overrides.
   1665   ;;
   1666   ;; For example, setting `:semantic-tokens-faces-overrides' to
   1667   ;; `(:types (("macro" . font-lock-keyword-face)))' will remap "macro" tokens from
   1668   ;; their default face `lsp-face-semhl-macro' to `font-lock-keyword-face'.
   1669   ;;
   1670   ;; `(:types (("macro" . font-lock-keyword-face) ("not-quite-a-macro" . some-face)))'
   1671   ;; will also remap "macro", but on top of that associate the fictional token type
   1672   ;; "not-quite-a-macro" with the face named `some-face'.
   1673   ;;
   1674   ;; `(:types (("macro" . font-lock-keyword-face))
   1675   ;;   :modifiers (("declaration" . lsp-face-semhl-interface))
   1676   ;;   :discard-default-types t
   1677   ;;   :discard-default-modifiers t)'
   1678   ;; will discard all default face definitions, hence leaving the client with
   1679   ;; only one token type "macro", mapped to `font-lock-keyword-face', and one
   1680   ;; modifier type "declaration", mapped to `lsp-face-semhl-interface'.
   1681   semantic-tokens-faces-overrides
   1682   ;; Provides support for registering LSP Server specific capabilities.
   1683   custom-capabilities
   1684   ;; Function which returns the folders that are considered to be not projects but library files.
   1685   ;; The function accepts one parameter currently active workspace.
   1686   ;; See: https://github.com/emacs-lsp/lsp-mode/issues/225.
   1687   library-folders-fn
   1688   ;; function which will be called when opening file in the workspace to perform
   1689   ;; client specific initialization. The function accepts one parameter
   1690   ;; currently active workspace.
   1691   before-file-open-fn
   1692   ;; Function which will be called right after a workspace has been initialized.
   1693   initialized-fn
   1694   ;; ‘remote?’ indicate whether the client can be used for LSP server over TRAMP.
   1695   (remote? nil)
   1696 
   1697   ;; ‘completion-in-comments?’ t if the client supports completion in comments.
   1698   (completion-in-comments? nil)
   1699 
   1700   ;; ‘path->uri-fn’ the function to use for path->uri conversion for the client.
   1701   (path->uri-fn nil)
   1702 
   1703   ;; ‘uri->path-fn’ the function to use for uri->path conversion for the client.
   1704   (uri->path-fn nil)
   1705   ;; Function that returns an environment structure that will be used
   1706   ;; to set some environment variables when starting the language
   1707   ;; server process. These environment variables enable some
   1708   ;; additional features in the language server. The environment
   1709   ;; structure is an alist of the form (KEY . VALUE), where KEY is a
   1710   ;; string (regularly in all caps), and VALUE may be a string, a
   1711   ;; boolean, or a sequence of strings.
   1712   environment-fn
   1713 
   1714   ;; ‘after-open-fn’ workspace after open specific hooks.
   1715   (after-open-fn nil)
   1716 
   1717   ;; ‘async-request-handlers’ is a hash table mapping request method names
   1718   ;; (strings) to functions handling the respective requests that may take
   1719   ;; time to finish.  Upon receiving a request, ‘lsp-mode’ will call the
   1720   ;; associated handler function passing three arguments, the ‘lsp--workspace’
   1721   ;; object, the deserialized request parameters and the callback which accept
   1722   ;; result as its parameter.
   1723   (async-request-handlers (make-hash-table :test 'equal))
   1724   download-server-fn
   1725   download-in-progress?
   1726   buffers
   1727   synchronize-sections)
   1728 
   1729 (defun lsp-clients-executable-find (find-command &rest args)
   1730   "Finds an executable by invoking a search command.
   1731 
   1732 FIND-COMMAND is the executable finder that searches for the
   1733 actual language server executable. ARGS is a list of arguments to
   1734 give to FIND-COMMAND to find the language server.  Returns the
   1735 output of FIND-COMMAND if it exits successfully, nil otherwise.
   1736 
   1737 Typical uses include finding an executable by invoking `find' in
   1738 a project, finding LLVM commands on macOS with `xcrun', or
   1739 looking up project-specific language servers for projects written
   1740 in the various dynamic languages, e.g. `nvm', `pyenv' and `rbenv'
   1741 etc."
   1742   (when-let* ((find-command-path (executable-find find-command))
   1743               (executable-path
   1744                (with-temp-buffer
   1745                  (when (zerop (apply 'call-process find-command-path nil t nil args))
   1746                    (buffer-substring-no-properties (point-min) (point-max))))))
   1747     (string-trim executable-path)))
   1748 
   1749 (defvar lsp--already-widened nil)
   1750 
   1751 (defmacro lsp-save-restriction-and-excursion (&rest form)
   1752   (declare (indent 0) (debug t))
   1753   `(if lsp--already-widened
   1754        (save-excursion ,@form)
   1755      (-let [lsp--already-widened t]
   1756        (save-restriction
   1757          (widen)
   1758          (save-excursion ,@form)))))
   1759 
   1760 ;; from http://emacs.stackexchange.com/questions/8082/how-to-get-buffer-position-given-line-number-and-column-number
   1761 (defun lsp--line-character-to-point (line character)
   1762   "Return the point for character CHARACTER on line LINE."
   1763   (or (lsp-virtual-buffer-call :line/character->point line character)
   1764       (let ((inhibit-field-text-motion t))
   1765         (lsp-save-restriction-and-excursion
   1766           (goto-char (point-min))
   1767           (forward-line line)
   1768           ;; server may send character position beyond the current line and we
   1769           ;; should fallback to line end.
   1770           (-let [line-end (line-end-position)]
   1771             (if (> character (- line-end (point)))
   1772                 line-end
   1773               (forward-char character)
   1774               (point)))))))
   1775 
   1776 (lsp-defun lsp--position-to-point ((&Position :line :character))
   1777   "Convert `Position' object in PARAMS to a point."
   1778   (lsp--line-character-to-point line character))
   1779 
   1780 (lsp-defun lsp--range-to-region ((&RangeToPoint :start :end))
   1781   (cons start end))
   1782 
   1783 (lsp-defun lsp--range-text ((&RangeToPoint :start :end))
   1784   (buffer-substring start end))
   1785 
   1786 (lsp-defun lsp--find-wrapping-range ((&SelectionRange :parent? :range (&RangeToPoint :start :end)))
   1787   (cond
   1788    ((and
   1789      (region-active-p)
   1790      (<= start (region-beginning) end)
   1791      (<= start (region-end) end)
   1792      (or (not (= start (region-beginning)))
   1793          (not (= end (region-end)))))
   1794     (cons start end))
   1795    ((and (<= start (point) end)
   1796          (not (region-active-p)))
   1797     (cons start end))
   1798    (parent? (lsp--find-wrapping-range parent?))))
   1799 
   1800 (defun lsp--get-selection-range ()
   1801   (or
   1802    (-when-let ((cache . cache-tick) lsp--document-selection-range-cache)
   1803      (when (= cache-tick (buffer-modified-tick)) cache))
   1804    (let ((response (cl-first
   1805                     (lsp-request
   1806                      "textDocument/selectionRange"
   1807                      (list :textDocument (lsp--text-document-identifier)
   1808                            :positions (vector (lsp--cur-position)))))))
   1809      (setq lsp--document-selection-range-cache
   1810            (cons response (buffer-modified-tick)))
   1811      response)))
   1812 
   1813 (defun lsp-extend-selection ()
   1814   "Extend selection."
   1815   (interactive)
   1816   (unless (lsp-feature? "textDocument/selectionRange")
   1817     (signal 'lsp-capability-not-supported (list "selectionRangeProvider")))
   1818   (-when-let ((start . end) (lsp--find-wrapping-range (lsp--get-selection-range)))
   1819     (goto-char start)
   1820     (set-mark (point))
   1821     (goto-char end)
   1822     (exchange-point-and-mark)))
   1823 
   1824 (defun lsp-warn (message &rest args)
   1825   "Display a warning message made from (`format-message' MESSAGE ARGS...).
   1826 This is equivalent to `display-warning', using `lsp-mode' as the type and
   1827 `:warning' as the level."
   1828   (display-warning 'lsp-mode (apply #'format-message message args)))
   1829 
   1830 (defun lsp--get-uri-handler (scheme)
   1831   "Get uri handler for SCHEME in the current workspace."
   1832   (--some (gethash scheme (lsp--client-uri-handlers (lsp--workspace-client it)))
   1833           (or (lsp-workspaces) (lsp--session-workspaces (lsp-session)))))
   1834 
   1835 (defun lsp--fix-path-casing (path)
   1836   "On windows, downcases path because the windows file system is
   1837 case-insensitive.
   1838 
   1839 On other systems, returns path without change."
   1840   (if (eq system-type 'windows-nt) (downcase path) path))
   1841 
   1842 (defun lsp--uri-to-path (uri)
   1843   "Convert URI to a file path."
   1844   (if-let ((fn (->> (lsp-workspaces)
   1845                     (-keep (-compose #'lsp--client-uri->path-fn #'lsp--workspace-client))
   1846                     (cl-first))))
   1847       (funcall fn uri)
   1848     (lsp--uri-to-path-1 uri)))
   1849 
   1850 (defun lsp-remap-path-if-needed (file-name)
   1851   (-if-let ((virtual-buffer &as &plist :buffer) (gethash file-name lsp--virtual-buffer-mappings))
   1852       (propertize (buffer-local-value 'buffer-file-name buffer)
   1853                   'lsp-virtual-buffer virtual-buffer)
   1854     file-name))
   1855 
   1856 (defun lsp--uri-to-path-1 (uri)
   1857   "Convert URI to a file path."
   1858   (let* ((url (url-generic-parse-url (url-unhex-string uri)))
   1859          (type (url-type url))
   1860          (target (url-target url))
   1861          (file
   1862           (concat (decode-coding-string (url-filename url)
   1863                                         (or locale-coding-system 'utf-8))
   1864                   (when (and target
   1865                              (not (s-match
   1866                                    (rx "#" (group (1+ num)) (or "," "#")
   1867                                        (group (1+ num))
   1868                                        string-end)
   1869                                    uri)))
   1870                     (concat "#" target))))
   1871          (file-name (if (and type (not (string= type "file")))
   1872                         (if-let ((handler (lsp--get-uri-handler type)))
   1873                             (funcall handler uri)
   1874                           uri)
   1875                       ;; `url-generic-parse-url' is buggy on windows:
   1876                       ;; https://github.com/emacs-lsp/lsp-mode/pull/265
   1877                       (or (and (eq system-type 'windows-nt)
   1878                                (eq (elt file 0) ?\/)
   1879                                (substring file 1))
   1880                           file))))
   1881     (->> file-name
   1882          (concat (-some #'lsp--workspace-host-root (lsp-workspaces)))
   1883          (lsp-remap-path-if-needed))))
   1884 
   1885 (defun lsp--buffer-uri ()
   1886   "Return URI of the current buffer."
   1887   (or lsp-buffer-uri
   1888       (plist-get lsp--virtual-buffer :buffer-uri)
   1889       (lsp--path-to-uri
   1890        (or (buffer-file-name) (buffer-file-name (buffer-base-buffer))))))
   1891 
   1892 (defun lsp-register-client-capabilities (&rest _args)
   1893   "Implemented only to make `company-lsp' happy.
   1894 DELETE when `lsp-mode.el' is deleted.")
   1895 
   1896 (defconst lsp--url-path-allowed-chars
   1897   (url--allowed-chars (append '(?/) url-unreserved-chars))
   1898   "`url-unreserved-chars' with additional delim ?/.
   1899 This set of allowed chars is enough for hexifying local file paths.")
   1900 
   1901 (defun lsp--path-to-uri-1 (path)
   1902   (concat lsp--uri-file-prefix
   1903           (--> path
   1904             (expand-file-name it)
   1905             (or (file-remote-p it 'localname t) it)
   1906             (url-hexify-string it lsp--url-path-allowed-chars))))
   1907 
   1908 (defun lsp--path-to-uri (path)
   1909   "Convert PATH to a uri."
   1910   (if-let ((uri-fn (->> (lsp-workspaces)
   1911                         (-keep (-compose #'lsp--client-path->uri-fn #'lsp--workspace-client))
   1912                         (cl-first))))
   1913       (funcall uri-fn path)
   1914     (lsp--path-to-uri-1 path)))
   1915 
   1916 (defun lsp--string-match-any (regex-list str)
   1917   "Return the first regex, if any, within REGEX-LIST matching STR."
   1918   (--first (string-match it str) regex-list))
   1919 
   1920 (cl-defstruct lsp-watch
   1921   (descriptors (make-hash-table :test 'equal))
   1922   root-directory)
   1923 
   1924 (defun lsp--folder-watch-callback (event callback watch ignored-files ignored-directories)
   1925   (let ((file-name (cl-third event))
   1926         (event-type (cl-second event)))
   1927     (cond
   1928      ((and (file-directory-p file-name)
   1929            (equal 'created event-type)
   1930            (not (lsp--string-match-any ignored-directories file-name)))
   1931 
   1932       (lsp-watch-root-folder (file-truename file-name) callback ignored-files ignored-directories watch)
   1933 
   1934       ;; process the files that are already present in
   1935       ;; the directory.
   1936       (->> (directory-files-recursively file-name ".*" t)
   1937            (seq-do (lambda (f)
   1938                      (unless (file-directory-p f)
   1939                        (funcall callback (list nil 'created f)))))))
   1940      ((and (memq event-type '(created deleted changed))
   1941            (not (file-directory-p file-name))
   1942            (not (lsp--string-match-any ignored-files file-name)))
   1943       (funcall callback event))
   1944      ((and (memq event-type '(renamed))
   1945            (not (file-directory-p file-name))
   1946            (not (lsp--string-match-any ignored-files file-name)))
   1947       (funcall callback `(,(cl-first event) deleted ,(cl-third event)))
   1948       (funcall callback `(,(cl-first event) created ,(cl-fourth event)))))))
   1949 
   1950 (defun lsp--ask-about-watching-big-repo (number-of-directories dir)
   1951   "Ask the user if they want to watch NUMBER-OF-DIRECTORIES from a repository DIR.
   1952 This is useful when there is a lot of files in a repository, as
   1953 that may slow Emacs down. Returns t if the user wants to watch
   1954 the entire repository, nil otherwise."
   1955   (prog1
   1956       (yes-or-no-p
   1957        (format
   1958         "Watching all the files in %s would require adding watches to %s directories, so watching the repo may slow Emacs down.
   1959 Do you want to watch all files in %s? "
   1960         dir
   1961         number-of-directories
   1962         dir))
   1963     (lsp--info
   1964      (concat "You can configure this warning with the `lsp-enable-file-watchers' "
   1965              "and `lsp-file-watch-threshold' variables"))))
   1966 
   1967 
   1968 (defun lsp--path-is-watchable-directory (path dir ignored-directories)
   1969   "Figure out whether PATH (inside of DIR) is meant to have a file watcher set.
   1970 IGNORED-DIRECTORIES is a list of regexes to filter out directories we don't
   1971 want to watch."
   1972   (let
   1973       ((full-path (f-join dir path)))
   1974     (and (file-accessible-directory-p full-path)
   1975          (not (equal path "."))
   1976          (not (equal path ".."))
   1977          (not (lsp--string-match-any ignored-directories full-path)))))
   1978 
   1979 
   1980 (defun lsp--all-watchable-directories (dir ignored-directories)
   1981   "Traverse DIR recursively returning a list of paths that should have watchers.
   1982 IGNORED-DIRECTORIES will be used for exclusions"
   1983   (let* ((dir (if (f-symlink? dir)
   1984                   (file-truename dir)
   1985                 dir)))
   1986     (apply #'nconc
   1987            ;; the directory itself is assumed to be part of the set
   1988            (list dir)
   1989            ;; collect all subdirectories that are watchable
   1990            (-map
   1991             (lambda (path) (lsp--all-watchable-directories (f-join dir path) ignored-directories))
   1992             ;; but only look at subdirectories that are watchable
   1993             (-filter (lambda (path) (lsp--path-is-watchable-directory path dir ignored-directories))
   1994                      (directory-files dir))))))
   1995 
   1996 (defun lsp-watch-root-folder (dir callback ignored-files ignored-directories &optional watch warn-big-repo?)
   1997   "Create recursive file notification watch in DIR.
   1998 CALLBACK will be called when there are changes in any of
   1999 the monitored files. WATCHES is a hash table directory->file
   2000 notification handle which contains all of the watch that
   2001 already have been created. Watches will not be created for
   2002 any directory that matches any regex in IGNORED-DIRECTORIES.
   2003 Watches will not be created for any file that matches any
   2004 regex in IGNORED-FILES."
   2005   (let* ((dir (if (f-symlink? dir)
   2006                   (file-truename dir)
   2007                 dir))
   2008          (watch (or watch (make-lsp-watch :root-directory dir)))
   2009          (dirs-to-watch (lsp--all-watchable-directories dir ignored-directories)))
   2010     (lsp-log "Creating watchers for following %s folders:\n  %s"
   2011              (length dirs-to-watch)
   2012              (s-join "\n  " dirs-to-watch))
   2013     (when (or
   2014            (not warn-big-repo?)
   2015            (not lsp-file-watch-threshold)
   2016            (let ((number-of-directories (length dirs-to-watch)))
   2017              (or
   2018               (< number-of-directories lsp-file-watch-threshold)
   2019               (condition-case nil
   2020                   (lsp--ask-about-watching-big-repo number-of-directories dir)
   2021                 (quit)))))
   2022       (dolist (current-dir dirs-to-watch)
   2023         (condition-case err
   2024             (progn
   2025               (puthash
   2026                current-dir
   2027                (file-notify-add-watch current-dir
   2028                                       '(change)
   2029                                       (lambda (event)
   2030                                         (lsp--folder-watch-callback event callback watch ignored-files ignored-directories)))
   2031                (lsp-watch-descriptors watch)))
   2032           (error (lsp-log "Failed to create a watch for %s: message" (error-message-string err)))
   2033           (file-missing (lsp-log "Failed to create a watch for %s: message" (error-message-string err))))))
   2034     watch))
   2035 
   2036 (defun lsp-kill-watch (watch)
   2037   "Delete WATCH."
   2038   (-> watch lsp-watch-descriptors hash-table-values (-each #'file-notify-rm-watch))
   2039   (ht-clear! (lsp-watch-descriptors watch)))
   2040 
   2041 (defun lsp-json-bool (val)
   2042   "Convert VAL to JSON boolean."
   2043   (if val t :json-false))
   2044 
   2045 (defmacro with-lsp-workspace (workspace &rest body)
   2046   "Helper macro for invoking BODY in WORKSPACE context."
   2047   (declare (debug (form body))
   2048            (indent 1))
   2049   `(let ((lsp--cur-workspace ,workspace)) ,@body))
   2050 
   2051 (defmacro with-lsp-workspaces (workspaces &rest body)
   2052   "Helper macro for invoking BODY against multiple WORKSPACES."
   2053   (declare (debug (form body))
   2054            (indent 1))
   2055   `(let ((lsp--buffer-workspaces ,workspaces)) ,@body))
   2056 
   2057 
   2058 
   2059 (defmacro lsp-consistency-check (package)
   2060   `(defconst ,(intern (concat (symbol-name package)
   2061                               "-plist-value-when-compiled"))
   2062      (eval-when-compile lsp-use-plists)))
   2063 
   2064 
   2065 ;; loading code-workspace files
   2066 
   2067 ;;;###autoload
   2068 (defun lsp-load-vscode-workspace (file)
   2069   "Load vscode workspace from FILE"
   2070   (interactive "fSelect file to import: ")
   2071   (mapc #'lsp-workspace-folders-remove (lsp-session-folders (lsp-session)))
   2072 
   2073   (let ((dir (f-dirname file)))
   2074     (->> file
   2075          (json-read-file)
   2076          (alist-get 'folders)
   2077          (-map (-lambda ((&alist 'path))
   2078                  (lsp-workspace-folders-add (expand-file-name path dir)))))))
   2079 
   2080 ;;;###autoload
   2081 (defun lsp-save-vscode-workspace (file)
   2082   "Save vscode workspace to FILE"
   2083   (interactive "FSelect file to save to: ")
   2084 
   2085   (let ((json-encoding-pretty-print t))
   2086     (f-write-text (json-encode
   2087                    `((folders . ,(->> (lsp-session)
   2088                                       (lsp-session-folders)
   2089                                       (--map `((path . ,it)))))))
   2090                   'utf-8
   2091                   file)))
   2092 
   2093 
   2094 (defmacro lsp-foreach-workspace (&rest body)
   2095   "Execute BODY for each of the current workspaces."
   2096   (declare (debug (form body)))
   2097   `(--map (with-lsp-workspace it ,@body) (lsp-workspaces)))
   2098 
   2099 (defmacro when-lsp-workspace (workspace &rest body)
   2100   "Helper macro for invoking BODY in WORKSPACE context if present."
   2101   (declare (debug (form body))
   2102            (indent 1))
   2103   `(when-let ((lsp--cur-workspace ,workspace)) ,@body))
   2104 
   2105 (lsp-defun lsp--window-show-quick-pick (_workspace (&ShowQuickPickParams :place-holder :can-pick-many :items))
   2106   (if-let* ((selectfunc (if can-pick-many #'completing-read-multiple #'completing-read))
   2107             (itemLabels (seq-map (-lambda ((item &as &QuickPickItem :label)) (format "%s" label))
   2108                                  items))
   2109             (result (funcall-interactively
   2110                      selectfunc
   2111                      (format "%s%s " place-holder (if can-pick-many " (* for all)" "")) itemLabels))
   2112             (choices (if (listp result)
   2113                          (if (equal result '("*"))
   2114                              itemLabels
   2115                            result)
   2116                        (list result))))
   2117       (vconcat (seq-filter #'identity (seq-map (-lambda ((item &as &QuickPickItem :label :user-data))
   2118                                                  (if (member label choices)
   2119                                                      (lsp-make-quick-pick-item :label label :picked t :user-data user-data)
   2120                                                    nil))
   2121                                                items)))))
   2122 
   2123 (lsp-defun lsp--window-show-input-box (_workspace (&ShowInputBoxParams :prompt :value?))
   2124   (read-string (format "%s: " prompt) (or value? "")))
   2125 
   2126 (lsp-defun lsp--window-show-message (_workspace (&ShowMessageRequestParams :message :type))
   2127   "Send the server's messages to log.
   2128 PARAMS - the data sent from _WORKSPACE."
   2129   (funcall (cl-case type
   2130              (1 'lsp--error)
   2131              (2 'lsp--warn)
   2132              (t 'lsp--info))
   2133            "%s"
   2134            message))
   2135 
   2136 (lsp-defun lsp--window-log-message (workspace (&ShowMessageRequestParams :message :type))
   2137   "Send the server's messages to log.
   2138 PARAMS - the data sent from WORKSPACE."
   2139   (ignore
   2140    (let ((client (lsp--workspace-client workspace)))
   2141      (when (or (not client)
   2142                (cl-notany (-rpartial #'string-match-p message)
   2143                           (lsp--client-ignore-messages client)))
   2144        (lsp-log "%s" (lsp--propertize message type))))))
   2145 
   2146 (lsp-defun lsp--window-log-message-request ((&ShowMessageRequestParams :message :type :actions?))
   2147   "Display a message request to user sending the user selection back to server."
   2148   (let* ((message (lsp--propertize message type))
   2149          (choices (seq-map #'lsp:message-action-item-title actions?)))
   2150     (if choices
   2151         (completing-read (concat message " ") (seq-into choices 'list) nil t)
   2152       (lsp-log message))))
   2153 
   2154 (lsp-defun lsp--window-show-document ((&ShowDocumentParams :uri :selection?))
   2155   "Show document URI in a buffer and go to SELECTION if any."
   2156   (let ((path (lsp--uri-to-path uri)))
   2157     (when (f-exists? path)
   2158       (with-current-buffer (find-file path)
   2159         (when selection?
   2160           (goto-char (lsp--position-to-point (lsp:range-start selection?))))
   2161         t))))
   2162 
   2163 (defcustom lsp-progress-prefix "⌛ "
   2164   "Progress prefix."
   2165   :group 'lsp-mode
   2166   :type 'string
   2167   :package-version '(lsp-mode . "8.0.0"))
   2168 
   2169 (defcustom lsp-progress-function #'lsp-on-progress-modeline
   2170   "Function for handling the progress notifications."
   2171   :group 'lsp-mode
   2172   :type '(choice
   2173           (const :tag "Use modeline" lsp-on-progress-modeline)
   2174           (const :tag "Legacy(uses either `progress-reporter' or `spinner' based on `lsp-progress-via-spinner')"
   2175                  lsp-on-progress-legacy)
   2176           (const :tag "Ignore" ignore)
   2177           (function :tag "Other function"))
   2178   :package-version '(lsp-mode . "8.0.0"))
   2179 
   2180 (defcustom lsp-request-while-no-input-may-block nil
   2181   "Have `lsp-request-while-no-input` block unless `non-essential` is t."
   2182   :group 'lsp-mode
   2183   :type 'boolean)
   2184 
   2185 (defun lsp--progress-status ()
   2186   "Returns the status of the progress for the current workspaces."
   2187   (-let ((progress-status
   2188           (s-join
   2189            "|"
   2190            (-keep
   2191             (lambda (workspace)
   2192               (let ((tokens (lsp--workspace-work-done-tokens workspace)))
   2193                 (unless (ht-empty? tokens)
   2194                   (mapconcat
   2195                    (-lambda ((&WorkDoneProgressBegin :message? :title :percentage?))
   2196                      (concat (if percentage?
   2197                                  (if (numberp percentage?)
   2198                                      (format "%.0f%%%% " percentage?)
   2199                                    (format "%s%%%% " percentage?))
   2200                                "")
   2201                              (or message? title)))
   2202                    (ht-values tokens)
   2203                    "|"))))
   2204             (lsp-workspaces)))))
   2205     (unless (s-blank? progress-status)
   2206       (concat lsp-progress-prefix progress-status " "))))
   2207 
   2208 (lsp-defun lsp-on-progress-modeline (workspace (&ProgressParams :token :value
   2209                                                                 (value &as &WorkDoneProgress :kind)))
   2210   "PARAMS contains the progress data.
   2211 WORKSPACE is the workspace that contains the progress token."
   2212   (add-to-list 'global-mode-string '(t (:eval (lsp--progress-status))))
   2213   (pcase kind
   2214     ("begin" (lsp-workspace-set-work-done-token token value workspace))
   2215     ("report" (lsp-workspace-set-work-done-token token value workspace))
   2216     ("end" (lsp-workspace-rem-work-done-token token workspace)))
   2217   (force-mode-line-update))
   2218 
   2219 (lsp-defun lsp-on-progress-legacy (workspace (&ProgressParams :token :value
   2220                                                               (value &as &WorkDoneProgress :kind)))
   2221   "PARAMS contains the progress data.
   2222 WORKSPACE is the workspace that contains the progress token."
   2223   (pcase kind
   2224     ("begin"
   2225      (-let* (((&WorkDoneProgressBegin :title :percentage?) value)
   2226              (reporter
   2227               (if lsp-progress-via-spinner
   2228                   (let* ((spinner-strings (alist-get (lsp-progress-spinner-type) spinner-types))
   2229                          ;; Set message as a tooltip for the spinner strings
   2230                          (propertized-strings
   2231                           (seq-map (lambda (string) (propertize string 'help-echo title))
   2232                                    spinner-strings))
   2233                          (spinner-type (vconcat propertized-strings)))
   2234                     ;; The progress relates to the server as a whole,
   2235                     ;; display it on all buffers.
   2236                     (mapcar (lambda (buffer)
   2237                               (lsp-with-current-buffer buffer
   2238                                 (spinner-start spinner-type))
   2239                               buffer)
   2240                             (lsp--workspace-buffers workspace)))
   2241                 (if percentage?
   2242                     (make-progress-reporter title 0 100 percentage?)
   2243                   ;; No percentage, just progress
   2244                   (make-progress-reporter title nil nil)))))
   2245        (lsp-workspace-set-work-done-token token reporter workspace)))
   2246     ("report"
   2247      (when-let ((reporter (lsp-workspace-get-work-done-token token workspace)))
   2248        (unless lsp-progress-via-spinner
   2249          (progress-reporter-update reporter (lsp:work-done-progress-report-percentage? value)))))
   2250 
   2251     ("end"
   2252      (when-let ((reporter (lsp-workspace-get-work-done-token token workspace)))
   2253        (if lsp-progress-via-spinner
   2254            (mapc (lambda (buffer)
   2255                    (when (lsp-buffer-live-p buffer)
   2256                      (lsp-with-current-buffer buffer
   2257                        (spinner-stop))))
   2258                  reporter)
   2259          (progress-reporter-done reporter))
   2260        (lsp-workspace-rem-work-done-token token workspace)))))
   2261 
   2262 
   2263 ;; diagnostics
   2264 
   2265 (defvar lsp-diagnostic-filter nil
   2266   "A a function which will be called with
   2267   `&PublishDiagnosticsParams' and `workspace' which can be used
   2268   to filter out the diagnostics. The function should return
   2269   `&PublishDiagnosticsParams'.
   2270 
   2271 Common usecase are:
   2272 1. Filter the diagnostics for a particular language server.
   2273 2. Filter out the diagnostics under specific level.")
   2274 
   2275 (defvar lsp-diagnostic-stats (ht))
   2276 
   2277 (defun lsp-diagnostics (&optional current-workspace?)
   2278   "Return the diagnostics from all workspaces."
   2279   (or (pcase (if current-workspace?
   2280                  (lsp-workspaces)
   2281                (lsp--session-workspaces (lsp-session)))
   2282         (`() ())
   2283         (`(,workspace) (lsp--workspace-diagnostics workspace))
   2284         (`,workspaces (let ((result (make-hash-table :test 'equal)))
   2285                         (mapc (lambda (workspace)
   2286                                 (->> workspace
   2287                                      (lsp--workspace-diagnostics)
   2288                                      (maphash (lambda (file-name diagnostics)
   2289                                                 (puthash file-name
   2290                                                          (append (gethash file-name result) diagnostics)
   2291                                                          result)))))
   2292                               workspaces)
   2293                         result)))
   2294       (ht)))
   2295 
   2296 (defun lsp-diagnostics-stats-for (path)
   2297   "Get diagnostics statistics for PATH.
   2298 The result format is vector [_ errors warnings infos hints] or nil."
   2299   (gethash (lsp--fix-path-casing path) lsp-diagnostic-stats))
   2300 
   2301 (defun lsp-diagnostics--update-path (path new-stats)
   2302   (let ((new-stats (copy-sequence new-stats))
   2303         (path (lsp--fix-path-casing (directory-file-name path))))
   2304     (if-let ((old-data (gethash path lsp-diagnostic-stats)))
   2305         (dotimes (idx 5)
   2306           (cl-callf + (aref old-data idx)
   2307             (aref new-stats idx)))
   2308       (puthash path new-stats lsp-diagnostic-stats))))
   2309 
   2310 (lsp-defun lsp--on-diagnostics-update-stats (workspace
   2311                                              (&PublishDiagnosticsParams :uri :diagnostics))
   2312   (let ((path (lsp--fix-path-casing (lsp--uri-to-path uri)))
   2313         (new-stats (make-vector 5 0)))
   2314     (mapc (-lambda ((&Diagnostic :severity?))
   2315             (cl-incf (aref new-stats (or severity? 1))))
   2316           diagnostics)
   2317     (when-let ((old-diags (gethash path (lsp--workspace-diagnostics workspace))))
   2318       (mapc (-lambda ((&Diagnostic :severity?))
   2319               (cl-decf (aref new-stats (or severity? 1))))
   2320             old-diags))
   2321     (lsp-diagnostics--update-path path new-stats)
   2322     (while (not (string= path (setf path (file-name-directory
   2323                                           (directory-file-name path)))))
   2324       (lsp-diagnostics--update-path path new-stats))))
   2325 
   2326 (defun lsp--on-diagnostics (workspace params)
   2327   "Callback for textDocument/publishDiagnostics.
   2328 interface PublishDiagnosticsParams {
   2329     uri: string;
   2330     diagnostics: Diagnostic[];
   2331 }
   2332 PARAMS contains the diagnostics data.
   2333 WORKSPACE is the workspace that contains the diagnostics."
   2334   (when lsp-diagnostic-filter
   2335     (setf params (funcall lsp-diagnostic-filter params workspace)))
   2336 
   2337   (lsp--on-diagnostics-update-stats workspace params)
   2338 
   2339   (-let* (((&PublishDiagnosticsParams :uri :diagnostics) params)
   2340           (lsp--virtual-buffer-mappings (ht))
   2341           (file (lsp--fix-path-casing (lsp--uri-to-path uri)))
   2342           (workspace-diagnostics (lsp--workspace-diagnostics workspace)))
   2343 
   2344     (if (seq-empty-p diagnostics)
   2345         (remhash file workspace-diagnostics)
   2346       (puthash file (append diagnostics nil) workspace-diagnostics))
   2347 
   2348     (run-hooks 'lsp-diagnostics-updated-hook)))
   2349 
   2350 (defun lsp-diagnostics--workspace-cleanup (workspace)
   2351   (->> workspace
   2352        (lsp--workspace-diagnostics)
   2353        (maphash (lambda (key _)
   2354                   (lsp--on-diagnostics-update-stats
   2355                    workspace
   2356                    (lsp-make-publish-diagnostics-params
   2357                     :uri (lsp--path-to-uri key)
   2358                     :diagnostics [])))))
   2359   (clrhash (lsp--workspace-diagnostics workspace)))
   2360 
   2361 
   2362 
   2363 ;; textDocument/foldingRange support
   2364 
   2365 (cl-defstruct lsp--folding-range beg end kind children)
   2366 
   2367 (defvar-local lsp--cached-folding-ranges nil)
   2368 (defvar-local lsp--cached-nested-folding-ranges nil)
   2369 
   2370 (defun lsp--folding-range-width (range)
   2371   (- (lsp--folding-range-end range)
   2372      (lsp--folding-range-beg range)))
   2373 
   2374 (defun lsp--get-folding-ranges ()
   2375   "Get the folding ranges for the current buffer."
   2376   (unless (eq (buffer-chars-modified-tick) (car lsp--cached-folding-ranges))
   2377     (let* ((ranges (lsp-request "textDocument/foldingRange"
   2378                                 `(:textDocument ,(lsp--text-document-identifier))))
   2379            (sorted-line-col-pairs (->> ranges
   2380                                        (cl-mapcan (-lambda ((&FoldingRange :start-line
   2381                                                                            :start-character?
   2382                                                                            :end-line
   2383                                                                            :end-character?))
   2384                                                     (list (cons start-line start-character?)
   2385                                                           (cons end-line end-character?))))
   2386                                        (-sort #'lsp--line-col-comparator)))
   2387            (line-col-to-point-map (lsp--convert-line-col-to-points-batch
   2388                                    sorted-line-col-pairs)))
   2389       (setq lsp--cached-folding-ranges
   2390             (cons (buffer-chars-modified-tick)
   2391                   (--> ranges
   2392                     (seq-map (-lambda ((range &as
   2393                                               &FoldingRange :start-line
   2394                                               :start-character?
   2395                                               :end-line
   2396                                               :end-character?
   2397                                               :kind?))
   2398                                (make-lsp--folding-range
   2399                                 :beg (ht-get line-col-to-point-map
   2400                                              (cons start-line start-character?))
   2401                                 :end (ht-get line-col-to-point-map
   2402                                              (cons end-line end-character?))
   2403                                 :kind kind?))
   2404                              it)
   2405                     (seq-filter (lambda (folding-range)
   2406                                   (< (lsp--folding-range-beg folding-range)
   2407                                      (lsp--folding-range-end folding-range)))
   2408                                 it)
   2409                     (seq-into it 'list)
   2410                     (delete-dups it))))))
   2411   (cdr lsp--cached-folding-ranges))
   2412 
   2413 (defun lsp--get-nested-folding-ranges ()
   2414   "Get a list of nested folding ranges for the current buffer."
   2415   (-let [(tick . _) lsp--cached-folding-ranges]
   2416     (if (and (eq tick (buffer-chars-modified-tick))
   2417              lsp--cached-nested-folding-ranges)
   2418         lsp--cached-nested-folding-ranges
   2419       (setq lsp--cached-nested-folding-ranges
   2420             (lsp--folding-range-build-trees (lsp--get-folding-ranges))))))
   2421 
   2422 (defun lsp--folding-range-build-trees (ranges)
   2423   (setq ranges (seq-sort #'lsp--range-before-p ranges))
   2424   (let* ((dummy-node (make-lsp--folding-range
   2425                       :beg most-negative-fixnum
   2426                       :end most-positive-fixnum))
   2427          (stack (list dummy-node)))
   2428     (dolist (range ranges)
   2429       (while (not (lsp--range-inside-p range (car stack)))
   2430         (pop stack))
   2431       (push range (lsp--folding-range-children (car stack)))
   2432       (push range stack))
   2433     (lsp--folding-range-children dummy-node)))
   2434 
   2435 (defun lsp--range-inside-p (r1 r2)
   2436   "Return non-nil if folding range R1 lies inside R2"
   2437   (and (>= (lsp--folding-range-beg r1) (lsp--folding-range-beg r2))
   2438        (<= (lsp--folding-range-end r1) (lsp--folding-range-end r2))))
   2439 
   2440 (defun lsp--range-before-p (r1 r2)
   2441   "Return non-nil if folding range R1 ends before R2"
   2442   ;; Ensure r1 comes before r2
   2443   (or (< (lsp--folding-range-beg r1)
   2444          (lsp--folding-range-beg r2))
   2445       ;; If beg(r1) == beg(r2) make sure r2 ends first
   2446       (and (= (lsp--folding-range-beg r1)
   2447               (lsp--folding-range-beg r2))
   2448            (< (lsp--folding-range-end r2)
   2449               (lsp--folding-range-end r1)))))
   2450 
   2451 (defun lsp--point-inside-range-p (point range)
   2452   "Return non-nil if POINT lies inside folding range RANGE."
   2453   (and (>= point (lsp--folding-range-beg range))
   2454        (<= point (lsp--folding-range-end range))))
   2455 
   2456 (cl-defun lsp--get-current-innermost-folding-range (&optional (point (point)))
   2457   "Return the innermost folding range POINT lies in."
   2458   (seq-reduce (lambda (innermost-range curr-range)
   2459                 (if (and (lsp--point-inside-range-p point curr-range)
   2460                          (or (null innermost-range)
   2461                              (lsp--range-inside-p curr-range innermost-range)))
   2462                     curr-range
   2463                   innermost-range))
   2464               (lsp--get-folding-ranges)
   2465               nil))
   2466 
   2467 (cl-defun lsp--get-current-outermost-folding-range (&optional (point (point)))
   2468   "Return the outermost folding range POINT lies in."
   2469   (cdr (seq-reduce (-lambda ((best-pair &as outermost-width . _) curr-range)
   2470                      (let ((curr-width (lsp--folding-range-width curr-range)))
   2471                        (if (and (lsp--point-inside-range-p point curr-range)
   2472                                 (or (null best-pair)
   2473                                     (> curr-width outermost-width)))
   2474                            (cons curr-width curr-range)
   2475                          best-pair)))
   2476                    (lsp--get-folding-ranges)
   2477                    nil)))
   2478 
   2479 (defun lsp--folding-range-at-point-bounds ()
   2480   (when (and lsp-enable-folding
   2481              (lsp-feature? "textDocument/foldingRange"))
   2482     (if-let ((range (lsp--get-current-innermost-folding-range)))
   2483         (cons (lsp--folding-range-beg range)
   2484               (lsp--folding-range-end range)))))
   2485 (put 'lsp--folding-range 'bounds-of-thing-at-point
   2486      #'lsp--folding-range-at-point-bounds)
   2487 
   2488 (defun lsp--get-nearest-folding-range (&optional backward)
   2489   (let ((point (point))
   2490         (found nil))
   2491     (while (not
   2492             (or found
   2493                 (if backward
   2494                     (<= point (point-min))
   2495                   (>= point (point-max)))))
   2496       (if backward (cl-decf point) (cl-incf point))
   2497       (setq found (lsp--get-current-innermost-folding-range point)))
   2498     found))
   2499 
   2500 (defun lsp--folding-range-at-point-forward-op (n)
   2501   (when (and lsp-enable-folding
   2502              (not (zerop n))
   2503              (lsp-feature? "textDocument/foldingRange"))
   2504     (cl-block break
   2505       (dotimes (_ (abs n))
   2506         (if-let ((range (lsp--get-nearest-folding-range (< n 0))))
   2507             (goto-char (if (< n 0)
   2508                            (lsp--folding-range-beg range)
   2509                          (lsp--folding-range-end range)))
   2510           (cl-return-from break))))))
   2511 (put 'lsp--folding-range 'forward-op
   2512      #'lsp--folding-range-at-point-forward-op)
   2513 
   2514 (defun lsp--folding-range-at-point-beginning-op ()
   2515   (goto-char (car (lsp--folding-range-at-point-bounds))))
   2516 (put 'lsp--folding-range 'beginning-op
   2517      #'lsp--folding-range-at-point-beginning-op)
   2518 
   2519 (defun lsp--folding-range-at-point-end-op ()
   2520   (goto-char (cdr (lsp--folding-range-at-point-bounds))))
   2521 (put 'lsp--folding-range 'end-op
   2522      #'lsp--folding-range-at-point-end-op)
   2523 
   2524 (defun lsp--range-at-point-bounds ()
   2525   (or (lsp--folding-range-at-point-bounds)
   2526       (when-let ((range (and
   2527                          (lsp-feature? "textDocument/hover")
   2528                          (->> (lsp--text-document-position-params)
   2529                               (lsp-request "textDocument/hover")
   2530                               (lsp:hover-range?)))))
   2531         (lsp--range-to-region range))))
   2532 
   2533 ;; A more general purpose "thing", useful for applications like focus.el
   2534 (put 'lsp--range 'bounds-of-thing-at-point
   2535      #'lsp--range-at-point-bounds)
   2536 
   2537 (defun lsp--log-io-p (method)
   2538   "Return non nil if should log for METHOD."
   2539   (and lsp-log-io
   2540        (or (not lsp-log-io-allowlist-methods)
   2541            (member method lsp-log-io-allowlist-methods))))
   2542 
   2543 
   2544 ;; toggles
   2545 
   2546 (defun lsp-toggle-trace-io ()
   2547   "Toggle client-server protocol logging."
   2548   (interactive)
   2549   (setq lsp-log-io (not lsp-log-io))
   2550   (lsp--info "Server logging %s." (if lsp-log-io "enabled" "disabled")))
   2551 
   2552 (defun lsp-toggle-signature-auto-activate ()
   2553   "Toggle signature auto activate."
   2554   (interactive)
   2555   (setq lsp-signature-auto-activate
   2556         (unless lsp-signature-auto-activate '(:on-trigger-char)))
   2557   (lsp--info "Signature autoactivate %s." (if lsp-signature-auto-activate "enabled" "disabled"))
   2558   (lsp--update-signature-help-hook))
   2559 
   2560 (defun lsp-toggle-on-type-formatting ()
   2561   "Toggle on type formatting."
   2562   (interactive)
   2563   (setq lsp-enable-on-type-formatting (not lsp-enable-on-type-formatting))
   2564   (lsp--info "On type formatting is %s." (if lsp-enable-on-type-formatting "enabled" "disabled"))
   2565   (lsp--update-on-type-formatting-hook))
   2566 
   2567 (defun lsp-toggle-symbol-highlight ()
   2568   "Toggle symbol highlighting."
   2569   (interactive)
   2570   (setq lsp-enable-symbol-highlighting (not lsp-enable-symbol-highlighting))
   2571 
   2572   (cond
   2573    ((and lsp-enable-symbol-highlighting
   2574          (lsp-feature? "textDocument/documentHighlight"))
   2575     (add-hook 'lsp-on-idle-hook #'lsp--document-highlight nil t)
   2576     (lsp--info "Symbol highlighting enabled in current buffer."))
   2577    ((not lsp-enable-symbol-highlighting)
   2578     (remove-hook 'lsp-on-idle-hook #'lsp--document-highlight t)
   2579     (lsp--remove-overlays 'lsp-highlight)
   2580     (lsp--info "Symbol highlighting disabled in current buffer."))))
   2581 
   2582 
   2583 ;; keybindings
   2584 (defvar lsp--binding-descriptions nil
   2585   "List of key binding/short description pair.")
   2586 
   2587 (defmacro lsp-define-conditional-key (keymap key def desc cond &rest bindings)
   2588   "In KEYMAP, define key sequence KEY as DEF conditionally.
   2589 This is like `define-key', except the definition disappears
   2590 whenever COND evaluates to nil.
   2591 DESC is the short-description for the binding.
   2592 BINDINGS is a list of (key def desc cond)."
   2593   (declare (indent defun)
   2594            (debug (form form form form form &rest sexp)))
   2595   (->> (cl-list* key def desc cond bindings)
   2596        (-partition 4)
   2597        (-mapcat (-lambda ((key def desc cond))
   2598                   `((define-key ,keymap ,key
   2599                       '(menu-item
   2600                         ,(format "maybe-%s" def)
   2601                         ,def
   2602                         :filter
   2603                         (lambda (item)
   2604                           (when (with-current-buffer (or (when (buffer-live-p lsp--describe-buffer)
   2605                                                            lsp--describe-buffer)
   2606                                                          (current-buffer))
   2607                                   ,cond)
   2608                             item))))
   2609                     (when (stringp ,key)
   2610                       (setq lsp--binding-descriptions
   2611                             (append lsp--binding-descriptions '(,key ,desc)))))))
   2612        macroexp-progn))
   2613 
   2614 (defvar lsp--describe-buffer nil)
   2615 
   2616 (defun lsp-describe-buffer-bindings-advice (fn buffer &optional prefix menus)
   2617   (let ((lsp--describe-buffer buffer))
   2618     (funcall fn buffer prefix menus)))
   2619 
   2620 (advice-add 'describe-buffer-bindings
   2621             :around
   2622             #'lsp-describe-buffer-bindings-advice)
   2623 
   2624 (defun lsp--prepend-prefix (mappings)
   2625   (->> mappings
   2626        (-partition 2)
   2627        (-mapcat (-lambda ((key description))
   2628                   (list (concat lsp-keymap-prefix " " key)
   2629                         description)))))
   2630 
   2631 (defvar lsp-command-map
   2632   (-doto (make-sparse-keymap)
   2633     (lsp-define-conditional-key
   2634       ;; workspaces
   2635       "wD" lsp-disconnect "disconnect" (lsp-workspaces)
   2636       "wd" lsp-describe-session "describe session" t
   2637       "wq" lsp-workspace-shutdown "shutdown server" (lsp-workspaces)
   2638       "wr" lsp-workspace-restart "restart server" (lsp-workspaces)
   2639       "ws" lsp "start server" t
   2640 
   2641       ;; formatting
   2642       "==" lsp-format-buffer "format buffer" (or (lsp-feature? "textDocument/rangeFormatting")
   2643                                                  (lsp-feature? "textDocument/formatting"))
   2644       "=r" lsp-format-region "format region" (lsp-feature? "textDocument/rangeFormatting")
   2645 
   2646       ;; folders
   2647       "Fa" lsp-workspace-folders-add "add folder" t
   2648       "Fb" lsp-workspace-blocklist-remove "un-blocklist folder" t
   2649       "Fr" lsp-workspace-folders-remove "remove folder" t
   2650 
   2651       ;; toggles
   2652       "TD" lsp-modeline-diagnostics-mode "toggle modeline diagnostics" (lsp-feature?
   2653                                                                         "textDocument/publishDiagnostics")
   2654       "TL" lsp-toggle-trace-io "toggle log io" t
   2655       "TS" lsp-ui-sideline-mode "toggle sideline" (featurep 'lsp-ui-sideline)
   2656       "TT" lsp-treemacs-sync-mode "toggle treemacs integration" (featurep 'lsp-treemacs)
   2657       "Ta" lsp-modeline-code-actions-mode "toggle modeline code actions" (lsp-feature?
   2658                                                                           "textDocument/codeAction")
   2659       "Tb" lsp-headerline-breadcrumb-mode "toggle breadcrumb" (lsp-feature?
   2660                                                                "textDocument/documentSymbol")
   2661       "Td" lsp-ui-doc-mode "toggle documentation popup" (featurep 'lsp-ui-doc)
   2662       "Tf" lsp-toggle-on-type-formatting "toggle on type formatting" (lsp-feature?
   2663                                                                       "textDocument/onTypeFormatting")
   2664       "Th" lsp-toggle-symbol-highlight "toggle highlighting" (lsp-feature? "textDocument/documentHighlight")
   2665       "Tl" lsp-lens-mode "toggle lenses" (lsp-feature? "textDocument/codeLens")
   2666       "Ts" lsp-toggle-signature-auto-activate "toggle signature" (lsp-feature? "textDocument/signatureHelp")
   2667 
   2668       ;; goto
   2669       "ga" xref-find-apropos "find symbol in workspace" (lsp-feature? "workspace/symbol")
   2670       "gd" lsp-find-declaration "find declarations" (lsp-feature? "textDocument/declaration")
   2671       "ge" lsp-treemacs-errors-list "show errors" (fboundp 'lsp-treemacs-errors-list)
   2672       "gg" lsp-find-definition "find definitions" (lsp-feature? "textDocument/definition")
   2673       "gh" lsp-treemacs-call-hierarchy "call hierarchy" (and (lsp-feature? "callHierarchy/incomingCalls")
   2674                                                              (fboundp 'lsp-treemacs-call-hierarchy))
   2675       "gi" lsp-find-implementation "find implementations" (lsp-feature? "textDocument/implementation")
   2676       "gr" lsp-find-references "find references" (lsp-feature? "textDocument/references")
   2677       "gt" lsp-find-type-definition "find type definition" (lsp-feature? "textDocument/typeDefinition")
   2678 
   2679       ;; help
   2680       "hg" lsp-ui-doc-glance "glance symbol" (and (featurep 'lsp-ui-doc)
   2681                                                   (lsp-feature? "textDocument/hover"))
   2682       "hh" lsp-describe-thing-at-point "describe symbol at point" (lsp-feature? "textDocument/hover")
   2683       "hs" lsp-signature-activate "signature help" (lsp-feature? "textDocument/signatureHelp")
   2684 
   2685       ;; refactoring
   2686       "ro" lsp-organize-imports "organize imports" (lsp-feature? "textDocument/codeAction")
   2687       "rr" lsp-rename "rename" (lsp-feature? "textDocument/rename")
   2688 
   2689       ;; actions
   2690       "aa" lsp-execute-code-action "code actions" (lsp-feature? "textDocument/codeAction")
   2691       "ah" lsp-document-highlight "highlight symbol" (lsp-feature? "textDocument/documentHighlight")
   2692       "al" lsp-avy-lens "lens" (and (bound-and-true-p lsp-lens-mode) (featurep 'avy))
   2693 
   2694       ;; peeks
   2695       "Gg" lsp-ui-peek-find-definitions "peek definitions" (and (lsp-feature? "textDocument/definition")
   2696                                                                 (fboundp 'lsp-ui-peek-find-definitions))
   2697       "Gi" lsp-ui-peek-find-implementation "peek implementations" (and
   2698                                                                    (fboundp 'lsp-ui-peek-find-implementation)
   2699                                                                    (lsp-feature? "textDocument/implementation"))
   2700       "Gr" lsp-ui-peek-find-references "peek references" (and (fboundp 'lsp-ui-peek-find-references)
   2701                                                               (lsp-feature? "textDocument/references"))
   2702       "Gs" lsp-ui-peek-find-workspace-symbol "peek workspace symbol" (and (fboundp
   2703                                                                            'lsp-ui-peek-find-workspace-symbol)
   2704                                                                           (lsp-feature? "workspace/symbol")))))
   2705 
   2706 
   2707 ;; which-key integration
   2708 
   2709 (declare-function which-key-add-major-mode-key-based-replacements "ext:which-key")
   2710 (declare-function which-key-add-key-based-replacements "ext:which-key")
   2711 
   2712 (defun lsp-enable-which-key-integration (&optional all-modes)
   2713   "Adds descriptions for `lsp-mode-map' to `which-key-mode' for the current
   2714 active `major-mode', or for all major modes when ALL-MODES is t."
   2715   (cl-flet ((which-key-fn (if all-modes
   2716                               'which-key-add-key-based-replacements
   2717                             (apply-partially 'which-key-add-major-mode-key-based-replacements major-mode))))
   2718     (apply
   2719      #'which-key-fn
   2720      (lsp--prepend-prefix
   2721       (cl-list*
   2722        ""    "lsp"
   2723        "w"   "workspaces"
   2724        "F"   "folders"
   2725        "="   "formatting"
   2726        "T"   "toggle"
   2727        "g"   "goto"
   2728        "h"   "help"
   2729        "r"   "refactor"
   2730        "a"   "code actions"
   2731        "G"   "peek"
   2732        lsp--binding-descriptions)))))
   2733 
   2734 
   2735 ;; Globbing syntax
   2736 
   2737 ;; We port VSCode's glob-to-regexp code
   2738 ;; (https://github.com/Microsoft/vscode/blob/466da1c9013c624140f6d1473b23a870abc82d44/src/vs/base/common/glob.ts)
   2739 ;; since the LSP globbing syntax seems to be the same as that of
   2740 ;; VSCode.
   2741 
   2742 (defconst lsp-globstar "**"
   2743   "Globstar pattern.")
   2744 
   2745 (defconst lsp-glob-split ?/
   2746   "The character by which we split path components in a glob
   2747 pattern.")
   2748 
   2749 (defconst lsp-path-regexp "[/\\\\]"
   2750   "Forward or backslash to be used as a path separator in
   2751 computed regexps.")
   2752 
   2753 (defconst lsp-non-path-regexp "[^/\\\\]"
   2754   "A regexp matching anything other than a slash.")
   2755 
   2756 (defconst lsp-globstar-regexp
   2757   (format "\\(?:%s\\|%s+%s\\|%s%s+\\)*?"
   2758           lsp-path-regexp
   2759           lsp-non-path-regexp lsp-path-regexp
   2760           lsp-path-regexp lsp-non-path-regexp)
   2761   "Globstar in regexp form.")
   2762 
   2763 (defun lsp-split-glob-pattern (pattern split-char)
   2764   "Split PATTERN at SPLIT-CHAR while respecting braces and brackets."
   2765   (when pattern
   2766     (let ((segments nil)
   2767           (in-braces nil)
   2768           (in-brackets nil)
   2769           (current-segment ""))
   2770       (dolist (char (string-to-list pattern))
   2771         (cl-block 'exit-point
   2772           (if (eq char split-char)
   2773               (when (and (null in-braces)
   2774                          (null in-brackets))
   2775                 (push current-segment segments)
   2776                 (setq current-segment "")
   2777                 (cl-return-from 'exit-point))
   2778             (pcase char
   2779               (?{
   2780                (setq in-braces t))
   2781               (?}
   2782                (setq in-braces nil))
   2783               (?\[
   2784                (setq in-brackets t))
   2785               (?\]
   2786                (setq in-brackets nil))))
   2787           (setq current-segment (concat current-segment
   2788                                         (char-to-string char)))))
   2789       (unless (string-empty-p current-segment)
   2790         (push current-segment segments))
   2791       (nreverse segments))))
   2792 
   2793 (defun lsp--glob-to-regexp (pattern)
   2794   "Helper function to convert a PATTERN from LSP's glob syntax to
   2795 an Elisp regexp."
   2796   (if (string-empty-p pattern)
   2797       ""
   2798     (let ((current-regexp "")
   2799           (glob-segments (lsp-split-glob-pattern pattern lsp-glob-split)))
   2800       (if (-all? (lambda (segment) (eq segment lsp-globstar))
   2801                  glob-segments)
   2802           ".*"
   2803         (let ((prev-segment-was-globstar nil))
   2804           (seq-do-indexed
   2805            (lambda (segment index)
   2806              (if (string-equal segment lsp-globstar)
   2807                  (unless prev-segment-was-globstar
   2808                    (setq current-regexp (concat current-regexp
   2809                                                 lsp-globstar-regexp))
   2810                    (setq prev-segment-was-globstar t))
   2811                (let ((in-braces nil)
   2812                      (brace-val "")
   2813                      (in-brackets nil)
   2814                      (bracket-val ""))
   2815                  (dolist (char (string-to-list segment))
   2816                    (cond
   2817                     ((and (not (char-equal char ?\}))
   2818                           in-braces)
   2819                      (setq brace-val (concat brace-val
   2820                                              (char-to-string char))))
   2821                     ((and in-brackets
   2822                           (or (not (char-equal char ?\]))
   2823                               (string-empty-p bracket-val)))
   2824                      (let ((curr (cond
   2825                                   ((char-equal char ?-)
   2826                                    "-")
   2827                                   ;; NOTE: ?\^ and ?^ are different characters
   2828                                   ((and (memq char '(?^ ?!))
   2829                                         (string-empty-p bracket-val))
   2830                                    "^")
   2831                                   ((char-equal char lsp-glob-split)
   2832                                    "")
   2833                                   (t
   2834                                    (regexp-quote (char-to-string char))))))
   2835                        (setq bracket-val (concat bracket-val curr))))
   2836                     (t
   2837                      (cl-case char
   2838                        (?{
   2839                         (setq in-braces t))
   2840                        (?\[
   2841                         (setq in-brackets t))
   2842                        (?}
   2843                         (let* ((choices (lsp-split-glob-pattern brace-val ?\,))
   2844                                (brace-regexp (concat "\\(?:"
   2845                                                      (mapconcat #'lsp--glob-to-regexp choices "\\|")
   2846                                                      "\\)")))
   2847                           (setq current-regexp (concat current-regexp
   2848                                                        brace-regexp))
   2849                           (setq in-braces nil)
   2850                           (setq brace-val "")))
   2851                        (?\]
   2852                         (setq current-regexp
   2853                               (concat current-regexp
   2854                                       "[" bracket-val "]"))
   2855                         (setq in-brackets nil)
   2856                         (setq bracket-val ""))
   2857                        (??
   2858                         (setq current-regexp
   2859                               (concat current-regexp
   2860                                       lsp-non-path-regexp)))
   2861                        (?*
   2862                         (setq current-regexp
   2863                               (concat current-regexp
   2864                                       lsp-non-path-regexp "*?")))
   2865                        (t
   2866                         (setq current-regexp
   2867                               (concat current-regexp
   2868                                       (regexp-quote (char-to-string char)))))))))
   2869                  (when (and (< index (1- (length glob-segments)))
   2870                             (or (not (string-equal (nth (1+ index) glob-segments)
   2871                                                    lsp-globstar))
   2872                                 (< (+ index 2)
   2873                                    (length glob-segments))))
   2874                    (setq current-regexp
   2875                          (concat current-regexp
   2876                                  lsp-path-regexp)))
   2877                  (setq prev-segment-was-globstar nil))))
   2878            glob-segments)
   2879           current-regexp)))))
   2880 
   2881 ;; See https://github.com/emacs-lsp/lsp-mode/issues/2365
   2882 (defun lsp-glob-unbrace-at-top-level (glob-pattern)
   2883   "If GLOB-PATTERN does not start with a brace, return a singleton list
   2884 containing GLOB-PATTERN.
   2885 
   2886 If GLOB-PATTERN does start with a brace, return a list of the
   2887 comma-separated globs within the top-level braces."
   2888   (if (not (string-prefix-p "{" glob-pattern))
   2889       (list glob-pattern)
   2890     (lsp-split-glob-pattern (substring glob-pattern 1 -1) ?\,)))
   2891 
   2892 (defun lsp-glob-convert-to-wrapped-regexp (glob-pattern)
   2893   "Convert GLOB-PATTERN to a regexp wrapped with the beginning-
   2894 and end-of-string meta-characters."
   2895   (concat "\\`" (lsp--glob-to-regexp (string-trim glob-pattern)) "\\'"))
   2896 
   2897 (defun lsp-glob-to-regexps (glob-pattern)
   2898   "Convert a GLOB-PATTERN to a list of Elisp regexps."
   2899   (when-let*
   2900       ((glob-pattern (cond ((hash-table-p glob-pattern)
   2901                             (ht-get glob-pattern "pattern"))
   2902                            ((stringp glob-pattern) glob-pattern)
   2903                            (t (error "Unknown glob-pattern type: %s" glob-pattern))))
   2904        (trimmed-pattern (string-trim glob-pattern))
   2905        (top-level-unbraced-patterns (lsp-glob-unbrace-at-top-level trimmed-pattern)))
   2906     (seq-map #'lsp-glob-convert-to-wrapped-regexp
   2907              top-level-unbraced-patterns)))
   2908 
   2909 
   2910 
   2911 (defvar lsp-mode-menu)
   2912 
   2913 (defun lsp-mouse-click (event)
   2914   (interactive "e")
   2915   (let* ((ec (event-start event))
   2916          (choice (x-popup-menu event lsp-mode-menu))
   2917          (action (lookup-key lsp-mode-menu (apply 'vector choice))))
   2918 
   2919     (select-window (posn-window ec))
   2920 
   2921     (unless (and (region-active-p) (eq action 'lsp-execute-code-action))
   2922       (goto-char (posn-point ec)))
   2923     (run-with-idle-timer
   2924      0.001 nil
   2925      (lambda ()
   2926        (cl-labels ((check (value) (not (null value))))
   2927          (when choice
   2928            (call-interactively action)))))))
   2929 
   2930 (defvar lsp-mode-map
   2931   (let ((map (make-sparse-keymap)))
   2932     (define-key map (kbd "C-<down-mouse-1>") #'lsp-find-definition-mouse)
   2933     (define-key map (kbd "C-<mouse-1>") #'ignore)
   2934     (define-key map (kbd "<mouse-3>") #'lsp-mouse-click)
   2935     (define-key map (kbd "C-S-SPC") #'lsp-signature-activate)
   2936     (when lsp-keymap-prefix
   2937       (define-key map (kbd lsp-keymap-prefix) lsp-command-map))
   2938     map)
   2939   "Keymap for `lsp-mode'.")
   2940 
   2941 (define-minor-mode lsp-mode "Mode for LSP interaction."
   2942   :keymap lsp-mode-map
   2943   :lighter
   2944   (" LSP["
   2945    (lsp--buffer-workspaces
   2946     (:eval (mapconcat #'lsp--workspace-print lsp--buffer-workspaces "]["))
   2947     (:propertize "Disconnected" face warning))
   2948    "]")
   2949   :group 'lsp-mode
   2950   (when (and lsp-mode (not lsp--buffer-workspaces) (not lsp--buffer-deferred))
   2951     ;; fire up `lsp' when someone calls `lsp-mode' instead of `lsp'
   2952     (lsp)))
   2953 
   2954 (defvar lsp-mode-menu
   2955   (easy-menu-create-menu
   2956    nil
   2957    `(["Go to definition" lsp-find-definition
   2958       :active (lsp-feature? "textDocument/definition")]
   2959      ["Find references" lsp-find-references
   2960       :active (lsp-feature? "textDocument/references")]
   2961      ["Find implementations" lsp-find-implementation
   2962       :active (lsp-feature? "textDocument/implementation")]
   2963      ["Find declarations" lsp-find-declaration
   2964       :active (lsp-feature? "textDocument/declaration")]
   2965      ["Go to type declaration" lsp-find-type-definition
   2966       :active (lsp-feature? "textDocument/typeDefinition")]
   2967      "--"
   2968      ["Describe" lsp-describe-thing-at-point]
   2969      ["Code action" lsp-execute-code-action]
   2970      ["Format" lsp-format-buffer]
   2971      ["Highlight references" lsp-document-highlight]
   2972      ["Type Hierarchy" lsp-java-type-hierarchy
   2973       :visible (lsp-can-execute-command? "java.navigate.resolveTypeHierarchy")]
   2974      ["Type Hierarchy" lsp-treemacs-type-hierarchy
   2975       :visible (and (not (lsp-can-execute-command? "java.navigate.resolveTypeHierarchy"))
   2976                     (functionp 'lsp-treemacs-type-hierarchy)
   2977                     (lsp-feature? "textDocument/typeHierarchy"))]
   2978      ["Call Hierarchy" lsp-treemacs-call-hierarchy
   2979       :visible (and (functionp 'lsp-treemacs-call-hierarchy)
   2980                     (lsp-feature? "textDocument/callHierarchy"))]
   2981      ["Rename" lsp-rename
   2982       :active (lsp-feature? "textDocument/rename")]
   2983      "--"
   2984      ("Session"
   2985       ["View logs" lsp-workspace-show-log]
   2986       ["Describe" lsp-describe-session]
   2987       ["Shutdown" lsp-shutdown-workspace]
   2988       ["Restart" lsp-restart-workspace])
   2989      ("Workspace Folders"
   2990       ["Add" lsp-workspace-folders-add]
   2991       ["Remove" lsp-workspace-folders-remove]
   2992       ["Open" lsp-workspace-folders-open])
   2993      ("Toggle features"
   2994       ["Lenses" lsp-lens-mode]
   2995       ["Headerline breadcrumb" lsp-headerline-breadcrumb-mode]
   2996       ["Modeline code actions" lsp-modeline-code-actions-mode]
   2997       ["Modeline diagnostics" lsp-modeline-diagnostics-mode])
   2998      "---"
   2999      ("Debug"
   3000       :active (bound-and-true-p dap-ui-mode)
   3001       :filter ,(lambda (_)
   3002                  (and (boundp 'dap-ui-menu-items)
   3003                       (nthcdr 3 dap-ui-menu-items))))))
   3004   "Menu for lsp-mode.")
   3005 
   3006 (defalias 'make-lsp-client 'make-lsp--client)
   3007 
   3008 (cl-defstruct lsp--registered-capability
   3009   (id "")
   3010   (method " ")
   3011   (options nil))
   3012 
   3013 ;; A ‘lsp--workspace’ object represents exactly one language server process.
   3014 (cl-defstruct lsp--workspace
   3015   ;; the `ewoc' object for displaying I/O to and from the server
   3016   (ewoc nil)
   3017 
   3018   ;; ‘server-capabilities’ is a hash table of the language server capabilities.
   3019   ;; It is the hash table representation of a LSP ServerCapabilities structure;
   3020   ;; cf. https://microsoft.github.io/language-server-protocol/specification#initialize.
   3021   (server-capabilities nil)
   3022 
   3023   ;; ‘registered-server-capabilities’ is a list of hash tables that represent
   3024   ;; dynamically-registered Registration objects.  See
   3025   ;; https://microsoft.github.io/language-server-protocol/specification#client_registerCapability.
   3026   (registered-server-capabilities nil)
   3027 
   3028   ;; ‘root’ is a directory name or a directory file name for the workspace
   3029   ;; root.  ‘lsp-mode’ passes this directory to the ‘initialize’ method of the
   3030   ;; language server; see
   3031   ;; https://microsoft.github.io/language-server-protocol/specification#initialize.
   3032   (root nil)
   3033 
   3034   ;; ‘client’ is the ‘lsp--client’ object associated with this workspace.
   3035   (client nil)
   3036 
   3037   ;; ‘host-root’ contains the host root info as derived from `file-remote-p'. It
   3038   ;; used to derive the file path in `lsp--uri-to-path' when using tramp
   3039   ;; connection.
   3040   (host-root nil)
   3041 
   3042   ;; ‘proc’ is a process object; it may represent a regular process, a pipe, or
   3043   ;; a network connection.  ‘lsp-mode’ communicates with ‘proc’ using the
   3044   ;; language server protocol.  ‘proc’ corresponds to the COMMUNICATION-PROCESS
   3045   ;; element of the return value of the client’s ‘get-root’ field, which see.
   3046   (proc nil)
   3047 
   3048   ;; ‘proc’ is a process object; it must represent a regular process, not a
   3049   ;; pipe or network process.  It represents the actual server process that
   3050   ;; corresponds to this workspace.  ‘cmd-proc’ corresponds to the
   3051   ;; COMMAND-PROCESS element of the return value of the client’s ‘get-root’
   3052   ;; field, which see.
   3053   (cmd-proc nil)
   3054 
   3055   ;; ‘buffers’ is a list of buffers associated with this workspace.
   3056   (buffers nil)
   3057 
   3058   ;; if semantic tokens is enabled, `semantic-tokens-faces' contains
   3059   ;; one face (or nil) for each token type supported by the language server.
   3060   (semantic-tokens-faces nil)
   3061 
   3062   ;; If semantic highlighting is enabled, `semantic-tokens-modifier-faces'
   3063   ;; contains one face (or nil) for each modifier type supported by the language
   3064   ;; server
   3065   (semantic-tokens-modifier-faces nil)
   3066 
   3067   ;; Extra client capabilities provided by third-party packages using
   3068   ;; `lsp-register-client-capabilities'. It's value is an alist of (PACKAGE-NAME
   3069   ;; . CAPS), where PACKAGE-NAME is a symbol of the third-party package name,
   3070   ;; and CAPS is either a plist of the client capabilities, or a function that
   3071   ;; takes no argument and returns a plist of the client capabilities or nil.
   3072   (extra-client-capabilities nil)
   3073 
   3074   ;; Workspace status
   3075   (status nil)
   3076 
   3077   ;; ‘metadata’ is a generic storage for workspace specific data. It is
   3078   ;; accessed via `lsp-workspace-set-metadata' and `lsp-workspace-set-metadata'
   3079   (metadata (make-hash-table :test 'equal))
   3080 
   3081   ;; contains all the file notification watches that have been created for the
   3082   ;; current workspace in format filePath->file notification handle.
   3083   (watches (make-hash-table :test 'equal))
   3084 
   3085   ;; list of workspace folders
   3086   (workspace-folders nil)
   3087 
   3088   ;; ‘last-id’ the last request id for the current workspace.
   3089   (last-id 0)
   3090 
   3091   ;; ‘status-string’ allows extensions to specify custom status string based on
   3092   ;; the Language Server specific messages.
   3093   (status-string nil)
   3094 
   3095   ;; ‘shutdown-action’ flag used to mark that workspace should not be restarted (e.g. it
   3096   ;; was stopped).
   3097   shutdown-action
   3098 
   3099   ;; ‘diagnostics’ a hashmap with workspace diagnostics.
   3100   (diagnostics (make-hash-table :test 'equal))
   3101 
   3102   ;; contains all the workDone progress tokens that have been created
   3103   ;; for the current workspace.
   3104   (work-done-tokens (make-hash-table :test 'equal)))
   3105 
   3106 
   3107 (cl-defstruct lsp-session
   3108   ;; contains the folders that are part of the current session
   3109   folders
   3110   ;; contains the folders that must not be imported in the current workspace.
   3111   folders-blocklist
   3112   ;; contains the list of folders that must be imported in a project in case of
   3113   ;; multi root LSP server.
   3114   (server-id->folders (make-hash-table :test 'equal))
   3115   ;; folder to list of the servers that are associated with the folder.
   3116   (folder->servers (make-hash-table :test 'equal))
   3117   ;; ‘metadata’ is a generic storage for workspace specific data. It is
   3118   ;; accessed via `lsp-workspace-set-metadata' and `lsp-workspace-set-metadata'
   3119   (metadata (make-hash-table :test 'equal)))
   3120 
   3121 (defun lsp-workspace-status (status-string &optional workspace)
   3122   "Set current workspace status to STATUS-STRING.
   3123 If WORKSPACE is not specified defaults to lsp--cur-workspace."
   3124   (let ((status-string (when status-string (replace-regexp-in-string "%" "%%" status-string))))
   3125     (setf (lsp--workspace-status-string (or workspace lsp--cur-workspace)) status-string)))
   3126 
   3127 (defun lsp-session-set-metadata (key value &optional _workspace)
   3128   "Associate KEY with VALUE in the WORKSPACE metadata.
   3129 If WORKSPACE is not provided current workspace will be used."
   3130   (puthash key value (lsp-session-metadata (lsp-session))))
   3131 
   3132 (defalias 'lsp-workspace-set-metadata 'lsp-session-set-metadata)
   3133 
   3134 (defun lsp-session-get-metadata (key &optional _workspace)
   3135   "Lookup KEY in WORKSPACE metadata.
   3136 If WORKSPACE is not provided current workspace will be used."
   3137   (gethash key (lsp-session-metadata (lsp-session))))
   3138 
   3139 (defalias 'lsp-workspace-get-metadata 'lsp-session-get-metadata)
   3140 
   3141 (defun lsp-workspace-set-work-done-token (token value workspace)
   3142   "Associate TOKEN with VALUE in the WORKSPACE work-done-tokens."
   3143   (puthash token value (lsp--workspace-work-done-tokens workspace)))
   3144 
   3145 (defun lsp-workspace-get-work-done-token (token workspace)
   3146   "Lookup TOKEN in the WORKSPACE work-done-tokens."
   3147   (gethash token (lsp--workspace-work-done-tokens workspace)))
   3148 
   3149 (defun lsp-workspace-rem-work-done-token (token workspace)
   3150   "Remove TOKEN from the WORKSPACE work-done-tokens."
   3151   (remhash token (lsp--workspace-work-done-tokens workspace)))
   3152 
   3153 
   3154 (defun lsp--make-notification (method &optional params)
   3155   "Create notification body for method METHOD and parameters PARAMS."
   3156   (list :jsonrpc "2.0" :method method :params params))
   3157 
   3158 (defalias 'lsp--make-request 'lsp--make-notification)
   3159 (defalias 'lsp-make-request 'lsp--make-notification)
   3160 
   3161 (defun lsp--make-response (id result)
   3162   "Create response for REQUEST with RESULT."
   3163   `(:jsonrpc "2.0" :id ,id :result ,result))
   3164 
   3165 (defun lsp-make-notification (method &optional params)
   3166   "Create notification body for method METHOD and parameters PARAMS."
   3167   (lsp--make-notification method params))
   3168 
   3169 (defmacro lsp--json-serialize (params)
   3170   (if (progn
   3171         (require 'json)
   3172         (fboundp 'json-serialize))
   3173       `(json-serialize ,params
   3174                        :null-object nil
   3175                        :false-object :json-false)
   3176     `(let ((json-false :json-false))
   3177        (json-encode ,params))))
   3178 
   3179 (defun lsp--make-message (params)
   3180   "Create a LSP message from PARAMS, after encoding it to a JSON string."
   3181   (let ((body (lsp--json-serialize params)))
   3182     (concat "Content-Length: "
   3183             (number-to-string (1+ (string-bytes body)))
   3184             "\r\n\r\n"
   3185             body
   3186             "\n")))
   3187 
   3188 (cl-defstruct lsp--log-entry timestamp process-time type method id body)
   3189 
   3190 (defun lsp--make-log-entry (method id body type &optional process-time)
   3191   "Create an outgoing log object from BODY with method METHOD and id ID.
   3192 If ID is non-nil, then the body is assumed to be a notification.
   3193 TYPE can either be `incoming' or `outgoing'"
   3194   (cl-assert (memq type '(incoming-req outgoing-req incoming-notif
   3195                                        outgoing-notif incoming-resp
   3196                                        outgoing-resp)))
   3197   (make-lsp--log-entry
   3198    :timestamp (format-time-string "%I:%M:%S %p")
   3199    :process-time process-time
   3200    :method method
   3201    :id id
   3202    :type type
   3203    :body body))
   3204 
   3205 (defun lsp--log-font-lock-json (body)
   3206   "Font lock JSON BODY."
   3207   (with-temp-buffer
   3208     (insert body)
   3209     ;; We set the temp buffer file-name extension to .json and call `set-auto-mode'
   3210     ;; so the users configured json mode is used which could be
   3211     ;; `json-mode', `json-ts-mode', `jsonian-mode', etc.
   3212     (let ((buffer-file-name "lsp-log.json"))
   3213       (delay-mode-hooks
   3214         (set-auto-mode)
   3215         (if (fboundp 'font-lock-ensure)
   3216             (font-lock-ensure)
   3217           (with-no-warnings
   3218             (font-lock-fontify-buffer)))))
   3219     (buffer-string)))
   3220 
   3221 (defun lsp--log-entry-pp (entry)
   3222   (cl-assert (lsp--log-entry-p entry))
   3223   (pcase-let (((cl-struct lsp--log-entry timestamp method id type process-time
   3224                           body)
   3225                entry)
   3226               (json-false :json-false)
   3227               (json-encoding-pretty-print t)
   3228               (str nil))
   3229     (setq str
   3230           (concat (format "[Trace - %s] " timestamp)
   3231                   (pcase type
   3232                     ('incoming-req (format "Received request '%s - (%s)." method id))
   3233                     ('outgoing-req (format "Sending request '%s - (%s)'." method id))
   3234 
   3235                     ('incoming-notif (format "Received notification '%s'." method))
   3236                     ('outgoing-notif (format "Sending notification '%s'." method))
   3237 
   3238                     ('incoming-resp (format "Received response '%s - (%s)' in %dms."
   3239                                             method id process-time))
   3240                     ('outgoing-resp
   3241                      (format
   3242                       "Sending response '%s - (%s)'. Processing request took %dms"
   3243                       method id process-time)))
   3244                   "\n"
   3245                   (if (memq type '(incoming-resp ougoing-resp))
   3246                       "Result: "
   3247                     "Params: ")
   3248                   (lsp--log-font-lock-json (json-encode body))
   3249                   "\n\n\n"))
   3250     (setq str (propertize str 'mouse-face 'highlight 'read-only t))
   3251     (insert str)))
   3252 
   3253 (defvar-local lsp--log-io-ewoc nil)
   3254 
   3255 (defun lsp--get-create-io-ewoc (workspace)
   3256   (if (and (lsp--workspace-ewoc workspace)
   3257            (buffer-live-p (ewoc-buffer (lsp--workspace-ewoc workspace))))
   3258       (lsp--workspace-ewoc workspace)
   3259     (with-current-buffer (lsp--get-log-buffer-create workspace)
   3260       (unless (eq 'lsp-log-io-mode major-mode) (lsp-log-io-mode))
   3261       (setq-local window-point-insertion-type t)
   3262       (setq lsp--log-io-ewoc (ewoc-create #'lsp--log-entry-pp nil nil t))
   3263       (setf (lsp--workspace-ewoc workspace) lsp--log-io-ewoc))
   3264     (lsp--workspace-ewoc workspace)))
   3265 
   3266 (defun lsp--ewoc-count (ewoc)
   3267   (let* ((count 0)
   3268          (count-fn (lambda (_) (setq count (1+ count)))))
   3269     (ewoc-map count-fn ewoc)
   3270     count))
   3271 
   3272 (defun lsp--log-entry-new (entry workspace)
   3273   (let* ((ewoc (lsp--get-create-io-ewoc workspace))
   3274          (count (and (not (eq lsp-io-messages-max t)) (lsp--ewoc-count ewoc)))
   3275          (node (if (or (eq lsp-io-messages-max t)
   3276                        (>= lsp-io-messages-max count))
   3277                    nil
   3278                  (ewoc-nth ewoc (1- lsp-io-messages-max))))
   3279          (prev nil)
   3280          (inhibit-read-only t))
   3281     (while node
   3282       (setq prev (ewoc-prev ewoc node))
   3283       (ewoc-delete ewoc node)
   3284       (setq node prev))
   3285     (ewoc-enter-last ewoc entry)))
   3286 
   3287 (defun lsp--send-notification (body)
   3288   "Send BODY as a notification to the language server."
   3289   (lsp-foreach-workspace
   3290    (when (lsp--log-io-p (plist-get body :method))
   3291      (lsp--log-entry-new (lsp--make-log-entry
   3292                           (plist-get body :method)
   3293                           nil (plist-get body :params) 'outgoing-notif)
   3294                          lsp--cur-workspace))
   3295    (lsp--send-no-wait body
   3296                       (lsp--workspace-proc lsp--cur-workspace))))
   3297 
   3298 (defalias 'lsp-send-notification 'lsp--send-notification)
   3299 
   3300 (defun lsp-notify (method params)
   3301   "Send notification METHOD with PARAMS."
   3302   (lsp--send-notification (lsp--make-notification method params)))
   3303 
   3304 (defun lsp--cur-workspace-check ()
   3305   "Check whether buffer lsp workspace(s) are set."
   3306   (cl-assert (lsp-workspaces) nil
   3307              "No language server(s) is associated with this buffer."))
   3308 
   3309 (defun lsp--send-request (body &optional no-wait no-merge)
   3310   "Send BODY as a request to the language server, get the response.
   3311 If NO-WAIT is non-nil, don't synchronously wait for a response.
   3312 If NO-MERGE is non-nil, don't merge the results but return an
   3313 alist mapping workspace->result."
   3314   (lsp-request (plist-get body :method)
   3315                (plist-get body :params)
   3316                :no-wait no-wait
   3317                :no-merge no-merge))
   3318 
   3319 (defalias 'lsp-send-request 'lsp--send-request
   3320   "Send BODY as a request to the language server and return the response
   3321 synchronously.
   3322 \n(fn BODY)")
   3323 
   3324 (cl-defun lsp-request (method params &key no-wait no-merge)
   3325   "Send request METHOD with PARAMS.
   3326 If NO-MERGE is non-nil, don't merge the results but return alist
   3327 workspace->result.
   3328 If NO-WAIT is non-nil send the request as notification."
   3329   (if no-wait
   3330       (lsp-notify method params)
   3331     (let* ((send-time (float-time))
   3332            ;; max time by which we must get a response
   3333            (expected-time
   3334             (and
   3335              lsp-response-timeout
   3336              (+ send-time lsp-response-timeout)))
   3337            resp-result resp-error done?)
   3338       (unwind-protect
   3339           (progn
   3340             (lsp-request-async method params
   3341                                (lambda (res) (setf resp-result (or res :finished)) (throw 'lsp-done '_))
   3342                                :error-handler (lambda (err) (setf resp-error err) (throw 'lsp-done '_))
   3343                                :no-merge no-merge
   3344                                :mode 'detached
   3345                                :cancel-token :sync-request)
   3346             (while (not (or resp-error resp-result))
   3347               (if (functionp 'json-rpc-connection)
   3348                   (catch 'lsp-done (sit-for 0.01))
   3349                 (catch 'lsp-done
   3350                   (accept-process-output
   3351                    nil
   3352                    (if expected-time (- expected-time send-time) 1))))
   3353               (setq send-time (float-time))
   3354               (when (and expected-time (< expected-time send-time))
   3355                 (error "Timeout while waiting for response.  Method: %s" method)))
   3356             (setq done? t)
   3357             (cond
   3358              ((eq resp-result :finished) nil)
   3359              (resp-result resp-result)
   3360              ((lsp-json-error? resp-error) (error (lsp:json-error-message resp-error)))
   3361              ((lsp-json-error? (cl-first resp-error))
   3362               (error (lsp:json-error-message (cl-first resp-error))))))
   3363         (unless done?
   3364           (lsp-cancel-request-by-token :sync-request))))))
   3365 
   3366 (cl-defun lsp-request-while-no-input (method params)
   3367   "Send request METHOD with PARAMS and waits until there is no input.
   3368 Return same value as `lsp--while-no-input' and respecting `non-essential'."
   3369   (if (or non-essential (not lsp-request-while-no-input-may-block))
   3370       (let* ((send-time (float-time))
   3371              ;; max time by which we must get a response
   3372              (expected-time
   3373               (and
   3374                lsp-response-timeout
   3375                (+ send-time lsp-response-timeout)))
   3376              resp-result resp-error done?)
   3377         (unwind-protect
   3378             (progn
   3379               (lsp-request-async method params
   3380                                  (lambda (res) (setf resp-result (or res :finished)) (throw 'lsp-done '_))
   3381                                  :error-handler (lambda (err) (setf resp-error err) (throw 'lsp-done '_))
   3382                                  :mode 'detached
   3383                                  :cancel-token :sync-request)
   3384               (while (not (or resp-error resp-result (input-pending-p)))
   3385                 (catch 'lsp-done
   3386                   (sit-for
   3387                    (if expected-time (- expected-time send-time) 1)))
   3388                 (setq send-time (float-time))
   3389                 (when (and expected-time (< expected-time send-time))
   3390                   (error "Timeout while waiting for response.  Method: %s" method)))
   3391               (setq done? (or resp-error resp-result))
   3392               (cond
   3393                ((eq resp-result :finished) nil)
   3394                (resp-result resp-result)
   3395                ((lsp-json-error? resp-error) (error (lsp:json-error-message resp-error)))
   3396                ((lsp-json-error? (cl-first resp-error))
   3397                 (error (lsp:json-error-message (cl-first resp-error))))))
   3398           (unless done?
   3399             (lsp-cancel-request-by-token :sync-request))
   3400           (when (and (input-pending-p) lsp--throw-on-input)
   3401             (throw 'input :interrupted))))
   3402     (lsp-request method params)))
   3403 
   3404 (defvar lsp--cancelable-requests (ht))
   3405 
   3406 (cl-defun lsp-request-async (method params callback
   3407                                     &key mode error-handler cancel-handler no-merge cancel-token)
   3408   "Send METHOD with PARAMS as a request to the language server.
   3409 Call CALLBACK with the response received from the server
   3410 asynchronously.
   3411 MODE determines when the callback will be called depending on the
   3412 condition of the original buffer.  It could be:
   3413 - `detached' which means that the callback will be executed no
   3414 matter what has happened to the buffer.
   3415 - `alive' - the callback will be executed only if the buffer from
   3416 which the call was executed is still alive.
   3417 - `current' the callback will be executed only if the original buffer
   3418 is still selected.
   3419 - `tick' - the callback will be executed only if the buffer was not modified.
   3420 - `unchanged' - the callback will be executed only if the buffer hasn't
   3421 changed and if the buffer is not modified.
   3422 
   3423 ERROR-HANDLER will be called in case the request has failed.
   3424 CANCEL-HANDLER will be called in case the request is being canceled.
   3425 If NO-MERGE is non-nil, don't merge the results but return alist
   3426 workspace->result.
   3427 CANCEL-TOKEN is the token that can be used to cancel request."
   3428   (lsp--send-request-async `(:jsonrpc "2.0" :method ,method :params ,params)
   3429                            callback mode error-handler cancel-handler no-merge cancel-token))
   3430 
   3431 (defun lsp--create-request-cancel (id workspaces hook buf method cancel-callback)
   3432   (lambda (&rest _)
   3433     (unless (and (equal 'post-command-hook hook)
   3434                  (equal (current-buffer) buf))
   3435       (lsp--request-cleanup-hooks id)
   3436       (with-lsp-workspaces workspaces
   3437         (lsp--cancel-request id)
   3438         (when cancel-callback (funcall cancel-callback)))
   3439       (lsp-log "Cancelling %s(%s) in hook %s" method id hook))))
   3440 
   3441 (defun lsp--create-async-callback
   3442     (callback method no-merge workspaces)
   3443   "Create async handler expecting COUNT results, merge them and call CALLBACK.
   3444 MODE determines when the callback will be called depending on the
   3445 condition of the original buffer. METHOD is the invoked method.
   3446 If NO-MERGE is non-nil, don't merge the results but return alist
   3447 workspace->result. ID is the request id."
   3448   (let (results errors)
   3449     (lambda (result)
   3450       (push (cons lsp--cur-workspace result)
   3451             (if (eq result :error) errors results))
   3452       (when (and (not (eq (length errors) (length workspaces)))
   3453                  (eq (+ (length errors) (length results)) (length workspaces)))
   3454         (funcall callback
   3455                  (if no-merge
   3456                      results
   3457                    (lsp--merge-results (-map #'cl-rest results) method)))))))
   3458 
   3459 (defcustom lsp-default-create-error-handler-fn nil
   3460   "Default error handler customization.
   3461 Handler should give METHOD as argument and return function of one argument
   3462 ERROR."
   3463   :type 'function
   3464   :group 'lsp-mode
   3465   :package-version '(lsp-mode . "9.0.0"))
   3466 
   3467 (defun lsp--create-default-error-handler (method)
   3468   "Default error handler.
   3469 METHOD is the executed method."
   3470   (if lsp-default-create-error-handler-fn
   3471       (funcall lsp-default-create-error-handler-fn method)
   3472     (lambda (error)
   3473       (lsp--warn "%s" (or (lsp--error-string error)
   3474                           (format "%s Request has failed" method))))))
   3475 
   3476 (defvar lsp--request-cleanup-hooks (ht))
   3477 
   3478 (defun lsp--request-cleanup-hooks (request-id)
   3479   (when-let ((cleanup-function (gethash request-id lsp--request-cleanup-hooks)))
   3480     (funcall cleanup-function)
   3481     (remhash request-id lsp--request-cleanup-hooks)))
   3482 
   3483 (defun lsp-cancel-request-by-token (cancel-token)
   3484   "Cancel request using CANCEL-TOKEN."
   3485   (-when-let ((request-id . workspaces) (gethash cancel-token lsp--cancelable-requests))
   3486     (with-lsp-workspaces workspaces
   3487       (lsp--cancel-request request-id))
   3488     (remhash cancel-token lsp--cancelable-requests)
   3489     (lsp--request-cleanup-hooks request-id)))
   3490 
   3491 (defun lsp--send-request-async (body callback
   3492                                      &optional mode error-callback cancel-callback
   3493                                      no-merge cancel-token)
   3494   "Send BODY as a request to the language server.
   3495 Call CALLBACK with the response received from the server
   3496 asynchronously.
   3497 MODE determines when the callback will be called depending on the
   3498 condition of the original buffer.  It could be:
   3499 - `detached' which means that the callback will be executed no
   3500 matter what has happened to the buffer.
   3501 - `alive' - the callback will be executed only if the buffer from
   3502 which the call was executed is still alive.
   3503 - `current' the callback will be executed only if the original buffer
   3504 is still selected.
   3505 - `tick' - the callback will be executed only if the buffer was not modified.
   3506 - `unchanged' - the callback will be executed only if the buffer hasn't
   3507 changed and if the buffer is not modified.
   3508 
   3509 ERROR-CALLBACK will be called in case the request has failed.
   3510 CANCEL-CALLBACK will be called in case the request is being canceled.
   3511 If NO-MERGE is non-nil, don't merge the results but return alist
   3512 workspace->result.
   3513 CANCEL-TOKEN is the token that can be used to cancel request."
   3514   (when cancel-token
   3515     (lsp-cancel-request-by-token cancel-token))
   3516 
   3517   (if-let ((target-workspaces (lsp--find-workspaces-for body)))
   3518       (let* ((start-time (current-time))
   3519              (method (plist-get body :method))
   3520              (id (cl-incf lsp-last-id))
   3521              (buf (current-buffer))
   3522              (cancel-callback (when cancel-callback
   3523                                 (pcase mode
   3524                                   ((or 'alive 'tick 'unchanged)
   3525                                    (lambda ()
   3526                                      (with-current-buffer buf
   3527                                        (funcall cancel-callback))))
   3528                                   (_ cancel-callback))))
   3529              ;; calculate what are the (hook . local) pairs which will cancel
   3530              ;; the request
   3531              (hooks (pcase mode
   3532                       ('alive     '((kill-buffer-hook . t)))
   3533                       ('tick      '((kill-buffer-hook . t) (after-change-functions . t)))
   3534                       ('unchanged '((after-change-functions . t) (post-command-hook . nil)))
   3535                       ('current   '((post-command-hook . nil)))))
   3536              ;; note: lambdas in emacs can be compared but we should make sure
   3537              ;; that all of the captured arguments are the same - in our case
   3538              ;; `lsp--create-request-cancel' will return the same lambda when
   3539              ;; called with the same params.
   3540              (cleanup-hooks
   3541               (lambda () (mapc
   3542                           (-lambda ((hook . local))
   3543                             (if local
   3544                                 (when (buffer-live-p buf)
   3545                                   (with-current-buffer buf
   3546                                     (remove-hook hook
   3547                                                  (lsp--create-request-cancel
   3548                                                   id target-workspaces hook buf method cancel-callback)
   3549                                                  t)))
   3550                               (remove-hook hook (lsp--create-request-cancel
   3551                                                  id target-workspaces hook buf method cancel-callback))))
   3552                           hooks)
   3553                 (remhash cancel-token lsp--cancelable-requests)))
   3554              (callback (pcase mode
   3555                          ((or 'alive 'tick 'unchanged) (lambda (&rest args)
   3556                                                          (with-current-buffer buf
   3557                                                            (apply callback args))))
   3558                          (_ callback)))
   3559              (callback (lsp--create-async-callback callback
   3560                                                    method
   3561                                                    no-merge
   3562                                                    target-workspaces))
   3563              (callback (lambda (result)
   3564                          (lsp--request-cleanup-hooks id)
   3565                          (funcall callback result)))
   3566              (error-callback (lsp--create-async-callback
   3567                               (or error-callback
   3568                                   (lsp--create-default-error-handler method))
   3569                               method
   3570                               nil
   3571                               target-workspaces))
   3572              (error-callback (lambda (error)
   3573                                (funcall callback :error)
   3574                                (lsp--request-cleanup-hooks id)
   3575                                (funcall error-callback error)))
   3576              (body (plist-put body :id id)))
   3577 
   3578         ;; cancel request in any of the hooks
   3579         (mapc (-lambda ((hook . local))
   3580                 (add-hook hook
   3581                           (lsp--create-request-cancel
   3582                            id target-workspaces hook buf method cancel-callback)
   3583                           nil local))
   3584               hooks)
   3585         (puthash id cleanup-hooks lsp--request-cleanup-hooks)
   3586 
   3587         (setq lsp--last-active-workspaces target-workspaces)
   3588 
   3589         (when cancel-token
   3590           (puthash cancel-token (cons id target-workspaces) lsp--cancelable-requests))
   3591 
   3592         (seq-doseq (workspace target-workspaces)
   3593           (when (lsp--log-io-p method)
   3594             (lsp--log-entry-new (lsp--make-log-entry method id
   3595                                                      (plist-get body :params)
   3596                                                      'outgoing-req)
   3597                                 workspace))
   3598           (puthash id
   3599                    (list callback error-callback method start-time (current-time))
   3600                    (-> workspace
   3601                        (lsp--workspace-client)
   3602                        (lsp--client-response-handlers)))
   3603           (lsp--send-no-wait body (lsp--workspace-proc workspace)))
   3604         body)
   3605     (error "The connected server(s) does not support method %s.
   3606 To find out what capabilities support your server use `M-x lsp-describe-session'
   3607 and expand the capabilities section"
   3608            (plist-get body :method))))
   3609 
   3610 ;; deprecated, use lsp-request-async.
   3611 (defalias 'lsp-send-request-async 'lsp--send-request-async)
   3612 (make-obsolete 'lsp-send-request-async 'lsp-request-async "lsp-mode 7.0.1")
   3613 
   3614 ;; Clean up the entire state of lsp mode when Emacs is killed, to get rid of any
   3615 ;; pending language servers.
   3616 (add-hook 'kill-emacs-hook #'lsp--global-teardown)
   3617 
   3618 (defun lsp--global-teardown ()
   3619   "Unload working workspaces."
   3620   (lsp-foreach-workspace (lsp--shutdown-workspace)))
   3621 
   3622 (defun lsp--shutdown-workspace (&optional restart)
   3623   "Shut down the language server process for ‘lsp--cur-workspace’."
   3624   (with-demoted-errors "LSP error: %S"
   3625     (let ((lsp-response-timeout 0.5))
   3626       (condition-case err
   3627           (lsp-request "shutdown" nil)
   3628         (error (lsp--error "%s" err))))
   3629     (lsp-notify "exit" nil))
   3630   (setf (lsp--workspace-shutdown-action lsp--cur-workspace) (or (and restart 'restart) 'shutdown))
   3631   (lsp--uninitialize-workspace))
   3632 
   3633 (defcustom lsp-inlay-hint-enable nil
   3634   "If non-nil it will enable inlay hints."
   3635   :type 'boolean
   3636   :group 'lsp-mode
   3637   :package-version '(lsp-mode . "9.0.0"))
   3638 
   3639 (defun lsp--uninitialize-workspace ()
   3640   "Cleanup buffer state.
   3641 When a workspace is shut down, by request or from just
   3642 disappearing, unset all the variables related to it."
   3643   (-let [(&lsp-wks 'cmd-proc 'buffers) lsp--cur-workspace]
   3644     (lsp-process-kill cmd-proc)
   3645     (mapc (lambda (buf)
   3646             (when (lsp-buffer-live-p buf)
   3647               (lsp-with-current-buffer buf
   3648                                        (lsp-managed-mode -1))))
   3649           buffers)
   3650     (lsp-diagnostics--workspace-cleanup lsp--cur-workspace)))
   3651 
   3652 (defun lsp--client-capabilities (&optional custom-capabilities)
   3653   "Return the client capabilities appending CUSTOM-CAPABILITIES."
   3654   (append
   3655    `((general . ((positionEncodings . ["utf-32", "utf-16"])))
   3656      (workspace . ((workspaceEdit . ((documentChanges . t)
   3657                                      (resourceOperations . ["create" "rename" "delete"])))
   3658                    (applyEdit . t)
   3659                    (symbol . ((symbolKind . ((valueSet . ,(apply 'vector (number-sequence 1 26)))))))
   3660                    (executeCommand . ((dynamicRegistration . :json-false)))
   3661                    ,@(when lsp-enable-file-watchers '((didChangeWatchedFiles . ((dynamicRegistration . t)))))
   3662                    (workspaceFolders . t)
   3663                    (configuration . t)
   3664                    ,@(when lsp-semantic-tokens-enable
   3665                        `((semanticTokens . ((refreshSupport . ,(or (and (boundp 'lsp-semantic-tokens-honor-refresh-requests)
   3666                                                                         lsp-semantic-tokens-honor-refresh-requests)
   3667                                                                    :json-false))))))
   3668                    ,@(when lsp-lens-enable '((codeLens . ((refreshSupport . t)))))
   3669                    ,@(when lsp-inlay-hint-enable '((inlayHint . ((refreshSupport . :json-false)))))
   3670                    (fileOperations . ((didCreate . :json-false)
   3671                                       (willCreate . :json-false)
   3672                                       (didRename . t)
   3673                                       (willRename . t)
   3674                                       (didDelete . :json-false)
   3675                                       (willDelete . :json-false)))))
   3676      (textDocument . ((declaration . ((dynamicRegistration . t)
   3677                                       (linkSupport . t)))
   3678                       (definition . ((dynamicRegistration . t)
   3679                                      (linkSupport . t)))
   3680                       (references . ((dynamicRegistration . t)))
   3681                       (implementation . ((dynamicRegistration . t)
   3682                                          (linkSupport . t)))
   3683                       (typeDefinition . ((dynamicRegistration . t)
   3684                                          (linkSupport . t)))
   3685                       (synchronization . ((willSave . t) (didSave . t) (willSaveWaitUntil . t)))
   3686                       (documentSymbol . ((symbolKind . ((valueSet . ,(apply 'vector (number-sequence 1 26)))))
   3687                                          (hierarchicalDocumentSymbolSupport . t)))
   3688                       (formatting . ((dynamicRegistration . t)))
   3689                       (rangeFormatting . ((dynamicRegistration . t)))
   3690                       (onTypeFormatting . ((dynamicRegistration . t)))
   3691                       ,@(when (and lsp-semantic-tokens-enable
   3692                                    (functionp 'lsp--semantic-tokens-capabilities))
   3693                           (lsp--semantic-tokens-capabilities))
   3694                       (rename . ((dynamicRegistration . t) (prepareSupport . t)))
   3695                       (codeAction . ((dynamicRegistration . t)
   3696                                      (isPreferredSupport . t)
   3697                                      (codeActionLiteralSupport . ((codeActionKind . ((valueSet . [""
   3698                                                                                                   "quickfix"
   3699                                                                                                   "refactor"
   3700                                                                                                   "refactor.extract"
   3701                                                                                                   "refactor.inline"
   3702                                                                                                   "refactor.rewrite"
   3703                                                                                                   "source"
   3704                                                                                                   "source.organizeImports"])))))
   3705                                      (resolveSupport . ((properties . ["edit" "command"])))
   3706                                      (dataSupport . t)))
   3707                       (completion . ((completionItem . ((snippetSupport . ,(cond
   3708                                                                             ((and lsp-enable-snippet (not (fboundp 'yas-minor-mode)))
   3709                                                                              (lsp--warn (concat
   3710                                                                                          "Yasnippet is not installed, but `lsp-enable-snippet' is set to `t'. "
   3711                                                                                          "You must either install yasnippet, or disable snippet support."))
   3712                                                                              :json-false)
   3713                                                                             (lsp-enable-snippet t)
   3714                                                                             (t :json-false)))
   3715                                                         (documentationFormat . ["markdown" "plaintext"])
   3716                                                         ;; Remove this after jdtls support resolveSupport
   3717                                                         (resolveAdditionalTextEditsSupport . t)
   3718                                                         (insertReplaceSupport . t)
   3719                                                         (deprecatedSupport . t)
   3720                                                         (resolveSupport
   3721                                                          . ((properties . ["documentation"
   3722                                                                            "detail"
   3723                                                                            "additionalTextEdits"
   3724                                                                            "command"])))
   3725                                                         (insertTextModeSupport . ((valueSet . [1 2])))))
   3726                                      (contextSupport . t)
   3727                                      (dynamicRegistration . t)))
   3728                       (signatureHelp . ((signatureInformation . ((parameterInformation . ((labelOffsetSupport . t)))))
   3729                                         (dynamicRegistration . t)))
   3730                       (documentLink . ((dynamicRegistration . t)
   3731                                        (tooltipSupport . t)))
   3732                       (hover . ((contentFormat . ["markdown" "plaintext"])
   3733                                 (dynamicRegistration . t)))
   3734                       ,@(when lsp-enable-folding
   3735                           `((foldingRange . ((dynamicRegistration . t)
   3736                                              ,@(when lsp-folding-range-limit
   3737                                                  `((rangeLimit . ,lsp-folding-range-limit)))
   3738                                              ,@(when lsp-folding-line-folding-only
   3739                                                  `((lineFoldingOnly . t)))))))
   3740                       (selectionRange . ((dynamicRegistration . t)))
   3741                       (callHierarchy . ((dynamicRegistration . :json-false)))
   3742                       (typeHierarchy . ((dynamicRegistration . t)))
   3743                       (publishDiagnostics . ((relatedInformation . t)
   3744                                              (tagSupport . ((valueSet . [1 2])))
   3745                                              (versionSupport . t)))
   3746                       (linkedEditingRange . ((dynamicRegistration . t)))))
   3747      (window . ((workDoneProgress . t)
   3748                 (showDocument . ((support . t))))))
   3749    custom-capabilities))
   3750 
   3751 (defun lsp-find-roots-for-workspace (workspace session)
   3752   "Get all roots for the WORKSPACE."
   3753   (-filter #'identity (ht-map (lambda (folder workspaces)
   3754                                 (when (-contains? workspaces workspace)
   3755                                   folder))
   3756                               (lsp-session-folder->servers session))))
   3757 
   3758 (defun lsp-session-watches (&optional session)
   3759   "Get watches created for SESSION."
   3760   (or (gethash "__watches" (lsp-session-metadata (or session (lsp-session))))
   3761       (-let [res (make-hash-table :test 'equal)]
   3762         (puthash "__watches" res (lsp-session-metadata (or session (lsp-session))))
   3763         res)))
   3764 
   3765 (defun lsp--file-process-event (session root-folder event)
   3766   "Process file event."
   3767   (let* ((changed-file (cl-third event))
   3768          (rel-changed-file (f-relative changed-file root-folder))
   3769          (event-numeric-kind (alist-get (cl-second event) lsp--file-change-type))
   3770          (bit-position (1- event-numeric-kind))
   3771          (watch-bit (ash 1 bit-position)))
   3772     (->>
   3773      session
   3774      lsp-session-folder->servers
   3775      (gethash root-folder)
   3776      (seq-do (lambda (workspace)
   3777                (when (->>
   3778                       workspace
   3779                       lsp--workspace-registered-server-capabilities
   3780                       (-any?
   3781                        (lambda (capability)
   3782                          (and
   3783                           (equal (lsp--registered-capability-method capability)
   3784                                  "workspace/didChangeWatchedFiles")
   3785                           (->>
   3786                            capability
   3787                            lsp--registered-capability-options
   3788                            (lsp:did-change-watched-files-registration-options-watchers)
   3789                            (seq-find
   3790                             (-lambda ((fs-watcher &as &FileSystemWatcher :glob-pattern :kind? :_cachedRegexp cached-regexp))
   3791                               (when (or (null kind?)
   3792                                         (> (logand kind? watch-bit) 0))
   3793                                 (-let [regexes (or cached-regexp
   3794                                                    (let ((regexp (lsp-glob-to-regexps glob-pattern)))
   3795                                                      (lsp-put fs-watcher :_cachedRegexp regexp)
   3796                                                      regexp))]
   3797                                   (-any? (lambda (re)
   3798                                            (or (string-match re changed-file)
   3799                                                (string-match re rel-changed-file)))
   3800                                          regexes))))))))))
   3801                  (with-lsp-workspace workspace
   3802                    (lsp-notify
   3803                     "workspace/didChangeWatchedFiles"
   3804                     `((changes . [((type . ,event-numeric-kind)
   3805                                    (uri . ,(lsp--path-to-uri changed-file)))]))))))))))
   3806 
   3807 (lsp-defun lsp--server-register-capability ((&Registration :method :id :register-options?))
   3808   "Register capability REG."
   3809   (when (and lsp-enable-file-watchers
   3810              (equal method "workspace/didChangeWatchedFiles"))
   3811     (-let* ((created-watches (lsp-session-watches (lsp-session)))
   3812             (root-folders (cl-set-difference
   3813                            (lsp-find-roots-for-workspace lsp--cur-workspace (lsp-session))
   3814                            (ht-keys created-watches))))
   3815       ;; create watch for each root folder without such
   3816       (dolist (folder root-folders)
   3817         (let* ((watch (make-lsp-watch :root-directory folder))
   3818                (ignored-things (lsp--get-ignored-regexes-for-workspace-root folder))
   3819                (ignored-files-regex-list (car ignored-things))
   3820                (ignored-directories-regex-list (cadr ignored-things)))
   3821           (puthash folder watch created-watches)
   3822           (lsp-watch-root-folder (file-truename folder)
   3823                                  (-partial #'lsp--file-process-event (lsp-session) folder)
   3824                                  ignored-files-regex-list
   3825                                  ignored-directories-regex-list
   3826                                  watch
   3827                                  t)))))
   3828 
   3829   (push
   3830    (make-lsp--registered-capability :id id :method method :options register-options?)
   3831    (lsp--workspace-registered-server-capabilities lsp--cur-workspace)))
   3832 
   3833 (defmacro lsp--with-workspace-temp-buffer (workspace-root &rest body)
   3834   "With a temp-buffer under `WORKSPACE-ROOT' and evaluate `BODY', useful to
   3835 access dir-local variables."
   3836   (declare (indent 1) (debug t))
   3837   `(with-temp-buffer
   3838      ;; Set the buffer's name to something under the root so that we can hack the local variables
   3839      ;; This file doesn't need to exist and will not be created due to this.
   3840      (setq-local buffer-file-name (expand-file-name "lsp-mode-temp" (expand-file-name ,workspace-root)))
   3841      (hack-local-variables)
   3842      (prog1 ,@body
   3843        (setq-local buffer-file-name nil))))
   3844 
   3845 (defun lsp--get-ignored-regexes-for-workspace-root (workspace-root)
   3846   "Return a list of the form
   3847 (lsp-file-watch-ignored-files lsp-file-watch-ignored-directories) for the given
   3848 WORKSPACE-ROOT."
   3849   ;; The intent of this function is to provide per-root workspace-level customization of the
   3850   ;; lsp-file-watch-ignored-directories and lsp-file-watch-ignored-files variables.
   3851   (lsp--with-workspace-temp-buffer workspace-root
   3852     (list lsp-file-watch-ignored-files (lsp-file-watch-ignored-directories))))
   3853 
   3854 
   3855 (defun lsp--cleanup-hanging-watches ()
   3856   "Cleanup watches in case there are no more workspaces that are interested
   3857 in that particular folder."
   3858   (let* ((session (lsp-session))
   3859          (watches (lsp-session-watches session)))
   3860     (dolist (watched-folder (ht-keys watches))
   3861       (when (-none? (lambda (workspace)
   3862                       (with-lsp-workspace workspace
   3863                         (lsp--registered-capability "workspace/didChangeWatchedFiles")))
   3864                     (gethash watched-folder (lsp-session-folder->servers (lsp-session))))
   3865         (lsp-log "Cleaning up watches for folder %s. There is no workspace watching this folder..." watched-folder)
   3866         (lsp-kill-watch (gethash watched-folder watches))
   3867         (remhash watched-folder watches)))))
   3868 
   3869 (lsp-defun lsp--server-unregister-capability ((&Unregistration :id :method))
   3870   "Unregister capability UNREG."
   3871   (setf (lsp--workspace-registered-server-capabilities lsp--cur-workspace)
   3872         (seq-remove (lambda (e) (equal (lsp--registered-capability-id e) id))
   3873                     (lsp--workspace-registered-server-capabilities lsp--cur-workspace)))
   3874   (when (equal method "workspace/didChangeWatchedFiles")
   3875     (lsp--cleanup-hanging-watches)))
   3876 
   3877 (defun lsp--server-capabilities ()
   3878   "Return the capabilities of the language server associated with the buffer."
   3879   (->> (lsp-workspaces)
   3880        (-keep #'lsp--workspace-server-capabilities)
   3881        (apply #'lsp-merge)))
   3882 
   3883 (defun lsp--send-open-close-p ()
   3884   "Return whether open and close notifications should be sent to the server."
   3885   (let ((sync (lsp:server-capabilities-text-document-sync? (lsp--server-capabilities))))
   3886     (or (memq sync '(1 2))
   3887         (lsp:text-document-sync-options-open-close? sync))))
   3888 
   3889 (defun lsp--send-will-save-p ()
   3890   "Return whether willSave notifications should be sent to the server."
   3891   (-> (lsp--server-capabilities)
   3892       (lsp:server-capabilities-text-document-sync?)
   3893       (lsp:text-document-sync-options-will-save?)))
   3894 
   3895 (defun lsp--send-will-save-wait-until-p ()
   3896   "Return whether willSaveWaitUntil notifications should be sent to the server."
   3897   (-> (lsp--server-capabilities)
   3898       (lsp:server-capabilities-text-document-sync?)
   3899       (lsp:text-document-sync-options-will-save-wait-until?)))
   3900 
   3901 (defun lsp--send-did-save-p ()
   3902   "Return whether didSave notifications should be sent to the server."
   3903   (let ((sync (lsp:server-capabilities-text-document-sync? (lsp--server-capabilities))))
   3904     (or (memq sync '(1 2))
   3905         (lsp:text-document-sync-options-save? sync))))
   3906 
   3907 (defun lsp--save-include-text-p ()
   3908   "Return whether save notifications should include the text document's contents."
   3909   (->> (lsp--server-capabilities)
   3910        (lsp:server-capabilities-text-document-sync?)
   3911        (lsp:text-document-sync-options-save?)
   3912        (lsp:text-document-save-registration-options-include-text?)))
   3913 
   3914 (defun lsp--send-will-rename-files-p (path)
   3915   "Return whether willRenameFiles request should be sent to the server.
   3916 If any filters, checks if it applies for PATH."
   3917   (let* ((will-rename (-> (lsp--server-capabilities)
   3918                           (lsp:server-capabilities-workspace?)
   3919                           (lsp:workspace-server-capabilities-file-operations?)
   3920                           (lsp:workspace-file-operations-will-rename?)))
   3921          (filters (seq-into (lsp:file-operation-registration-options-filters will-rename) 'list)))
   3922     (and will-rename
   3923          (or (seq-empty-p filters)
   3924              (-any? (-lambda ((&FileOperationFilter :scheme? :pattern (&FileOperationPattern :glob)))
   3925                       (-let [regexes (lsp-glob-to-regexps glob)]
   3926                         (and (or (not scheme?)
   3927                                  (string-prefix-p scheme? (lsp--path-to-uri path)))
   3928                              (-any? (lambda (re)
   3929                                       (string-match re path))
   3930                                     regexes))))
   3931                     filters)))))
   3932 
   3933 (defun lsp--send-did-rename-files-p ()
   3934   "Return whether didRenameFiles notification should be sent to the server."
   3935   (-> (lsp--server-capabilities)
   3936       (lsp:server-capabilities-workspace?)
   3937       (lsp:workspace-server-capabilities-file-operations?)
   3938       (lsp:workspace-file-operations-did-rename?)))
   3939 
   3940 (declare-function project-roots "ext:project" (project) t)
   3941 (declare-function project-root "ext:project" (project) t)
   3942 
   3943 (defun lsp--suggest-project-root ()
   3944   "Get project root."
   3945   (or
   3946    (when (fboundp 'projectile-project-root)
   3947      (condition-case nil
   3948          (projectile-project-root)
   3949        (error nil)))
   3950    (when (fboundp 'project-current)
   3951      (when-let ((project (project-current)))
   3952        (if (fboundp 'project-root)
   3953            (project-root project)
   3954          (car (with-no-warnings
   3955                 (project-roots project))))))
   3956    default-directory))
   3957 
   3958 (defun lsp--read-from-file (file)
   3959   "Read FILE content."
   3960   (when (file-exists-p file)
   3961     (cl-first (read-from-string (f-read-text file 'utf-8)))))
   3962 
   3963 (defun lsp--persist (file-name to-persist)
   3964   "Persist TO-PERSIST in FILE-NAME.
   3965 
   3966 This function creates the parent directories if they don't exist
   3967 yet."
   3968   (let ((print-length nil)
   3969         (print-level nil))
   3970     ;; Create all parent directories:
   3971     (make-directory (f-parent file-name) t)
   3972     (f-write-text (prin1-to-string to-persist) 'utf-8 file-name)))
   3973 
   3974 (defun lsp-workspace-folders-add (project-root)
   3975   "Add PROJECT-ROOT to the list of workspace folders."
   3976   (interactive
   3977    (list (read-directory-name "Select folder to add: "
   3978                               (or (lsp--suggest-project-root) default-directory) nil t)))
   3979   (cl-pushnew (lsp-f-canonical project-root)
   3980               (lsp-session-folders (lsp-session)) :test 'equal)
   3981   (lsp--persist-session (lsp-session))
   3982 
   3983   (run-hook-with-args 'lsp-workspace-folders-changed-functions (list project-root) nil))
   3984 
   3985 (defun lsp-workspace-folders-remove (project-root)
   3986   "Remove PROJECT-ROOT from the list of workspace folders."
   3987   (interactive (list (completing-read "Select folder to remove: "
   3988                                       (lsp-session-folders (lsp-session))
   3989                                       nil t nil nil
   3990                                       (lsp-find-session-folder (lsp-session) default-directory))))
   3991 
   3992   (setq project-root (lsp-f-canonical project-root))
   3993 
   3994   ;; send remove folder to each multiroot workspace associated with the folder
   3995   (dolist (wks (->> (lsp-session)
   3996                     (lsp-session-folder->servers)
   3997                     (gethash project-root)
   3998                     (--filter (lsp--client-multi-root (lsp--workspace-client it)))))
   3999     (with-lsp-workspace wks
   4000       (lsp-notify "workspace/didChangeWorkspaceFolders"
   4001                   (lsp-make-did-change-workspace-folders-params
   4002                    :event (lsp-make-workspace-folders-change-event
   4003                            :removed (vector (lsp-make-workspace-folder
   4004                                              :uri (lsp--path-to-uri project-root)
   4005                                              :name (f-filename project-root)))
   4006                            :added [])))))
   4007 
   4008   ;; turn off servers in the removed directory
   4009   (let* ((session (lsp-session))
   4010          (folder->servers (lsp-session-folder->servers session))
   4011          (server-id->folders (lsp-session-server-id->folders session))
   4012          (workspaces (gethash project-root folder->servers)))
   4013 
   4014     (remhash project-root folder->servers)
   4015 
   4016     ;; turn off the servers without root folders
   4017     (dolist (workspace workspaces)
   4018       (when (--none? (-contains? it workspace) (ht-values folder->servers))
   4019         (lsp--info "Shutdown %s since folder %s is removed..."
   4020                    (lsp--workspace-print workspace) project-root)
   4021         (with-lsp-workspace workspace (lsp--shutdown-workspace))))
   4022 
   4023     (setf (lsp-session-folders session)
   4024           (-remove-item project-root (lsp-session-folders session)))
   4025 
   4026     (ht-aeach (puthash key
   4027                        (-remove-item project-root value)
   4028                        server-id->folders)
   4029               server-id->folders)
   4030     (lsp--persist-session (lsp-session)))
   4031 
   4032   (run-hook-with-args 'lsp-workspace-folders-changed-functions nil (list project-root)))
   4033 
   4034 (defun lsp-workspace-blocklist-remove (project-root)
   4035   "Remove PROJECT-ROOT from the workspace blocklist."
   4036   (interactive (list (completing-read "Select folder to remove:"
   4037                                       (lsp-session-folders-blocklist (lsp-session))
   4038                                       nil t)))
   4039   (setf (lsp-session-folders-blocklist (lsp-session))
   4040         (delete project-root
   4041                 (lsp-session-folders-blocklist (lsp-session))))
   4042   (lsp--persist-session (lsp-session)))
   4043 
   4044 (define-obsolete-function-alias 'lsp-workspace-folders-switch
   4045   'lsp-workspace-folders-open "lsp-mode 6.1")
   4046 
   4047 (defun lsp-workspace-folders-open (project-root)
   4048   "Open the directory located at PROJECT-ROOT"
   4049   (interactive (list (completing-read "Open folder: "
   4050                                       (lsp-session-folders (lsp-session))
   4051                                       nil t)))
   4052   (find-file project-root))
   4053 
   4054 (defun lsp--maybe-enable-signature-help (trigger-characters)
   4055   (let ((ch last-command-event))
   4056     (when (cl-find ch trigger-characters :key #'string-to-char)
   4057       (lsp-signature-activate))))
   4058 
   4059 (defun lsp--on-type-formatting-handler-create ()
   4060   (when-let ((provider (lsp--capability-for-method "textDocument/onTypeFormatting" )))
   4061     (-let [(&DocumentOnTypeFormattingOptions :more-trigger-character?
   4062                                              :first-trigger-character) provider]
   4063       (lambda ()
   4064         (lsp--on-type-formatting first-trigger-character
   4065                                  more-trigger-character?)))))
   4066 
   4067 (defun lsp--update-on-type-formatting-hook (&optional cleanup?)
   4068   (let ((on-type-formatting-handler (lsp--on-type-formatting-handler-create)))
   4069     (cond
   4070      ((and lsp-enable-on-type-formatting on-type-formatting-handler (not cleanup?))
   4071       (add-hook 'post-self-insert-hook on-type-formatting-handler nil t))
   4072      ((or cleanup?
   4073           (not lsp-enable-on-type-formatting))
   4074       (remove-hook 'post-self-insert-hook on-type-formatting-handler t)))))
   4075 
   4076 (defun lsp--signature-help-handler-create ()
   4077   (-when-let ((&SignatureHelpOptions? :trigger-characters?)
   4078               (lsp--capability-for-method "textDocument/signatureHelp"))
   4079     (lambda ()
   4080       (lsp--maybe-enable-signature-help trigger-characters?))))
   4081 
   4082 (defun lsp--update-signature-help-hook (&optional cleanup?)
   4083   (let ((signature-help-handler (lsp--signature-help-handler-create)))
   4084     (cond
   4085      ((and (or (equal lsp-signature-auto-activate t)
   4086                (memq :on-trigger-char lsp-signature-auto-activate))
   4087            signature-help-handler)
   4088       (add-hook 'post-self-insert-hook signature-help-handler nil t))
   4089 
   4090      ((or cleanup?
   4091           (not (or (equal lsp-signature-auto-activate t)
   4092                    (memq :on-trigger-char lsp-signature-auto-activate))))
   4093       (remove-hook 'post-self-insert-hook signature-help-handler t)))))
   4094 
   4095 (defun lsp--after-set-visited-file-name ()
   4096   (lsp-disconnect)
   4097   (lsp))
   4098 
   4099 ;; TODO remove those eldoc workarounds when dropping support for Emacs 27
   4100 ;; https://github.com/emacs-lsp/lsp-mode/issues/3295#issuecomment-1308994099
   4101 (defvar eldoc-documentation-default) ; CI
   4102 (when (< emacs-major-version 28)
   4103   (unless (boundp 'eldoc-documentation-functions)
   4104     (load "eldoc" nil 'nomessage))
   4105   (when (memq (default-value 'eldoc-documentation-function) '(nil ignore))
   4106     ;; actually `eldoc-documentation-strategy', but CI was failing
   4107     (setq-default eldoc-documentation-function 'eldoc-documentation-default)))
   4108 
   4109 (define-minor-mode lsp-managed-mode
   4110   "Mode for source buffers managed by lsp-mode."
   4111   :lighter nil
   4112   (cond
   4113    (lsp-managed-mode
   4114     (when (lsp-feature? "textDocument/hover")
   4115       (add-hook 'eldoc-documentation-functions #'lsp-eldoc-function nil t)
   4116       (eldoc-mode 1))
   4117 
   4118     (add-hook 'after-change-functions #'lsp-on-change nil t)
   4119     (add-hook 'after-revert-hook #'lsp-on-revert nil t)
   4120     (add-hook 'after-save-hook #'lsp-on-save nil t)
   4121     (add-hook 'auto-save-hook #'lsp--on-auto-save nil t)
   4122     (add-hook 'before-change-functions #'lsp-before-change nil t)
   4123     (add-hook 'before-save-hook #'lsp--before-save nil t)
   4124     (add-hook 'kill-buffer-hook #'lsp--text-document-did-close nil t)
   4125     (add-hook 'post-command-hook #'lsp--post-command nil t)
   4126 
   4127     (lsp--update-on-type-formatting-hook)
   4128     (lsp--update-signature-help-hook)
   4129 
   4130     (when lsp-enable-xref
   4131       (add-hook 'xref-backend-functions #'lsp--xref-backend nil t))
   4132 
   4133     (lsp-configure-buffer)
   4134 
   4135     ;; make sure we turn off lsp-mode in case major mode changes, because major
   4136     ;; mode change will wipe the buffer locals.
   4137     (add-hook 'change-major-mode-hook #'lsp-disconnect nil t)
   4138     (add-hook 'after-set-visited-file-name-hook #'lsp--after-set-visited-file-name nil t)
   4139 
   4140     (let ((buffer (lsp-current-buffer)))
   4141       (run-with-idle-timer
   4142        0.0 nil
   4143        (lambda ()
   4144          (when (lsp-buffer-live-p buffer)
   4145            (lsp-with-current-buffer buffer
   4146              (lsp--on-change-debounce buffer)
   4147              (lsp--on-idle buffer)))))))
   4148    (t
   4149     (lsp-unconfig-buffer)
   4150 
   4151     (remove-hook 'eldoc-documentation-functions #'lsp-eldoc-function t)
   4152     (remove-hook 'post-command-hook #'lsp--post-command t)
   4153     (remove-hook 'after-change-functions #'lsp-on-change t)
   4154     (remove-hook 'after-revert-hook #'lsp-on-revert t)
   4155     (remove-hook 'after-save-hook #'lsp-on-save t)
   4156     (remove-hook 'auto-save-hook #'lsp--on-auto-save t)
   4157     (remove-hook 'before-change-functions #'lsp-before-change t)
   4158     (remove-hook 'before-save-hook #'lsp--before-save t)
   4159     (remove-hook 'kill-buffer-hook #'lsp--text-document-did-close t)
   4160 
   4161     (lsp--update-on-type-formatting-hook :cleanup)
   4162     (lsp--update-signature-help-hook :cleanup)
   4163 
   4164     (when lsp--on-idle-timer
   4165       (cancel-timer lsp--on-idle-timer)
   4166       (setq lsp--on-idle-timer nil))
   4167 
   4168     (remove-hook 'lsp-on-idle-hook #'lsp--document-links t)
   4169     (remove-hook 'lsp-on-idle-hook #'lsp--document-highlight t)
   4170 
   4171     (lsp--remove-overlays 'lsp-highlight)
   4172     (lsp--remove-overlays 'lsp-links)
   4173 
   4174     (remove-hook 'xref-backend-functions #'lsp--xref-backend t)
   4175     (remove-hook 'change-major-mode-hook #'lsp-disconnect t)
   4176     (remove-hook 'after-set-visited-file-name-hook #'lsp--after-set-visited-file-name t)
   4177     (setq-local lsp-buffer-uri nil))))
   4178 
   4179 (defun lsp-configure-buffer ()
   4180   "Configure LSP features for current buffer."
   4181   ;; make sure the core is running in the context of all available workspaces
   4182   ;; to avoid misconfiguration in case we are running in `with-lsp-workspace' context
   4183   (let ((lsp--buffer-workspaces (cond
   4184                                  (lsp--buffer-workspaces)
   4185                                  (lsp--cur-workspace (list lsp--cur-workspace))))
   4186         lsp--cur-workspace)
   4187     (when lsp-auto-configure
   4188       (lsp--auto-configure)
   4189 
   4190       (when (and lsp-enable-text-document-color
   4191                  (lsp-feature? "textDocument/documentColor"))
   4192         (add-hook 'lsp-on-change-hook #'lsp--document-color nil t))
   4193 
   4194       (when (and lsp-enable-imenu
   4195                  (lsp-feature? "textDocument/documentSymbol"))
   4196         (lsp-enable-imenu))
   4197 
   4198       (when (and lsp-enable-indentation
   4199                  (lsp-feature? "textDocument/rangeFormatting"))
   4200         (add-function :override (local 'indent-region-function) #'lsp-format-region))
   4201 
   4202       (when (and lsp-enable-symbol-highlighting
   4203                  (lsp-feature? "textDocument/documentHighlight"))
   4204         (add-hook 'lsp-on-idle-hook #'lsp--document-highlight nil t))
   4205 
   4206       (when (and lsp-enable-links
   4207                  (lsp-feature? "textDocument/documentLink"))
   4208         (add-hook 'lsp-on-idle-hook #'lsp--document-links nil t))
   4209 
   4210       (when (and lsp-inlay-hint-enable
   4211                  (lsp-feature? "textDocument/inlayHint"))
   4212         (lsp-inlay-hints-mode))
   4213 
   4214       (when (and lsp-enable-dap-auto-configure
   4215                  (functionp 'dap-mode))
   4216         (dap-auto-configure-mode 1)))
   4217     (run-hooks 'lsp-configure-hook)))
   4218 
   4219 (defun lsp-unconfig-buffer ()
   4220   "Unconfigure LSP features for buffer."
   4221   (lsp--remove-overlays 'lsp-color)
   4222 
   4223   (when (advice-function-member-p 'lsp--imenu-create-index imenu-create-index-function)
   4224     (remove-function (local 'imenu-create-index-function) #'lsp--imenu-create-index)
   4225     (setq-local imenu-menubar-modified-tick 0)
   4226     (setq-local imenu--index-alist nil)
   4227     (imenu--cleanup))
   4228 
   4229   (remove-function (local 'indent-region-function) #'lsp-format-region)
   4230 
   4231   (remove-hook 'lsp-on-change-hook #'lsp--document-color t)
   4232   (remove-hook 'lsp-on-idle-hook #'lsp--document-highlight t)
   4233   (remove-hook 'lsp-on-idle-hook #'lsp--document-links t)
   4234 
   4235   (when (and lsp-enable-dap-auto-configure
   4236              (functionp 'dap-mode))
   4237     (dap-auto-configure-mode -1))
   4238 
   4239   (run-hooks 'lsp-unconfigure-hook))
   4240 
   4241 (defun lsp--buffer-content ()
   4242   (lsp-save-restriction-and-excursion
   4243     (or (lsp-virtual-buffer-call :buffer-string)
   4244         (buffer-substring-no-properties (point-min)
   4245                                         (point-max)))))
   4246 
   4247 (defun lsp--text-document-did-open ()
   4248   "`document/didOpen' event."
   4249   (run-hooks 'lsp-before-open-hook)
   4250   (when (and lsp-auto-touch-files
   4251              (not (f-exists? (lsp--uri-to-path (lsp--buffer-uri)))))
   4252     (lsp--info "Saving file '%s' because it is not present on the disk." (lsp--buffer-uri))
   4253     (save-buffer))
   4254 
   4255   (setq lsp--cur-version (or lsp--cur-version 0))
   4256   (cl-pushnew (lsp-current-buffer) (lsp--workspace-buffers lsp--cur-workspace))
   4257   (lsp-notify
   4258    "textDocument/didOpen"
   4259    (list :textDocument
   4260          (list :uri (lsp--buffer-uri)
   4261                :languageId (lsp-buffer-language)
   4262                :version lsp--cur-version
   4263                :text (lsp--buffer-content))))
   4264 
   4265   (lsp-managed-mode 1)
   4266 
   4267   (run-hooks 'lsp-after-open-hook)
   4268   (when-let ((client (-some-> lsp--cur-workspace (lsp--workspace-client))))
   4269     (-some-> (lsp--client-after-open-fn client)
   4270       (funcall))
   4271     (-some-> (format "lsp-%s-after-open-hook" (lsp--client-server-id client))
   4272       (intern-soft)
   4273       (run-hooks))))
   4274 
   4275 (defun lsp--text-document-identifier ()
   4276   "Make TextDocumentIdentifier."
   4277   (list :uri (lsp--buffer-uri)))
   4278 
   4279 (defun lsp--versioned-text-document-identifier ()
   4280   "Make VersionedTextDocumentIdentifier."
   4281   (plist-put (lsp--text-document-identifier) :version lsp--cur-version))
   4282 
   4283 (defun lsp--cur-line (&optional point)
   4284   (1- (line-number-at-pos point)))
   4285 
   4286 (defun lsp--cur-position ()
   4287   "Make a Position object for the current point."
   4288   (or (lsp-virtual-buffer-call :cur-position)
   4289       (lsp-save-restriction-and-excursion
   4290         (list :line (lsp--cur-line)
   4291               :character (- (point) (line-beginning-position))))))
   4292 
   4293 (defun lsp--point-to-position (point)
   4294   "Convert POINT to Position."
   4295   (lsp-save-restriction-and-excursion
   4296     (goto-char point)
   4297     (lsp--cur-position)))
   4298 
   4299 (defun lsp--range (start end)
   4300   "Make Range body from START and END."
   4301   ;; make sure start and end are Position objects
   4302   (list :start start :end end))
   4303 
   4304 (defun lsp--region-to-range (start end)
   4305   "Make Range object for the current region."
   4306   (lsp--range (lsp--point-to-position start)
   4307               (lsp--point-to-position end)))
   4308 
   4309 (defun lsp--region-or-line ()
   4310   "The active region or the current line."
   4311   (if (use-region-p)
   4312       (lsp--region-to-range (region-beginning) (region-end))
   4313     (lsp--region-to-range (line-beginning-position) (line-end-position))))
   4314 
   4315 (defun lsp--check-document-changes-version (document-changes)
   4316   "Verify that DOCUMENT-CHANGES have the proper version."
   4317   (unless (seq-every-p
   4318            (-lambda ((&TextDocumentEdit :text-document))
   4319              (or
   4320               (not text-document)
   4321               (let* ((filename (-> text-document
   4322                                    lsp:versioned-text-document-identifier-uri
   4323                                    lsp--uri-to-path))
   4324                      (version (lsp:versioned-text-document-identifier-version? text-document)))
   4325                 (with-current-buffer (find-file-noselect filename)
   4326                   (or (null version) (zerop version) (= -1 version)
   4327                       (equal version lsp--cur-version))))))
   4328            document-changes)
   4329     (error "Document changes cannot be applied due to different document version")))
   4330 
   4331 (defun lsp--apply-workspace-edit (workspace-edit &optional operation)
   4332   "Apply the WorkspaceEdit object WORKSPACE-EDIT.
   4333 OPERATION is symbol representing the source of this text edit."
   4334   (-let (((&WorkspaceEdit :document-changes? :changes?) workspace-edit))
   4335     (if-let ((document-changes (seq-reverse document-changes?)))
   4336         (progn
   4337           (lsp--check-document-changes-version document-changes)
   4338           (->> document-changes
   4339                (seq-filter (-lambda ((&CreateFile :kind)) (equal kind "create")))
   4340                (seq-do (lambda (change) (lsp--apply-text-document-edit change operation))))
   4341           (->> document-changes
   4342                (seq-filter (-lambda ((&CreateFile :kind))
   4343                              (and (or (not kind) (equal kind "edit"))
   4344                                   (not (equal kind "create")))))
   4345                (seq-do (lambda (change) (lsp--apply-text-document-edit change operation))))
   4346           (->> document-changes
   4347                (seq-filter (-lambda ((&CreateFile :kind))
   4348                              (and (not (or (not kind) (equal kind "edit")))
   4349                                   (not (equal kind "create")))))
   4350                (seq-do (lambda (change) (lsp--apply-text-document-edit change operation)))))
   4351       (lsp-map
   4352        (lambda (uri text-edits)
   4353          (with-current-buffer (-> uri lsp--uri-to-path find-file-noselect)
   4354            (lsp--apply-text-edits text-edits operation)))
   4355        changes?))))
   4356 
   4357 (defmacro lsp-with-filename (file &rest body)
   4358   "Execute BODY with FILE as a context.
   4359 Need to handle the case when FILE indicates virtual buffer."
   4360   (declare (indent 1) (debug t))
   4361   `(if-let ((lsp--virtual-buffer (get-text-property 0 'lsp-virtual-buffer ,file)))
   4362        (lsp-with-current-buffer lsp--virtual-buffer
   4363          ,@body)
   4364      ,@body))
   4365 
   4366 (defun lsp--apply-text-document-edit (edit &optional operation)
   4367   "Apply the TextDocumentEdit object EDIT.
   4368 OPERATION is symbol representing the source of this text edit.
   4369 If the file is not being visited by any buffer, it is opened with
   4370 `find-file-noselect'.
   4371 Because lsp-mode does not store previous document versions, the edit is only
   4372 applied if the version of the textDocument matches the version of the
   4373 corresponding file.
   4374 
   4375 interface TextDocumentEdit {
   4376   textDocument: VersionedTextDocumentIdentifier;
   4377   edits: TextEdit[];
   4378 }"
   4379   (pcase (lsp:edit-kind edit)
   4380     ("create" (-let* (((&CreateFile :uri :options?) edit)
   4381                       (file-name (lsp--uri-to-path uri)))
   4382                 (mkdir (f-dirname file-name) t)
   4383                 (f-touch file-name)
   4384                 (when (lsp:create-file-options-overwrite? options?)
   4385                   (f-write-text "" nil file-name))
   4386                 (find-file-noselect file-name)))
   4387     ("delete" (-let (((&DeleteFile :uri :options? (&DeleteFileOptions? :recursive?)) edit))
   4388                 (f-delete (lsp--uri-to-path uri) recursive?)))
   4389     ("rename" (-let* (((&RenameFile :old-uri :new-uri :options? (&RenameFileOptions? :overwrite?)) edit)
   4390                       (old-file-name (lsp--uri-to-path old-uri))
   4391                       (new-file-name (lsp--uri-to-path new-uri))
   4392                       (buf (find-buffer-visiting old-file-name)))
   4393                 (when buf
   4394                   (lsp-with-current-buffer buf
   4395                     (save-buffer)
   4396                     (lsp--text-document-did-close)))
   4397                 (mkdir (f-dirname new-file-name) t)
   4398                 (rename-file old-file-name new-file-name overwrite?)
   4399                 (when buf
   4400                   (lsp-with-current-buffer buf
   4401                     (set-buffer-modified-p nil)
   4402                     (setq lsp-buffer-uri nil)
   4403                     (set-visited-file-name new-file-name)
   4404                     (lsp)))))
   4405     (_ (let ((file-name (->> edit
   4406                              (lsp:text-document-edit-text-document)
   4407                              (lsp:versioned-text-document-identifier-uri)
   4408                              (lsp--uri-to-path))))
   4409          (lsp-with-current-buffer (find-buffer-visiting file-name)
   4410            (lsp-with-filename file-name
   4411              (lsp--apply-text-edits (lsp:text-document-edit-edits edit) operation)))))))
   4412 
   4413 (lsp-defun lsp--position-compare ((&Position :line left-line
   4414                                              :character left-character)
   4415                                   (&Position :line right-line
   4416                                              :character right-character))
   4417   "Return t if position LEFT is greater than RIGHT."
   4418   (if (= left-line right-line)
   4419       (> left-character right-character)
   4420     (> left-line right-line)))
   4421 
   4422 (lsp-defun lsp-point-in-range? (position (&Range :start :end))
   4423   "Returns if POINT is in RANGE."
   4424   (not (or (lsp--position-compare start position)
   4425            (lsp--position-compare position end))))
   4426 
   4427 (lsp-defun lsp--position-equal ((&Position :line left-line
   4428                                            :character left-character)
   4429                                 (&Position :line right-line
   4430                                            :character right-character))
   4431   "Return whether LEFT and RIGHT positions are equal."
   4432   (and (= left-line right-line)
   4433        (= left-character right-character)))
   4434 
   4435 (lsp-defun lsp--text-edit-sort-predicate ((&TextEdit :range (&Range :start left-start :end left-end))
   4436                                           (&TextEdit :range (&Range :start right-start :end right-end)))
   4437   (if (lsp--position-equal left-start right-start)
   4438       (lsp--position-compare left-end right-end)
   4439     (lsp--position-compare left-start right-start)))
   4440 
   4441 (lsp-defun lsp--apply-text-edit ((edit &as &TextEdit :range (&RangeToPoint :start :end) :new-text))
   4442   "Apply the edits described in the TextEdit object in TEXT-EDIT."
   4443   (setq new-text (s-replace "\r" "" (or new-text "")))
   4444   (lsp:set-text-edit-new-text edit new-text)
   4445   (goto-char start)
   4446   (delete-region start end)
   4447   (insert new-text))
   4448 
   4449 ;; WORKAROUND: typescript-language might send -1 when applying code actions.
   4450 ;; see https://github.com/emacs-lsp/lsp-mode/issues/1582
   4451 (lsp-defun lsp--fix-point ((point &as &Position :character :line))
   4452   (-doto point
   4453     (lsp:set-position-line (max 0 line))
   4454     (lsp:set-position-character (max 0 character))))
   4455 
   4456 (lsp-defun lsp--apply-text-edit-replace-buffer-contents ((edit &as
   4457                                                                &TextEdit
   4458                                                                :range (&Range :start :end)
   4459                                                                :new-text))
   4460   "Apply the edits described in the TextEdit object in TEXT-EDIT.
   4461 The method uses `replace-buffer-contents'."
   4462   (setq new-text (s-replace "\r" "" (or new-text "")))
   4463   (lsp:set-text-edit-new-text edit new-text)
   4464   (-let* ((source (current-buffer))
   4465           ((beg . end) (lsp--range-to-region (lsp-make-range :start (lsp--fix-point start)
   4466                                                              :end (lsp--fix-point end)))))
   4467     (with-temp-buffer
   4468       (insert new-text)
   4469       (let ((temp (current-buffer)))
   4470         (with-current-buffer source
   4471           (save-excursion
   4472             (save-restriction
   4473               (narrow-to-region beg end)
   4474 
   4475               ;; On emacs versions < 26.2,
   4476               ;; `replace-buffer-contents' is buggy - it calls
   4477               ;; change functions with invalid arguments - so we
   4478               ;; manually call the change functions here.
   4479               ;;
   4480               ;; See emacs bugs #32237, #32278:
   4481               ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32237
   4482               ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32278
   4483               (let ((inhibit-modification-hooks t)
   4484                     (length (- end beg)))
   4485                 (run-hook-with-args 'before-change-functions
   4486                                     beg end)
   4487                 (replace-buffer-contents temp)
   4488                 (run-hook-with-args 'after-change-functions
   4489                                     beg (+ beg (length new-text))
   4490                                     length)))))))))
   4491 
   4492 (defun lsp--to-yasnippet-snippet (snippet)
   4493   "Convert LSP SNIPPET to yasnippet snippet."
   4494   ;; LSP snippet doesn't escape "{" and "`", but yasnippet requires escaping it.
   4495   (replace-regexp-in-string (rx (or bos (not (any "$" "\\"))) (group (or "{" "`")))
   4496                             (rx "\\" (backref 1))
   4497                             snippet
   4498                             nil nil 1))
   4499 
   4500 (defvar-local lsp-enable-relative-indentation nil
   4501   "Enable relative indentation when insert texts, snippets ...
   4502 from language server.")
   4503 
   4504 (defun lsp--expand-snippet (snippet &optional start end expand-env)
   4505   "Wrapper of `yas-expand-snippet' with all of it arguments.
   4506 The snippet will be convert to LSP style and indent according to
   4507 LSP server result."
   4508   (require 'yasnippet nil t)
   4509   (let* ((inhibit-field-text-motion t)
   4510          (yas-wrap-around-region nil)
   4511          (yas-indent-line 'none)
   4512          (yas-also-auto-indent-first-line nil))
   4513     (yas-expand-snippet
   4514      (lsp--to-yasnippet-snippet snippet)
   4515      start end expand-env)))
   4516 
   4517 (defun lsp--indent-lines (start end &optional insert-text-mode?)
   4518   "Indent from START to END based on INSERT-TEXT-MODE? value.
   4519 - When INSERT-TEXT-MODE? is provided
   4520   - if it's `lsp/insert-text-mode-as-it', do no editor indentation.
   4521   - if it's `lsp/insert-text-mode-adjust-indentation', adjust leading
   4522     whitespaces to match the line where text is inserted.
   4523 - When it's not provided, using `indent-line-function' for each line."
   4524   (save-excursion
   4525     (goto-char end)
   4526     (let* ((end-line (line-number-at-pos))
   4527            (offset (save-excursion
   4528                      (goto-char start)
   4529                      (current-indentation)))
   4530            (indent-line-function
   4531             (cond ((equal insert-text-mode? lsp/insert-text-mode-as-it)
   4532                    #'ignore)
   4533                   ((or (equal insert-text-mode? lsp/insert-text-mode-adjust-indentation)
   4534                        lsp-enable-relative-indentation
   4535                        ;; Indenting snippets is extremely slow in `org-mode' buffers
   4536                        ;; since it has to calculate indentation based on SRC block
   4537                        ;; position.  Thus we use relative indentation as default.
   4538                        (derived-mode-p 'org-mode))
   4539                    (lambda () (save-excursion
   4540                                 (beginning-of-line)
   4541                                 (indent-to-column offset))))
   4542                   (t indent-line-function))))
   4543       (goto-char start)
   4544       (forward-line)
   4545       (while (and (not (eobp))
   4546                   (<= (line-number-at-pos) end-line))
   4547         (funcall indent-line-function)
   4548         (forward-line)))))
   4549 
   4550 (defun lsp--apply-text-edits (edits &optional operation)
   4551   "Apply the EDITS described in the TextEdit[] object.
   4552 OPERATION is symbol representing the source of this text edit."
   4553   (unless (seq-empty-p edits)
   4554     (atomic-change-group
   4555       (run-hooks 'lsp-before-apply-edits-hook)
   4556       (let* ((change-group (prepare-change-group))
   4557              (howmany (length edits))
   4558              (message (format "Applying %s edits to `%s' ..." howmany (current-buffer)))
   4559              (_ (lsp--info message))
   4560              (reporter (make-progress-reporter message 0 howmany))
   4561              (done 0)
   4562              (apply-edit (if (not lsp--virtual-buffer)
   4563                              #'lsp--apply-text-edit-replace-buffer-contents
   4564                            #'lsp--apply-text-edit)))
   4565         (unwind-protect
   4566             (->> edits
   4567                  ;; We sort text edits so as to apply edits that modify latter
   4568                  ;; parts of the document first. Furthermore, because the LSP
   4569                  ;; spec dictates that: "If multiple inserts have the same
   4570                  ;; position, the order in the array defines which edit to
   4571                  ;; apply first."  We reverse the initial list and sort stably
   4572                  ;; to make sure the order among edits with the same position
   4573                  ;; is preserved.
   4574                  (nreverse)
   4575                  (seq-sort #'lsp--text-edit-sort-predicate)
   4576                  (mapc (lambda (edit)
   4577                          (progress-reporter-update reporter (cl-incf done))
   4578                          (funcall apply-edit edit)
   4579                          (when (lsp:snippet-text-edit-insert-text-format? edit)
   4580                            (-when-let ((&SnippetTextEdit :range (&RangeToPoint :start)
   4581                                                          :insert-text-format? :new-text) edit)
   4582                              (when (eq insert-text-format? lsp/insert-text-format-snippet)
   4583                                ;; No `save-excursion' needed since expand snippet will change point anyway
   4584                                (goto-char (+ start (length new-text)))
   4585                                (lsp--indent-lines start (point))
   4586                                (lsp--expand-snippet new-text start (point)))))
   4587                          (run-hook-with-args 'lsp-after-apply-edits-hook operation))))
   4588           (undo-amalgamate-change-group change-group)
   4589           (progress-reporter-done reporter))))))
   4590 
   4591 (defun lsp--create-apply-text-edits-handlers ()
   4592   "Create (handler cleanup-fn) for applying text edits in async request.
   4593 Only works when mode is `tick or `alive."
   4594   (let* (first-edited
   4595          (func (lambda (start &rest _)
   4596                  (setq first-edited (if first-edited
   4597                                         (min start first-edited)
   4598                                       start)))))
   4599     (add-hook 'before-change-functions func nil t)
   4600     (list
   4601      (lambda (edits)
   4602        (if (and first-edited
   4603                 (seq-find (-lambda ((&TextEdit :range (&RangeToPoint :end)))
   4604                             ;; Text edit region is overlapped
   4605                             (> end first-edited))
   4606                           edits))
   4607            (lsp--warn "TextEdits will not be applied since document has been modified before of them.")
   4608          (lsp--apply-text-edits edits 'completion-cleanup)))
   4609      (lambda ()
   4610        (remove-hook 'before-change-functions func t)))))
   4611 
   4612 (defun lsp--capability (cap &optional capabilities)
   4613   "Get the value of capability CAP.  If CAPABILITIES is non-nil, use them instead."
   4614   (when (stringp cap)
   4615     (setq cap (intern (concat ":" cap))))
   4616 
   4617   (lsp-get (or capabilities
   4618                (lsp--server-capabilities))
   4619            cap))
   4620 
   4621 (defun lsp--registered-capability (method)
   4622   "Check whether there is workspace providing METHOD."
   4623   (->> (lsp-workspaces)
   4624        (--keep (seq-find (lambda (reg)
   4625                            (equal (lsp--registered-capability-method reg) method))
   4626                          (lsp--workspace-registered-server-capabilities it)))
   4627        cl-first))
   4628 
   4629 (defun lsp--capability-for-method (method)
   4630   "Get the value of capability for METHOD."
   4631   (-let* ((reqs (cdr (assoc method lsp-method-requirements)))
   4632           ((&plist :capability) reqs))
   4633     (or (and capability (lsp--capability capability))
   4634         (-some-> (lsp--registered-capability method)
   4635           (lsp--registered-capability-options)))))
   4636 
   4637 (defvar-local lsp--before-change-vals nil
   4638   "Store the positions from the `lsp-before-change' function call, for
   4639 validation and use in the `lsp-on-change' function.")
   4640 
   4641 (defun lsp--text-document-content-change-event (start end length)
   4642   "Make a TextDocumentContentChangeEvent body for START to END, of length LENGTH."
   4643   ;; So (47 54 0) means add    7 chars starting at pos 47
   4644   ;; must become
   4645   ;;   {"range":{"start":{"line":5,"character":6}
   4646   ;;             ,"end" :{"line":5,"character":6}}
   4647   ;;             ,"rangeLength":0
   4648   ;;             ,"text":"\nbb = 5"}
   4649   ;;
   4650   ;; And (47 47 7) means delete 7 chars starting at pos 47
   4651   ;; must become
   4652   ;;   {"range":{"start":{"line":6,"character":0}
   4653   ;;            ,"end"  :{"line":7,"character":0}}
   4654   ;;            ,"rangeLength":7
   4655   ;;            ,"text":""}
   4656   ;;
   4657   ;; (208 221 3) means delete 3 chars starting at pos 208, and replace them with
   4658   ;; 13 chars. So it must become
   4659   ;;   {"range":{"start":{"line":5,"character":8}
   4660   ;;             ,"end" :{"line":5,"character":11}}
   4661   ;;             ,"rangeLength":3
   4662   ;;             ,"text":"new-chars-xxx"}
   4663   ;;
   4664 
   4665   ;; Adding text:
   4666   ;;   lsp-before-change:(start,end)=(33,33)
   4667   ;;   lsp-on-change:(start,end,length)=(33,34,0)
   4668   ;;
   4669   ;; Changing text:
   4670   ;;   lsp-before-change:(start,end)=(208,211)
   4671   ;;   lsp-on-change:(start,end,length)=(208,221,3)
   4672   ;;
   4673   ;; Deleting text:
   4674   ;;   lsp-before-change:(start,end)=(19,27)
   4675   ;;   lsp-on-change:(start,end,length)=(19,19,8)
   4676   (if (zerop length)
   4677       ;; Adding something only, work from start only
   4678       `( :range ,(lsp--range
   4679                   (lsp--point-to-position start)
   4680                   (lsp--point-to-position start))
   4681          :rangeLength 0
   4682          :text ,(buffer-substring-no-properties start end))
   4683 
   4684     (if (eq start end)
   4685         ;; Deleting something only
   4686         (if (lsp--bracketed-change-p start length)
   4687             ;; The before-change value is bracketed, use it
   4688             `( :range ,(lsp--range
   4689                         (lsp--point-to-position start)
   4690                         (plist-get lsp--before-change-vals :end-pos))
   4691                :rangeLength ,length
   4692                :text "")
   4693           ;; If the change is not bracketed, send a full change event instead.
   4694           (lsp--full-change-event))
   4695 
   4696       ;; Deleting some things, adding others
   4697       (if (lsp--bracketed-change-p start length)
   4698           ;; The before-change value is valid, use it
   4699           `( :range ,(lsp--range
   4700                       (lsp--point-to-position start)
   4701                       (plist-get lsp--before-change-vals :end-pos))
   4702              :rangeLength ,length
   4703              :text ,(buffer-substring-no-properties start end))
   4704         (lsp--full-change-event)))))
   4705 
   4706 (defun lsp--bracketed-change-p (start length)
   4707   "If the before and after positions are the same, and the length
   4708 is the size of the start range, we are probably good."
   4709   (-let [(&plist :end before-end :start before-start) lsp--before-change-vals]
   4710     (and (eq start before-start)
   4711          (eq length (- before-end before-start)))))
   4712 
   4713 (defun lsp--full-change-event ()
   4714   `(:text ,(lsp--buffer-content)))
   4715 
   4716 (defun lsp-before-change (start end)
   4717   "Executed before a file is changed.
   4718 Added to `before-change-functions'."
   4719   ;; Note:
   4720   ;;
   4721   ;; This variable holds a list of functions to call when Emacs is about to
   4722   ;; modify a buffer. Each function gets two arguments, the beginning and end of
   4723   ;; the region that is about to change, represented as integers. The buffer
   4724   ;; that is about to change is always the current buffer when the function is
   4725   ;; called.
   4726   ;;
   4727   ;; WARNING:
   4728   ;;
   4729   ;; Do not expect the before-change hooks and the after-change hooks be called
   4730   ;; in balanced pairs around each buffer change. Also don't expect the
   4731   ;; before-change hooks to be called for every chunk of text Emacs is about to
   4732   ;; delete. These hooks are provided on the assumption that Lisp programs will
   4733   ;; use either before- or the after-change hooks, but not both, and the
   4734   ;; boundaries of the region where the changes happen might include more than
   4735   ;; just the actual changed text, or even lump together several changes done
   4736   ;; piecemeal.
   4737   (save-match-data
   4738     (lsp-save-restriction-and-excursion
   4739       (setq lsp--before-change-vals
   4740             (list :start start
   4741                   :end end
   4742                   :end-pos (lsp--point-to-position end))))))
   4743 
   4744 (defun lsp--flush-delayed-changes ()
   4745   (let ((inhibit-quit t))
   4746     (when lsp--delay-timer
   4747       (cancel-timer lsp--delay-timer))
   4748     (mapc (-lambda ((workspace buffer document change))
   4749             (with-current-buffer buffer
   4750               (with-lsp-workspace workspace
   4751                 (lsp-notify "textDocument/didChange"
   4752                             (list :textDocument document
   4753                                   :contentChanges (vector change))))))
   4754           (prog1 (nreverse lsp--delayed-requests)
   4755             (setq lsp--delayed-requests nil)))))
   4756 
   4757 (defun lsp--workspace-sync-method (workspace)
   4758   (let ((sync (-> workspace
   4759                   (lsp--workspace-server-capabilities)
   4760                   (lsp:server-capabilities-text-document-sync?))))
   4761     (if (lsp-text-document-sync-options? sync)
   4762         (lsp:text-document-sync-options-change? sync)
   4763       sync)))
   4764 
   4765 (defun lsp-on-change (start end length &optional content-change-event-fn)
   4766   "Executed when a file is changed.
   4767 Added to `after-change-functions'."
   4768   ;; Note:
   4769   ;;
   4770   ;; Each function receives three arguments: the beginning and end of the region
   4771   ;; just changed, and the length of the text that existed before the change.
   4772   ;; All three arguments are integers. The buffer that has been changed is
   4773   ;; always the current buffer when the function is called.
   4774   ;;
   4775   ;; The length of the old text is the difference between the buffer positions
   4776   ;; before and after that text as it was before the change. As for the
   4777   ;; changed text, its length is simply the difference between the first two
   4778   ;; arguments.
   4779   ;;
   4780   ;; So (47 54 0) means add    7 chars starting at pos 47
   4781   ;; So (47 47 7) means delete 7 chars starting at pos 47
   4782   (save-match-data
   4783     (let ((inhibit-quit t)
   4784           ;; make sure that `lsp-on-change' is called in multi-workspace context
   4785           ;; see #2901
   4786           lsp--cur-workspace)
   4787       ;; A (revert-buffer) call with the 'preserve-modes parameter (eg, as done
   4788       ;; by auto-revert-mode) will cause this handler to get called with a nil
   4789       ;; buffer-file-name. We need the buffer-file-name to send notifications;
   4790       ;; so we skip handling revert-buffer-caused changes and instead handle
   4791       ;; reverts separately in lsp-on-revert
   4792       (when (not revert-buffer-in-progress-p)
   4793         (cl-incf lsp--cur-version)
   4794         (mapc
   4795          (lambda (workspace)
   4796            (pcase (or lsp-document-sync-method
   4797                       (lsp--workspace-sync-method workspace))
   4798              (1
   4799               (if lsp-debounce-full-sync-notifications
   4800                   (setq lsp--delayed-requests
   4801                         (->> lsp--delayed-requests
   4802                              (-remove (-lambda ((_ buffer))
   4803                                         (equal (current-buffer) buffer)))
   4804                              (cons (list workspace
   4805                                          (current-buffer)
   4806                                          (lsp--versioned-text-document-identifier)
   4807                                          (lsp--full-change-event)))))
   4808                 (with-lsp-workspace workspace
   4809                   (lsp-notify "textDocument/didChange"
   4810                               (list :contentChanges (vector (lsp--full-change-event))
   4811                                     :textDocument (lsp--versioned-text-document-identifier))))))
   4812              (2
   4813               (with-lsp-workspace workspace
   4814                 (lsp-notify
   4815                  "textDocument/didChange"
   4816                  (list :textDocument (lsp--versioned-text-document-identifier)
   4817                        :contentChanges (vector
   4818                                         (if content-change-event-fn
   4819                                             (funcall content-change-event-fn start end length)
   4820                                           (lsp--text-document-content-change-event
   4821                                            start end length)))))))))
   4822          (lsp-workspaces))
   4823         (when lsp--delay-timer (cancel-timer lsp--delay-timer))
   4824         (setq lsp--delay-timer (run-with-idle-timer
   4825                                 lsp-debounce-full-sync-notifications-interval
   4826                                 nil
   4827                                 #'lsp--flush-delayed-changes))
   4828         ;; force cleanup overlays after each change
   4829         (lsp--remove-overlays 'lsp-highlight)
   4830         (lsp--after-change (current-buffer))
   4831         (setq lsp--signature-last-index nil
   4832               lsp--signature-last nil)
   4833         ;; cleanup diagnostics
   4834         (when lsp-diagnostic-clean-after-change
   4835           (lsp-foreach-workspace
   4836            (-let [diagnostics (lsp--workspace-diagnostics lsp--cur-workspace)]
   4837              (remhash (lsp--fix-path-casing (buffer-file-name)) diagnostics))))))))
   4838 
   4839 
   4840 
   4841 ;; facilities for on change hooks. We do not want to make lsp calls on each
   4842 ;; change event so we add debounce to avoid flooding the server with events.
   4843 ;; Additionally, we want to have a mechanism for stopping the server calls in
   4844 ;; particular cases like, e. g. when performing completion.
   4845 
   4846 (defvar lsp-inhibit-lsp-hooks nil
   4847   "Flag to control.")
   4848 
   4849 (defcustom lsp-on-change-hook nil
   4850   "Hooks to run when buffer has changed."
   4851   :type 'hook
   4852   :group 'lsp-mode)
   4853 
   4854 (defcustom lsp-idle-delay 0.500
   4855   "Debounce interval for `after-change-functions'."
   4856   :type 'number
   4857   :group 'lsp-mode)
   4858 
   4859 (defcustom lsp-on-idle-hook nil
   4860   "Hooks to run after `lsp-idle-delay'."
   4861   :type 'hook
   4862   :group 'lsp-mode)
   4863 
   4864 (defun lsp--idle-reschedule (buffer)
   4865   (when lsp--on-idle-timer
   4866     (cancel-timer lsp--on-idle-timer))
   4867 
   4868   (setq lsp--on-idle-timer (run-with-idle-timer
   4869                             lsp-idle-delay
   4870                             nil
   4871                             #'lsp--on-idle
   4872                             buffer)))
   4873 
   4874 (defun lsp--post-command ()
   4875   (lsp--cleanup-highlights-if-needed)
   4876   (lsp--idle-reschedule (current-buffer)))
   4877 
   4878 (defun lsp--on-idle (buffer)
   4879   "Start post command loop."
   4880   (when (and (buffer-live-p buffer)
   4881              (equal buffer (current-buffer))
   4882              (not lsp-inhibit-lsp-hooks)
   4883              lsp-managed-mode)
   4884     (run-hooks 'lsp-on-idle-hook)))
   4885 
   4886 (defun lsp--on-change-debounce (buffer)
   4887   (when (and (buffer-live-p buffer)
   4888              (equal buffer (current-buffer))
   4889              (not lsp-inhibit-lsp-hooks)
   4890              lsp-managed-mode)
   4891     (run-hooks 'lsp-on-change-hook)))
   4892 
   4893 (defun lsp--after-change (buffer)
   4894   (when (fboundp 'lsp--semantic-tokens-refresh-if-enabled)
   4895     (lsp--semantic-tokens-refresh-if-enabled buffer))
   4896   (when lsp--on-change-timer
   4897     (cancel-timer lsp--on-change-timer))
   4898   (setq lsp--on-change-timer (run-with-idle-timer
   4899                               lsp-idle-delay
   4900                               nil
   4901                               #'lsp--on-change-debounce
   4902                               buffer))
   4903   (lsp--idle-reschedule buffer))
   4904 
   4905 
   4906 (defcustom lsp-trim-trailing-whitespace t
   4907   "Trim trailing whitespace on a line."
   4908   :group 'lsp-mode
   4909   :type 'boolean)
   4910 
   4911 (defcustom lsp-insert-final-newline t
   4912   "Insert a newline character at the end of the file if one does not exist."
   4913   :group 'lsp-mode
   4914   :type 'boolean)
   4915 
   4916 (defcustom lsp-trim-final-newlines t
   4917   "Trim all newlines after the final newline at the end of the file."
   4918   :group 'lsp-mode
   4919   :type 'boolean)
   4920 
   4921 
   4922 (defun lsp--on-type-formatting (first-trigger-characters more-trigger-characters)
   4923   "Self insert handling.
   4924 Applies on type formatting."
   4925   (let ((ch last-command-event))
   4926     (when (or (eq (string-to-char first-trigger-characters) ch)
   4927               (cl-find ch more-trigger-characters :key #'string-to-char))
   4928       (lsp-request-async "textDocument/onTypeFormatting"
   4929                          (lsp-make-document-on-type-formatting-params
   4930                           :text-document (lsp--text-document-identifier)
   4931                           :options (lsp-make-formatting-options
   4932                                     :tab-size (symbol-value (lsp--get-indent-width major-mode))
   4933                                     :insert-spaces (lsp-json-bool (not indent-tabs-mode))
   4934                                     :trim-trailing-whitespace? (lsp-json-bool lsp-trim-trailing-whitespace)
   4935                                     :insert-final-newline? (lsp-json-bool lsp-insert-final-newline)
   4936                                     :trim-final-newlines? (lsp-json-bool lsp-trim-final-newlines))
   4937                           :ch (char-to-string ch)
   4938                           :position (lsp--cur-position))
   4939                          (lambda (data) (lsp--apply-text-edits data 'format))
   4940                          :mode 'tick))))
   4941 
   4942 
   4943 ;; links
   4944 (defun lsp--document-links ()
   4945   (when (lsp-feature? "textDocument/documentLink")
   4946     (lsp-request-async
   4947      "textDocument/documentLink"
   4948      `(:textDocument ,(lsp--text-document-identifier))
   4949      (lambda (links)
   4950        (lsp--remove-overlays 'lsp-link)
   4951        (seq-do
   4952         (-lambda ((link &as &DocumentLink :range (&Range :start :end)))
   4953           (-doto (make-button (lsp--position-to-point start)
   4954                               (lsp--position-to-point end)
   4955                               'action (lsp--document-link-keymap link)
   4956                               'keymap (let ((map (make-sparse-keymap)))
   4957                                         (define-key map [M-return] 'push-button)
   4958                                         (define-key map [mouse-2] 'push-button)
   4959                                         map)
   4960                               'help-echo "mouse-2, M-RET: Visit this link")
   4961             (overlay-put 'lsp-link t)))
   4962         links))
   4963      :mode 'unchanged)))
   4964 
   4965 (defun lsp--document-link-handle-target (url)
   4966   (let* ((parsed-url (url-generic-parse-url (url-unhex-string url)))
   4967          (type (url-type parsed-url)))
   4968     (pcase type
   4969       ("file"
   4970        (xref-push-marker-stack)
   4971        (find-file (lsp--uri-to-path url))
   4972        (-when-let ((_ line column) (s-match (rx "#" (group (1+ num)) (or "," "#") (group (1+ num))) url))
   4973          (goto-char (lsp--position-to-point
   4974                      (lsp-make-position :character (1- (string-to-number column))
   4975                                         :line (1- (string-to-number line)))))))
   4976       ((or "http" "https") (browse-url url))
   4977       (type (if-let ((handler (lsp--get-uri-handler type)))
   4978                 (funcall handler url)
   4979               (signal 'lsp-file-scheme-not-supported (list url)))))))
   4980 
   4981 (lsp-defun lsp--document-link-keymap ((link &as &DocumentLink :target?))
   4982   (if target?
   4983       (lambda (_)
   4984         (interactive)
   4985         (lsp--document-link-handle-target target?))
   4986     (lambda (_)
   4987       (interactive)
   4988       (when (lsp:document-link-registration-options-resolve-provider?
   4989              (lsp--capability-for-method "textDocument/documentLink"))
   4990         (lsp-request-async
   4991          "documentLink/resolve"
   4992          link
   4993          (-lambda ((&DocumentLink :target?))
   4994            (lsp--document-link-handle-target target?)))))))
   4995 
   4996 
   4997 
   4998 (defcustom lsp-warn-no-matched-clients t
   4999   "Whether to show messages when there are no supported clients."
   5000   :group 'lsp-mode
   5001   :type 'boolean)
   5002 
   5003 (defun lsp-buffer-language--configured-id ()
   5004   "Return nil when not registered."
   5005   (->> lsp-language-id-configuration
   5006        (-first
   5007         (-lambda ((mode-or-pattern . language))
   5008           (cond
   5009            ((and (stringp mode-or-pattern)
   5010                  (s-matches? mode-or-pattern (buffer-file-name)))
   5011             language)
   5012            ((eq mode-or-pattern major-mode) language))))
   5013        cl-rest))
   5014 
   5015 (defvar-local lsp--buffer-language nil
   5016   "Locally cached returned value of `lsp-buffer-language'.")
   5017 
   5018 (defun lsp-buffer-language ()
   5019   "Get language corresponding current buffer."
   5020   (or lsp--buffer-language
   5021       (let* ((configured-language (lsp-buffer-language--configured-id)))
   5022         (setq lsp--buffer-language
   5023               (or configured-language
   5024                   ;; ensure non-nil
   5025                   (string-remove-suffix "-mode" (symbol-name major-mode))))
   5026         (when (and lsp-warn-no-matched-clients
   5027                    (null configured-language))
   5028           (lsp-warn "Unable to calculate the languageId for buffer `%s'. \
   5029 Take a look at `lsp-language-id-configuration'. The `major-mode' is %s"
   5030                     (buffer-name)
   5031                     major-mode))
   5032         lsp--buffer-language)))
   5033 
   5034 (defun lsp-activate-on (&rest languages)
   5035   "Returns language activation function.
   5036 The function will return t when the `lsp-buffer-language' returns
   5037 one of the LANGUAGES."
   5038   (lambda (_file-name _mode)
   5039     (-contains? languages (lsp-buffer-language))))
   5040 
   5041 (defun lsp-workspace-root (&optional path)
   5042   "Find the workspace root for the current file or PATH."
   5043   (-when-let* ((file-name (or path (buffer-file-name)))
   5044                (file-name (lsp-f-canonical file-name)))
   5045     (->> (lsp-session)
   5046          (lsp-session-folders)
   5047          (--filter (and (lsp--files-same-host it file-name)
   5048                         (or (lsp-f-ancestor-of? it file-name)
   5049                             (equal it file-name))))
   5050          (--max-by (> (length it) (length other))))))
   5051 
   5052 (defun lsp-on-revert ()
   5053   "Executed when a file is reverted.
   5054 Added to `after-revert-hook'."
   5055   (let ((n (buffer-size))
   5056         (revert-buffer-in-progress-p nil))
   5057     (lsp-on-change 0 n n)))
   5058 
   5059 (defun lsp--text-document-did-close (&optional keep-workspace-alive)
   5060   "Executed when the file is closed, added to `kill-buffer-hook'.
   5061 
   5062 If KEEP-WORKSPACE-ALIVE is non-nil, do not shutdown the workspace
   5063 if it's closing the last buffer in the workspace."
   5064   (lsp-foreach-workspace
   5065    (cl-callf2 delq (lsp-current-buffer) (lsp--workspace-buffers lsp--cur-workspace))
   5066    (with-demoted-errors "Error sending didClose notification in ‘lsp--text-document-did-close’: %S"
   5067      (lsp-notify "textDocument/didClose"
   5068                  `(:textDocument ,(lsp--text-document-identifier))))
   5069    (when (and (not lsp-keep-workspace-alive)
   5070               (not keep-workspace-alive)
   5071               (not (lsp--workspace-buffers lsp--cur-workspace)))
   5072      (lsp--shutdown-workspace))))
   5073 
   5074 (defun lsp--will-save-text-document-params (reason)
   5075   (list :textDocument (lsp--text-document-identifier)
   5076         :reason reason))
   5077 
   5078 (defun lsp--before-save ()
   5079   "Before save handler."
   5080   (with-demoted-errors "Error in ‘lsp--before-save’: %S"
   5081     (let ((params (lsp--will-save-text-document-params 1)))
   5082       (when (lsp--send-will-save-p)
   5083         (lsp-notify "textDocument/willSave" params))
   5084       (when (and (lsp--send-will-save-wait-until-p) lsp-before-save-edits)
   5085         (let ((lsp-response-timeout 0.1))
   5086           (condition-case nil
   5087               (lsp--apply-text-edits
   5088                (lsp-request "textDocument/willSaveWaitUntil"
   5089                             params)
   5090                'before-save)
   5091             (error)))))))
   5092 
   5093 (defun lsp--on-auto-save ()
   5094   "Handler for auto-save."
   5095   (when (lsp--send-will-save-p)
   5096     (with-demoted-errors "Error in ‘lsp--on-auto-save’: %S"
   5097       (lsp-notify "textDocument/willSave" (lsp--will-save-text-document-params 2)))))
   5098 
   5099 (defun lsp--text-document-did-save ()
   5100   "Executed when the file is closed, added to `after-save-hook''."
   5101   (when (lsp--send-did-save-p)
   5102     (with-demoted-errors "Error on ‘lsp--text-document-did-save: %S’"
   5103       (lsp-notify "textDocument/didSave"
   5104                   `( :textDocument ,(lsp--versioned-text-document-identifier)
   5105                      ,@(when (lsp--save-include-text-p)
   5106                          (list :text (lsp--buffer-content))))))))
   5107 
   5108 (defun lsp--text-document-position-params (&optional identifier position)
   5109   "Make TextDocumentPositionParams for the current point in the current document.
   5110 If IDENTIFIER and POSITION are non-nil, they will be used as the document
   5111 identifier and the position respectively."
   5112   (list :textDocument (or identifier (lsp--text-document-identifier))
   5113         :position (or position (lsp--cur-position))))
   5114 
   5115 (defun lsp--get-buffer-diagnostics ()
   5116   "Return buffer diagnostics."
   5117   (gethash (or
   5118             (plist-get lsp--virtual-buffer :buffer-file-name)
   5119             (lsp--fix-path-casing (buffer-file-name)))
   5120            (lsp-diagnostics t)))
   5121 
   5122 (defun lsp-cur-line-diagnostics ()
   5123   "Return any diagnostics that apply to the current line."
   5124   (-let [(&plist :start (&plist :line start) :end (&plist :line end)) (lsp--region-or-line)]
   5125     (cl-coerce (-filter
   5126                 (-lambda ((&Diagnostic :range (&Range :start (&Position :line))))
   5127                   (and (>= line start) (<= line end)))
   5128                 (lsp--get-buffer-diagnostics))
   5129                'vector)))
   5130 
   5131 (lsp-defun lsp-range-overlapping?((left &as &Range :start left-start :end left-end)
   5132                                   (right &as &Range :start right-start :end right-end))
   5133   (or (lsp-point-in-range? right-start left)
   5134       (lsp-point-in-range? right-end left)
   5135       (lsp-point-in-range? left-start right)
   5136       (lsp-point-in-range? left-end right)))
   5137 
   5138 (defun lsp-make-position-1 (position)
   5139   (lsp-make-position :line (plist-get position :line)
   5140                      :character (plist-get position :character)))
   5141 
   5142 (defun lsp-cur-possition-diagnostics ()
   5143   "Return any diagnostics that apply to the current line."
   5144   (-let* ((start (if (use-region-p) (region-beginning) (point)))
   5145           (end (if (use-region-p) (region-end) (point)))
   5146           (current-range (lsp-make-range :start (lsp-make-position-1 (lsp-point-to-position start))
   5147                                          :end (lsp-make-position-1 (lsp-point-to-position end)))))
   5148     (->> (lsp--get-buffer-diagnostics)
   5149          (-filter
   5150           (-lambda ((&Diagnostic :range))
   5151             (lsp-range-overlapping? range current-range)))
   5152          (apply 'vector))))
   5153 
   5154 (defalias 'lsp--cur-line-diagnotics 'lsp-cur-line-diagnostics)
   5155 
   5156 (defun lsp--extract-line-from-buffer (pos)
   5157   "Return the line pointed to by POS (a Position object) in the current buffer."
   5158   (let* ((point (lsp--position-to-point pos))
   5159          (inhibit-field-text-motion t))
   5160     (save-excursion
   5161       (goto-char point)
   5162       (buffer-substring (line-beginning-position) (line-end-position)))))
   5163 
   5164 (lsp-defun lsp--xref-make-item (filename (&Range :start (start &as &Position :character start-char :line start-line)
   5165                                                  :end (end &as &Position :character end-char)))
   5166   "Return a xref-item from a RANGE in FILENAME."
   5167   (let* ((line (lsp--extract-line-from-buffer start))
   5168          (len (length line)))
   5169     (add-face-text-property (max (min start-char len) 0)
   5170                             (max (min end-char len) 0)
   5171                             'xref-match t line)
   5172     ;; LINE is nil when FILENAME is not being current visited by any buffer.
   5173     (xref-make-match (or line filename)
   5174                      (xref-make-file-location
   5175                       filename
   5176                       (lsp-translate-line (1+ start-line))
   5177                       (lsp-translate-column start-char))
   5178                      (- end-char start-char))))
   5179 
   5180 (defun lsp--location-uri (loc)
   5181   (if (lsp-location? loc)
   5182       (lsp:location-uri loc)
   5183     (lsp:location-link-target-uri loc)))
   5184 
   5185 (lsp-defun lsp-goto-location ((loc &as &Location :uri :range (&Range :start)))
   5186   "Go to location."
   5187   (let ((path (lsp--uri-to-path uri)))
   5188     (if (f-exists? path)
   5189         (with-current-buffer (find-file path)
   5190           (goto-char (lsp--position-to-point start)))
   5191       (error "There is no file %s" path))))
   5192 
   5193 (defun lsp--location-range (loc)
   5194   (if (lsp-location? loc)
   5195       (lsp:location-range loc)
   5196     (lsp:location-link-target-selection-range loc)))
   5197 
   5198 (defun lsp--locations-to-xref-items (locations)
   5199   "Return a list of `xref-item' given LOCATIONS, which can be of
   5200 type Location, LocationLink, Location[] or LocationLink[]."
   5201   (setq locations
   5202         (pcase locations
   5203           ((seq (or (Location)
   5204                     (LocationLink)))
   5205            (append locations nil))
   5206           ((or (Location)
   5207                (LocationLink))
   5208            (list locations))))
   5209 
   5210   (cl-labels ((get-xrefs-in-file
   5211                (file-locs)
   5212                (-let [(filename . matches) file-locs]
   5213                  (condition-case err
   5214                      (let ((visiting (find-buffer-visiting filename))
   5215                            (fn (lambda (loc)
   5216                                  (lsp-with-filename filename
   5217                                    (lsp--xref-make-item filename
   5218                                                         (lsp--location-range loc))))))
   5219                        (if visiting
   5220                            (with-current-buffer visiting
   5221                              (seq-map fn matches))
   5222                          (when (file-readable-p filename)
   5223                            (with-temp-buffer
   5224                              (insert-file-contents-literally filename)
   5225                              (seq-map fn matches)))))
   5226                    (error (lsp-warn "Failed to process xref entry for filename '%s': %s"
   5227                                     filename (error-message-string err)))
   5228                    (file-error (lsp-warn "Failed to process xref entry, file-error, '%s': %s"
   5229                                          filename (error-message-string err)))))))
   5230 
   5231     (->> locations
   5232          (seq-sort #'lsp--location-before-p)
   5233          (seq-group-by (-compose #'lsp--uri-to-path #'lsp--location-uri))
   5234          (seq-map #'get-xrefs-in-file)
   5235          (apply #'nconc))))
   5236 
   5237 (defun lsp--location-before-p (left right)
   5238   "Sort first by file, then by line, then by column."
   5239   (let ((left-uri (lsp--location-uri left))
   5240         (right-uri (lsp--location-uri right)))
   5241     (if (not (string= left-uri right-uri))
   5242         (string< left-uri right-uri)
   5243       (-let (((&Range :start left-start) (lsp--location-range left))
   5244              ((&Range :start right-start) (lsp--location-range right)))
   5245         (lsp--position-compare right-start left-start)))))
   5246 
   5247 (defun lsp--make-reference-params (&optional td-position exclude-declaration)
   5248   "Make a ReferenceParam object.
   5249 If TD-POSITION is non-nil, use it as TextDocumentPositionParams object instead.
   5250 If EXCLUDE-DECLARATION is non-nil, request the server to include declarations."
   5251   (let ((json-false :json-false))
   5252     (plist-put (or td-position (lsp--text-document-position-params))
   5253                :context `(:includeDeclaration ,(lsp-json-bool (not exclude-declaration))))))
   5254 
   5255 (defun lsp--cancel-request (id)
   5256   "Cancel request with ID in all workspaces."
   5257   (lsp-foreach-workspace
   5258    (->> lsp--cur-workspace lsp--workspace-client lsp--client-response-handlers (remhash id))
   5259    (lsp-notify "$/cancelRequest" `(:id ,id))))
   5260 
   5261 (defvar-local lsp--hover-saved-bounds nil)
   5262 
   5263 (defun lsp-eldoc-function (cb &rest _ignored)
   5264   "`lsp-mode' eldoc function to display hover info (based on `textDocument/hover')."
   5265   (if (and lsp--hover-saved-bounds
   5266            (lsp--point-in-bounds-p lsp--hover-saved-bounds))
   5267       lsp--eldoc-saved-message
   5268     (setq lsp--hover-saved-bounds nil
   5269           lsp--eldoc-saved-message nil)
   5270     (if (looking-at-p "[[:space:]\n]")
   5271         (setq lsp--eldoc-saved-message nil) ; And returns nil.
   5272       (when (and lsp-eldoc-enable-hover (lsp-feature? "textDocument/hover"))
   5273         (lsp-request-async
   5274          "textDocument/hover"
   5275          (lsp--text-document-position-params)
   5276          (-lambda ((hover &as &Hover? :range? :contents))
   5277            (setq lsp--hover-saved-bounds (when range?
   5278                                            (lsp--range-to-region range?)))
   5279            (funcall cb (setq lsp--eldoc-saved-message
   5280                              (when contents
   5281                                (lsp--render-on-hover-content
   5282                                 contents
   5283                                 lsp-eldoc-render-all)))))
   5284          :error-handler #'ignore
   5285          :mode 'tick
   5286          :cancel-token :eldoc-hover)))))
   5287 
   5288 (defun lsp--point-on-highlight? ()
   5289   (-some? (lambda (overlay)
   5290             (overlay-get overlay 'lsp-highlight))
   5291           (overlays-at (point))))
   5292 
   5293 (defun lsp--cleanup-highlights-if-needed ()
   5294   (when (and lsp-enable-symbol-highlighting
   5295              lsp--have-document-highlights
   5296              (not (lsp--point-on-highlight?)))
   5297     (lsp--remove-overlays 'lsp-highlight)
   5298     (setq lsp--have-document-highlights nil)
   5299     (lsp-cancel-request-by-token :highlights)))
   5300 
   5301 (defvar-local lsp--symbol-bounds-of-last-highlight-invocation nil
   5302   "The bounds of the symbol from which `lsp--document-highlight'
   5303   most recently requested highlights.")
   5304 
   5305 (defun lsp--document-highlight ()
   5306   (when (lsp-feature? "textDocument/documentHighlight")
   5307     (let ((curr-sym-bounds (bounds-of-thing-at-point 'symbol)))
   5308       (unless (or (looking-at-p "[[:space:]\n]")
   5309                   (not lsp-enable-symbol-highlighting)
   5310                   (and lsp--have-document-highlights
   5311                        curr-sym-bounds
   5312                        (equal curr-sym-bounds
   5313                               lsp--symbol-bounds-of-last-highlight-invocation)))
   5314         (setq lsp--symbol-bounds-of-last-highlight-invocation
   5315               curr-sym-bounds)
   5316         (lsp-request-async "textDocument/documentHighlight"
   5317                            (lsp--text-document-position-params)
   5318                            #'lsp--document-highlight-callback
   5319                            :mode 'tick
   5320                            :cancel-token :highlights)))))
   5321 
   5322 (defun lsp--help-open-link (&rest _)
   5323   "Open markdown link at point via mouse or keyboard."
   5324   (interactive "P")
   5325   (let ((buffer-list-update-hook nil))
   5326     (-let [(buffer point) (if-let* ((valid (and (listp last-input-event)
   5327                                                 (eq (car last-input-event) 'mouse-2)))
   5328                                     (event (cadr last-input-event))
   5329                                     (win (posn-window event))
   5330                                     (buffer (window-buffer win)))
   5331                               `(,buffer ,(posn-point event))
   5332                             `(,(current-buffer) ,(point)))]
   5333       (with-current-buffer buffer
   5334         (when-let* ((face (get-text-property point 'face))
   5335                     (url (or (and (eq face 'markdown-link-face)
   5336                                   (get-text-property point 'help-echo))
   5337                              (and (memq face '(markdown-url-face markdown-plain-url-face))
   5338                                   (nth 3 (markdown-link-at-pos point))))))
   5339           (lsp--document-link-handle-target url))))))
   5340 
   5341 (defvar lsp-help-mode-map
   5342   (-doto (make-sparse-keymap)
   5343     (define-key [remap markdown-follow-link-at-point] #'lsp--help-open-link))
   5344   "Keymap for `lsp-help-mode'.")
   5345 
   5346 (define-derived-mode lsp-help-mode help-mode "LspHelp"
   5347   "Major mode for displaying lsp help.")
   5348 
   5349 (defun lsp-describe-thing-at-point ()
   5350   "Display the type signature and documentation of the thing at point."
   5351   (interactive)
   5352   (let ((contents (-some->> (lsp--text-document-position-params)
   5353                     (lsp--make-request "textDocument/hover")
   5354                     (lsp--send-request)
   5355                     (lsp:hover-contents))))
   5356     (if (and contents (not (equal contents "")))
   5357         (let ((lsp-help-buf-name "*lsp-help*"))
   5358           (with-current-buffer (get-buffer-create lsp-help-buf-name)
   5359             (delay-mode-hooks
   5360               (lsp-help-mode)
   5361               (with-help-window lsp-help-buf-name
   5362                 (insert (string-trim-right (lsp--render-on-hover-content contents t)))))
   5363             (run-mode-hooks)))
   5364       (lsp--info "No content at point."))))
   5365 
   5366 (defun lsp--point-in-bounds-p (bounds)
   5367   "Return whether the current point is within BOUNDS."
   5368   (and (<= (car bounds) (point)) (< (point) (cdr bounds))))
   5369 
   5370 (defun lsp-get-renderer (language)
   5371   "Get renderer for LANGUAGE."
   5372   (lambda (str)
   5373     (lsp--render-string str language)))
   5374 
   5375 (defun lsp--setup-markdown (mode)
   5376   "Setup the ‘markdown-mode’ in the frame.
   5377 MODE is the mode used in the parent frame."
   5378   (make-local-variable 'markdown-code-lang-modes)
   5379   (dolist (mark (alist-get mode lsp-custom-markup-modes))
   5380     (add-to-list 'markdown-code-lang-modes (cons mark mode)))
   5381   (setq-local markdown-fontify-code-blocks-natively t)
   5382   (setq-local markdown-fontify-code-block-default-mode mode)
   5383   (setq-local markdown-hide-markup t)
   5384 
   5385   ;; Render some common HTML entities.
   5386   ;; This should really happen in markdown-mode instead,
   5387   ;; but it doesn't, so we do it here for now.
   5388   (setq prettify-symbols-alist
   5389         (cl-loop for i from 0 to 255
   5390                  collect (cons (format "&#x%02X;" i) i)))
   5391   (push '("&lt;" . ?<) prettify-symbols-alist)
   5392   (push '("&gt;" . ?>) prettify-symbols-alist)
   5393   (push '("&amp;" . ?&) prettify-symbols-alist)
   5394   (push '("&nbsp;" . ? ) prettify-symbols-alist)
   5395   (setq prettify-symbols-compose-predicate
   5396         (lambda (_start _end _match) t))
   5397   (prettify-symbols-mode 1))
   5398 
   5399 (defvar lsp-help-link-keymap
   5400   (let ((map (make-sparse-keymap)))
   5401     (define-key map [mouse-2] #'lsp--help-open-link)
   5402     (define-key map "\r" #'lsp--help-open-link)
   5403     map)
   5404   "Keymap active on links in *lsp-help* mode.")
   5405 
   5406 (defun lsp--fix-markdown-links ()
   5407   (let ((inhibit-read-only t)
   5408         (inhibit-modification-hooks t)
   5409         (prop))
   5410     (save-restriction
   5411       (goto-char (point-min))
   5412       (while (setq prop (markdown-find-next-prop 'face))
   5413         (let ((end (or (next-single-property-change (car prop) 'face)
   5414                        (point-max))))
   5415           (when (memq (get-text-property (car prop) 'face)
   5416                       '(markdown-link-face
   5417                         markdown-url-face
   5418                         markdown-plain-url-face))
   5419             (add-text-properties (car prop) end
   5420                                  (list 'button t
   5421                                        'category 'lsp-help-link
   5422                                        'follow-link t
   5423                                        'keymap lsp-help-link-keymap)))
   5424           (goto-char end))))))
   5425 
   5426 (defun lsp--buffer-string-visible ()
   5427   "Return visible buffer string.
   5428 Stolen from `org-copy-visible'."
   5429   (let ((temp (generate-new-buffer " *temp*"))
   5430         (beg (point-min))
   5431         (end (point-max)))
   5432     (while (/= beg end)
   5433       (when (get-char-property beg 'invisible)
   5434         (setq beg (next-single-char-property-change beg 'invisible nil end)))
   5435       (let* ((next (next-single-char-property-change beg 'invisible nil end))
   5436              (substring (buffer-substring beg next)))
   5437         (with-current-buffer temp (insert substring))
   5438         ;; (setq result (concat result substring))
   5439         (setq beg next)))
   5440     (setq deactivate-mark t)
   5441     (prog1 (with-current-buffer temp
   5442              (s-chop-suffix "\n" (buffer-string)))
   5443       (kill-buffer temp))))
   5444 
   5445 (defvar lsp-buffer-major-mode nil
   5446   "Holds the major mode when fontification function is running.
   5447 See #2588")
   5448 
   5449 (defvar view-inhibit-help-message)
   5450 
   5451 (defun lsp--render-markdown ()
   5452   "Render markdown."
   5453 
   5454   (let ((markdown-enable-math nil))
   5455     (goto-char (point-min))
   5456     (while (re-search-forward
   5457             (rx (and "\\" (group (or "\\" "`" "*" "_" ":" "/"
   5458                                      "{" "}" "[" "]" "(" ")"
   5459                                      "#" "+" "-" "." "!" "|"))))
   5460             nil t)
   5461       (replace-match (rx (backref 1))))
   5462 
   5463     ;; markdown-mode v2.3 does not yet provide gfm-view-mode
   5464     (if (fboundp 'gfm-view-mode)
   5465         (let ((view-inhibit-help-message t))
   5466           (gfm-view-mode))
   5467       (gfm-mode))
   5468 
   5469     (lsp--setup-markdown lsp-buffer-major-mode)))
   5470 
   5471 (defvar lsp--display-inline-image-alist
   5472   '((lsp--render-markdown
   5473      (:regexp
   5474       "!\\[.*?\\](data:image/[a-zA-Z]+;base64,\\([A-Za-z0-9+/\n]+?=*?\\)\\(|[^)]+\\)?)"
   5475       :sexp
   5476       (create-image
   5477        (base64-decode-string
   5478         (buffer-substring-no-properties (match-beginning 1) (match-end 1)))
   5479        nil t))))
   5480   "Replaced string regexp and function returning image.
   5481 Each element should have the form (MODE . (PROPERTY-LIST...)).
   5482 MODE (car) is function which is defined in `lsp-language-id-configuration'.
   5483 Cdr should be list of PROPERTY-LIST.
   5484 
   5485 Each PROPERTY-LIST should have properties:
   5486 :regexp  Regexp which determines what string is relpaced to image.
   5487          You should also get information of image, by parenthesis constructs.
   5488          By default, all matched string is replaced to image, but you can
   5489          change index of replaced string by keyword :replaced-index.
   5490 
   5491 :sexp    Return image when evaluated. You can use information of regexp
   5492          by using (match-beggining N), (match-end N) or (match-substring N).
   5493 
   5494 In addition, each can have property:
   5495 :replaced-index  Determine index which is used to replace regexp to image.
   5496                  The value means first argument of `match-beginning' and
   5497                  `match-end'. If omitted, interpreted as index 0.")
   5498 
   5499 (defcustom lsp-display-inline-image t
   5500   "Showing inline image or not."
   5501   :group 'lsp-mode
   5502   :type 'boolean)
   5503 
   5504 (defcustom lsp-enable-suggest-server-download t
   5505   "When non-nil enable server downloading suggestions."
   5506   :group 'lsp-mode
   5507   :type 'boolean
   5508   :package-version '(lsp-mode . "9.0.0"))
   5509 
   5510 (defcustom lsp-auto-register-remote-clients t
   5511   "When non-nil register remote when registering the local one."
   5512   :group 'lsp-mode
   5513   :type 'boolean
   5514   :package-version '(lsp-mode . "9.0.0"))
   5515 
   5516 (defun lsp--display-inline-image (mode)
   5517   "Add image property if available."
   5518   (let ((plist-list (cdr (assq mode lsp--display-inline-image-alist))))
   5519     (when (and (display-images-p) lsp-display-inline-image)
   5520       (cl-loop
   5521        for plist in plist-list
   5522        with regexp with replaced-index
   5523        do
   5524        (setq regexp (plist-get plist :regexp))
   5525        (setq replaced-index (or (plist-get plist :replaced-index) 0))
   5526 
   5527        (font-lock-remove-keywords nil (list regexp replaced-index))
   5528        (let ((inhibit-read-only t))
   5529          (save-excursion
   5530            (goto-char (point-min))
   5531            (while (re-search-forward regexp nil t)
   5532              (set-text-properties
   5533               (match-beginning replaced-index) (match-end replaced-index)
   5534               nil)
   5535              (add-text-properties
   5536               (match-beginning replaced-index) (match-end replaced-index)
   5537               `(display ,(eval (plist-get plist :sexp)))))))))))
   5538 
   5539 (defun lsp--fontlock-with-mode (str mode)
   5540   "Fontlock STR with MODE."
   5541   (let ((lsp-buffer-major-mode major-mode))
   5542     (with-temp-buffer
   5543       (with-demoted-errors "Error during doc rendering: %s"
   5544         (insert str)
   5545         (delay-mode-hooks (funcall mode))
   5546         (cl-flet ((window-body-width () lsp-window-body-width))
   5547           ;; This can go wrong in some cases, and the fontification would
   5548           ;; not work as expected.
   5549           ;;
   5550           ;; See #2984
   5551           (ignore-errors (font-lock-ensure))
   5552           (lsp--display-inline-image mode)
   5553           (when (eq mode 'lsp--render-markdown)
   5554             (lsp--fix-markdown-links))))
   5555       (lsp--buffer-string-visible))))
   5556 
   5557 (defun lsp--render-string (str language)
   5558   "Render STR using `major-mode' corresponding to LANGUAGE.
   5559 When language is nil render as markup if `markdown-mode' is loaded."
   5560   (setq str (s-replace "\r" "" (or str "")))
   5561   (if-let* ((modes (-keep (-lambda ((mode . lang))
   5562                             (when (and (equal lang language) (functionp mode))
   5563                               mode))
   5564                           lsp-language-id-configuration))
   5565             (mode (car (or (member major-mode modes) modes))))
   5566       (lsp--fontlock-with-mode str mode)
   5567     str))
   5568 
   5569 (defun lsp--render-element (content)
   5570   "Render CONTENT element."
   5571   (let ((inhibit-message t))
   5572     (or
   5573      (pcase content
   5574        ((MarkedString :value :language)
   5575         (lsp--render-string value language))
   5576        ((MarkupContent :value :kind)
   5577         (lsp--render-string value kind))
   5578        ;; plain string
   5579        ((pred stringp) (lsp--render-string content "markdown"))
   5580        ((pred null) "")
   5581        (_ (error "Failed to handle %s" content)))
   5582      "")))
   5583 
   5584 (defun lsp--create-unique-string-fn ()
   5585   (let (elements)
   5586     (lambda (element)
   5587       (let ((count (cl-count element elements :test #'string=)))
   5588         (prog1 (if (zerop count)
   5589                    element
   5590                  (format "%s (%s)" element count))
   5591           (push element elements))))))
   5592 
   5593 (defun lsp--select-action (actions)
   5594   "Select an action to execute from ACTIONS."
   5595   (cond
   5596    ((seq-empty-p actions) (signal 'lsp-no-code-actions nil))
   5597    ((and (eq (seq-length actions) 1) lsp-auto-execute-action)
   5598     (lsp-seq-first actions))
   5599    (t (let ((completion-ignore-case t))
   5600         (lsp--completing-read "Select code action: "
   5601                               (seq-into actions 'list)
   5602                               (-compose (lsp--create-unique-string-fn)
   5603                                         #'lsp:code-action-title)
   5604                               nil t)))))
   5605 
   5606 (defun lsp--workspace-server-id (workspace)
   5607   "Return the server ID of WORKSPACE."
   5608   (-> workspace lsp--workspace-client lsp--client-server-id))
   5609 
   5610 (defun lsp--handle-rendered-for-echo-area (contents)
   5611   "Return a single line from RENDERED, appropriate for display in the echo area."
   5612   (pcase (lsp-workspaces)
   5613     (`(,workspace)
   5614      (lsp-clients-extract-signature-on-hover contents (lsp--workspace-server-id workspace)))
   5615     ;; For projects with multiple active workspaces we also default to
   5616     ;; render the first line.
   5617     (_ (lsp-clients-extract-signature-on-hover contents nil))))
   5618 
   5619 (cl-defmethod lsp-clients-extract-signature-on-hover (contents _server-id)
   5620   "Extract a representative line from CONTENTS, to show in the echo area."
   5621   (car (s-lines (s-trim (lsp--render-element contents)))))
   5622 
   5623 (defun lsp--render-on-hover-content (contents render-all)
   5624   "Render the content received from `document/onHover' request.
   5625 CONTENTS  - MarkedString | MarkedString[] | MarkupContent
   5626 RENDER-ALL - nil if only the signature should be rendered."
   5627   (cond
   5628    ((lsp-markup-content? contents)
   5629     ;; MarkupContent.
   5630     ;; It tends to be long and is not suitable to display fully in the echo area.
   5631     ;; Just display the first line which is typically the signature.
   5632     (if render-all
   5633         (lsp--render-element contents)
   5634       (lsp--handle-rendered-for-echo-area contents)))
   5635    ((and (stringp contents) (not (string-match-p "\n" contents)))
   5636     ;; If the contents is a single string containing a single line,
   5637     ;; render it always.
   5638     (lsp--render-element contents))
   5639    (t
   5640     ;; MarkedString -> MarkedString[]
   5641     (when (or (lsp-marked-string? contents) (stringp contents))
   5642       (setq contents (list contents)))
   5643     ;; Consider the signature consisting of the elements who have a renderable
   5644     ;; "language" property. When render-all is nil, ignore other elements.
   5645     (string-join
   5646      (seq-map
   5647       #'lsp--render-element
   5648       (if render-all
   5649           contents
   5650         ;; Only render contents that have an available renderer.
   5651         (seq-take
   5652          (seq-filter
   5653           (-andfn #'lsp-marked-string?
   5654                   (-compose #'lsp-get-renderer #'lsp:marked-string-language))
   5655           contents)
   5656          1)))
   5657      (if (bound-and-true-p page-break-lines-mode)
   5658          "\n\n"
   5659        "\n")))))
   5660 
   5661 
   5662 
   5663 (defvar lsp-signature-mode-map
   5664   (-doto (make-sparse-keymap)
   5665     (define-key (kbd "M-n") #'lsp-signature-next)
   5666     (define-key (kbd "M-p") #'lsp-signature-previous)
   5667     (define-key (kbd "M-a") #'lsp-signature-toggle-full-docs)
   5668     (define-key (kbd "C-c C-k") #'lsp-signature-stop)
   5669     (define-key (kbd "C-g") #'lsp-signature-stop))
   5670   "Keymap for `lsp-signature-mode'.")
   5671 
   5672 (define-minor-mode lsp-signature-mode
   5673   "Mode used to show signature popup."
   5674   :keymap lsp-signature-mode-map
   5675   :lighter ""
   5676   :group 'lsp-mode)
   5677 
   5678 (defun lsp-signature-stop ()
   5679   "Stop showing current signature help."
   5680   (interactive)
   5681   (lsp-cancel-request-by-token :signature)
   5682   (remove-hook 'post-command-hook #'lsp-signature)
   5683   (funcall lsp-signature-function nil)
   5684   (lsp-signature-mode -1))
   5685 
   5686 (declare-function page-break-lines--update-display-tables "ext:page-break-lines")
   5687 
   5688 (defun lsp--setup-page-break-mode-if-present ()
   5689   "Enable `page-break-lines-mode' in current buffer."
   5690   (when (fboundp 'page-break-lines-mode)
   5691     (page-break-lines-mode)
   5692     ;; force page-break-lines-mode to update the display tables.
   5693     (page-break-lines--update-display-tables)))
   5694 
   5695 (defun lsp-lv-message (message)
   5696   (add-hook 'lv-window-hook #'lsp--setup-page-break-mode-if-present)
   5697   (if message
   5698       (progn
   5699         (setq lsp--signature-last-buffer (current-buffer))
   5700         (let ((lv-force-update t))
   5701           (lv-message "%s" message)))
   5702     (lv-delete-window)
   5703     (remove-hook 'lv-window-hook #'lsp--setup-page-break-mode-if-present)))
   5704 
   5705 (declare-function posframe-show "ext:posframe")
   5706 (declare-function posframe-hide "ext:posframe")
   5707 (declare-function posframe-poshandler-point-bottom-left-corner-upward "ext:posframe")
   5708 
   5709 (defface lsp-signature-posframe
   5710   '((t :inherit tooltip))
   5711   "Background and foreground for `lsp-signature-posframe'."
   5712   :group 'lsp-mode)
   5713 
   5714 (defvar lsp-signature-posframe-params
   5715   (list :poshandler #'posframe-poshandler-point-bottom-left-corner-upward
   5716         :height 10
   5717         :width 60
   5718         :border-width 1
   5719         :min-width 60)
   5720   "Params for signature and `posframe-show'.")
   5721 
   5722 (defun lsp-signature-posframe (str)
   5723   "Use posframe to show the STR signatureHelp string."
   5724   (if str
   5725       (apply #'posframe-show
   5726              (with-current-buffer (get-buffer-create " *lsp-signature*")
   5727                (erase-buffer)
   5728                (insert str)
   5729                (visual-line-mode 1)
   5730                (lsp--setup-page-break-mode-if-present)
   5731                (current-buffer))
   5732              (append
   5733               lsp-signature-posframe-params
   5734               (list :position (point)
   5735                     :background-color (face-attribute 'lsp-signature-posframe :background nil t)
   5736                     :foreground-color (face-attribute 'lsp-signature-posframe :foreground nil t)
   5737                     :border-color (face-attribute 'font-lock-comment-face :foreground nil t))))
   5738     (posframe-hide " *lsp-signature*")))
   5739 
   5740 (defun lsp--handle-signature-update (signature)
   5741   (let ((message
   5742          (if (lsp-signature-help? signature)
   5743              (lsp--signature->message signature)
   5744            (mapconcat #'lsp--signature->message signature "\n"))))
   5745     (if (s-present? message)
   5746         (funcall lsp-signature-function message)
   5747       (lsp-signature-stop))))
   5748 
   5749 (defun lsp-signature-activate ()
   5750   "Activate signature help.
   5751 It will show up only if current point has signature help."
   5752   (interactive)
   5753   (setq lsp--signature-last nil
   5754         lsp--signature-last-index nil
   5755         lsp--signature-last-buffer (current-buffer))
   5756   (add-hook 'post-command-hook #'lsp-signature)
   5757   (lsp-signature-mode t))
   5758 
   5759 (defcustom lsp-signature-cycle t
   5760   "Whether `lsp-signature-next' and prev should cycle."
   5761   :type 'boolean
   5762   :group 'lsp-mode)
   5763 
   5764 (defun lsp-signature-next ()
   5765   "Show next signature."
   5766   (interactive)
   5767   (let ((nsigs (length (lsp:signature-help-signatures lsp--signature-last))))
   5768     (when (and lsp--signature-last-index
   5769                lsp--signature-last
   5770                (or lsp-signature-cycle (< (1+ lsp--signature-last-index) nsigs)))
   5771       (setq lsp--signature-last-index (% (1+ lsp--signature-last-index) nsigs))
   5772       (funcall lsp-signature-function (lsp--signature->message lsp--signature-last)))))
   5773 
   5774 (defun lsp-signature-previous ()
   5775   "Next signature."
   5776   (interactive)
   5777   (when (and lsp--signature-last-index
   5778              lsp--signature-last
   5779              (or lsp-signature-cycle (not (zerop lsp--signature-last-index))))
   5780     (setq lsp--signature-last-index (1- (if (zerop lsp--signature-last-index)
   5781                                             (length (lsp:signature-help-signatures lsp--signature-last))
   5782                                           lsp--signature-last-index)))
   5783     (funcall lsp-signature-function (lsp--signature->message lsp--signature-last))))
   5784 
   5785 (defun lsp-signature-toggle-full-docs ()
   5786   "Toggle full/partial signature documentation."
   5787   (interactive)
   5788   (let ((all? (not (numberp lsp-signature-doc-lines))))
   5789     (setq lsp-signature-doc-lines (if all?
   5790                                       (or (car-safe lsp-signature-doc-lines)
   5791                                           20)
   5792                                     (list lsp-signature-doc-lines))))
   5793   (lsp-signature-activate))
   5794 
   5795 (defun lsp--signature->message (signature-help)
   5796   "Generate eldoc message from SIGNATURE-HELP response."
   5797   (setq lsp--signature-last signature-help)
   5798 
   5799   (when (and signature-help (not (seq-empty-p (lsp:signature-help-signatures signature-help))))
   5800     (-let* (((&SignatureHelp :active-signature?
   5801                              :active-parameter?
   5802                              :signatures) signature-help)
   5803             (active-signature? (or lsp--signature-last-index active-signature? 0))
   5804             (_ (setq lsp--signature-last-index active-signature?))
   5805             ((signature &as &SignatureInformation? :label :parameters?) (seq-elt signatures active-signature?))
   5806             (prefix (if (= (length signatures) 1)
   5807                         ""
   5808                       (concat (propertize (format " %s/%s"
   5809                                                   (1+ active-signature?)
   5810                                                   (length signatures))
   5811                                           'face 'success)
   5812                               " ")))
   5813             (method-docs (when
   5814                              (and lsp-signature-render-documentation
   5815                                   (or (not (numberp lsp-signature-doc-lines)) (< 0 lsp-signature-doc-lines)))
   5816                            (let ((docs (lsp--render-element
   5817                                         (lsp:parameter-information-documentation? signature))))
   5818                              (when (s-present? docs)
   5819                                (concat
   5820                                 "\n"
   5821                                 (if (fboundp 'page-break-lines-mode)
   5822                                     "\n"
   5823                                   "")
   5824                                 (if (and (numberp lsp-signature-doc-lines)
   5825                                          (> (length (s-lines docs)) lsp-signature-doc-lines))
   5826                                     (concat (s-join "\n" (-take lsp-signature-doc-lines (s-lines docs)))
   5827                                             (propertize "\nTruncated..." 'face 'highlight))
   5828                                   docs)))))))
   5829       (when (and active-parameter? (not (seq-empty-p parameters?)))
   5830         (-when-let* ((param (when (and (< -1 active-parameter? (length parameters?)))
   5831                               (seq-elt parameters? active-parameter?)))
   5832                      (selected-param-label (let ((label (lsp:parameter-information-label param)))
   5833                                              (if (stringp label) label (append label nil))))
   5834                      (start (if (stringp selected-param-label)
   5835                                 (s-index-of selected-param-label label)
   5836                               (cl-first selected-param-label)))
   5837                      (end (if (stringp selected-param-label)
   5838                               (+ start (length selected-param-label))
   5839                             (cl-second selected-param-label))))
   5840           (add-face-text-property start end 'eldoc-highlight-function-argument nil label)))
   5841       (concat prefix label method-docs))))
   5842 
   5843 (defun lsp-signature ()
   5844   "Display signature info (based on `textDocument/signatureHelp')"
   5845   (if (and lsp--signature-last-buffer
   5846            (not (equal (current-buffer) lsp--signature-last-buffer)))
   5847       (lsp-signature-stop)
   5848     (lsp-request-async "textDocument/signatureHelp"
   5849                        (lsp--text-document-position-params)
   5850                        #'lsp--handle-signature-update
   5851                        :cancel-token :signature)))
   5852 
   5853 
   5854 (defcustom lsp-overlay-document-color-char "■"
   5855   "Display the char represent the document color in overlay"
   5856   :type 'string
   5857   :group 'lsp-mode)
   5858 
   5859 ;; color presentation
   5860 (defun lsp--color-create-interactive-command (color range)
   5861   (lambda ()
   5862     (interactive)
   5863     (-let [(&ColorPresentation? :text-edit?
   5864                                 :additional-text-edits?)
   5865            (lsp--completing-read
   5866             "Select color presentation: "
   5867             (lsp-request
   5868              "textDocument/colorPresentation"
   5869              `( :textDocument ,(lsp--text-document-identifier)
   5870                 :color ,color
   5871                 :range ,range))
   5872             #'lsp:color-presentation-label
   5873             nil
   5874             t)]
   5875       (when text-edit?
   5876         (lsp--apply-text-edit text-edit?))
   5877       (when additional-text-edits?
   5878         (lsp--apply-text-edits additional-text-edits? 'color-presentation)))))
   5879 
   5880 (defun lsp--number->color (number)
   5881   (let ((result (format "%x"
   5882                         (round (* (or number 0) 255.0)))))
   5883     (if (= 1 (length result))
   5884         (concat "0" result)
   5885       result)))
   5886 
   5887 (defun lsp--document-color ()
   5888   "Document color handler."
   5889   (when (lsp-feature? "textDocument/documentColor")
   5890     (lsp-request-async
   5891      "textDocument/documentColor"
   5892      `(:textDocument ,(lsp--text-document-identifier))
   5893      (lambda (result)
   5894        (lsp--remove-overlays 'lsp-color)
   5895        (seq-do
   5896         (-lambda ((&ColorInformation :color (color &as &Color :red :green :blue)
   5897                                      :range))
   5898           (-let* (((beg . end) (lsp--range-to-region range))
   5899                   (overlay (make-overlay beg end))
   5900                   (command (lsp--color-create-interactive-command color range)))
   5901             (overlay-put overlay 'lsp-color t)
   5902             (overlay-put overlay 'evaporate t)
   5903             (overlay-put overlay
   5904                          'before-string
   5905                          (propertize
   5906                           lsp-overlay-document-color-char
   5907                           'face `((:foreground ,(format
   5908                                                  "#%s%s%s"
   5909                                                  (lsp--number->color red)
   5910                                                  (lsp--number->color green)
   5911                                                  (lsp--number->color blue))))
   5912                           'action command
   5913                           'mouse-face 'lsp-lens-mouse-face
   5914                           'local-map (-doto (make-sparse-keymap)
   5915                                        (define-key [mouse-1] command))))))
   5916         result))
   5917      :mode 'unchanged
   5918      :cancel-token :document-color-token)))
   5919 
   5920 
   5921 
   5922 (defun lsp--action-trigger-parameter-hints (_command)
   5923   "Handler for editor.action.triggerParameterHints."
   5924   (when (member :on-server-request lsp-signature-auto-activate)
   5925     (lsp-signature-activate)))
   5926 
   5927 (defun lsp--action-trigger-suggest (_command)
   5928   "Handler for editor.action.triggerSuggest."
   5929   (cond
   5930    ((and (bound-and-true-p company-mode)
   5931          (fboundp 'company-auto-begin)
   5932          (fboundp 'company-post-command))
   5933     (run-at-time 0 nil
   5934                  (lambda ()
   5935                    (let ((this-command 'company-idle-begin)
   5936                          (company-minimum-prefix-length 0))
   5937                      (company-auto-begin)
   5938                      (company-post-command)))))
   5939    (t
   5940     (completion-at-point))))
   5941 
   5942 (defconst lsp--default-action-handlers
   5943   (ht ("editor.action.triggerParameterHints" #'lsp--action-trigger-parameter-hints)
   5944       ("editor.action.triggerSuggest" #'lsp--action-trigger-suggest))
   5945   "Default action handlers.")
   5946 
   5947 (defun lsp--find-action-handler (command)
   5948   "Find action handler for particular COMMAND."
   5949   (or
   5950    (--some (-some->> it
   5951              (lsp--workspace-client)
   5952              (lsp--client-action-handlers)
   5953              (gethash command))
   5954            (lsp-workspaces))
   5955    (gethash command lsp--default-action-handlers)))
   5956 
   5957 (defun lsp--text-document-code-action-params (&optional kind)
   5958   "Code action params."
   5959   (list :textDocument (lsp--text-document-identifier)
   5960         :range (if (use-region-p)
   5961                    (lsp--region-to-range (region-beginning) (region-end))
   5962                  (lsp--region-to-range (point) (point)))
   5963         :context `( :diagnostics ,(lsp-cur-possition-diagnostics)
   5964                     ,@(when kind (list :only (vector kind))))))
   5965 
   5966 (defun lsp-code-actions-at-point (&optional kind)
   5967   "Retrieve the code actions for the active region or the current line.
   5968 It will filter by KIND if non nil."
   5969   (lsp-request "textDocument/codeAction" (lsp--text-document-code-action-params kind)))
   5970 
   5971 (defun lsp-execute-code-action-by-kind (command-kind)
   5972   "Execute code action by COMMAND-KIND."
   5973   (if-let ((action (->> (lsp-get-or-calculate-code-actions command-kind)
   5974                         (-filter (-lambda ((&CodeAction :kind?))
   5975                                    (and kind? (s-prefix? command-kind kind?))))
   5976                         lsp--select-action)))
   5977       (lsp-execute-code-action action)
   5978     (signal 'lsp-no-code-actions '(command-kind))))
   5979 
   5980 (defalias 'lsp-get-or-calculate-code-actions 'lsp-code-actions-at-point)
   5981 
   5982 (lsp-defun lsp--execute-command ((action &as &Command :command :arguments?))
   5983   "Parse and execute a code ACTION represented as a Command LSP type."
   5984   (let ((server-id (->> (lsp-workspaces)
   5985                         (cl-first)
   5986                         (or lsp--cur-workspace)
   5987                         (lsp--workspace-client)
   5988                         (lsp--client-server-id))))
   5989     (condition-case nil
   5990         (with-no-warnings
   5991           (lsp-execute-command server-id (intern command) arguments?))
   5992       (cl-no-applicable-method
   5993        (if-let ((action-handler (lsp--find-action-handler command)))
   5994            (funcall action-handler action)
   5995          (lsp-send-execute-command command arguments?))))))
   5996 
   5997 (lsp-defun lsp-execute-code-action ((action &as &CodeAction :command? :edit?))
   5998   "Execute code action ACTION. For example, when text under the
   5999 caret has a suggestion to apply a fix from an lsp-server, calling
   6000 this function will do so.
   6001 If ACTION is not set it will be selected from `lsp-code-actions-at-point'.
   6002 Request codeAction/resolve for more info if server supports."
   6003   (interactive (list (lsp--select-action (lsp-code-actions-at-point))))
   6004   (if (and (lsp-feature? "codeAction/resolve")
   6005            (not command?)
   6006            (not edit?))
   6007       (lsp--execute-code-action (lsp-request "codeAction/resolve" action))
   6008     (lsp--execute-code-action action)))
   6009 
   6010 (lsp-defun lsp--execute-code-action ((action &as &CodeAction :command? :edit?))
   6011   "Execute code action ACTION."
   6012   (when edit?
   6013     (lsp--apply-workspace-edit edit? 'code-action))
   6014 
   6015   (cond
   6016    ((stringp command?) (lsp--execute-command action))
   6017    ((lsp-command? command?) (progn
   6018                               (when-let ((action-filter (->> (lsp-workspaces)
   6019                                                              (cl-first)
   6020                                                              (or lsp--cur-workspace)
   6021                                                              (lsp--workspace-client)
   6022                                                              (lsp--client-action-filter))))
   6023                                 (funcall action-filter command?))
   6024                               (lsp--execute-command command?)))))
   6025 
   6026 (lsp-defun lsp-fix-code-action-booleans ((&Command :arguments?) boolean-action-arguments)
   6027   "Patch incorrect boolean argument values in the provided `CodeAction' command
   6028 in place, based on the BOOLEAN-ACTION-ARGUMENTS list. The values
   6029 in this list can be either symbols or lists of symbols that
   6030 represent paths to boolean arguments in code actions:
   6031 
   6032 > (lsp-fix-code-action-booleans command `(:foo :bar (:some :nested :boolean)))
   6033 
   6034 When there are available code actions, the server sends
   6035 `lsp-mode' a list of possible command names and arguments as
   6036 JSON. `lsp-mode' parses all boolean false values as `nil'. As a
   6037 result code action arguments containing falsy values don't
   6038 roundtrip correctly because `lsp-mode' will end up sending null
   6039 values back to the client. This list makes it possible to
   6040 selectively transform `nil' values back into `:json-false'."
   6041   (seq-doseq (path boolean-action-arguments)
   6042     (seq-doseq (args arguments?)
   6043       (lsp--fix-nested-boolean args (if (listp path) path (list path))))))
   6044 
   6045 (defun lsp--fix-nested-boolean (structure path)
   6046   "Traverse STRUCTURE using the paths from the PATH list, changing the value to
   6047 `:json-false' if it was `nil'. PATH should be a list containing
   6048 one or more symbols, and STRUCTURE should be compatible with
   6049 `lsp-member?', `lsp-get', and `lsp-put'."
   6050   (let ((key (car path))
   6051         (rest (cdr path)))
   6052     (if (null rest)
   6053         ;; `lsp-put' returns `nil' both when the key doesn't exist and when the
   6054         ;; value is `nil', so we need to explicitly check its presence here
   6055         (when (and (lsp-member? structure key) (not (lsp-get structure key)))
   6056           (lsp-put structure key :json-false))
   6057       ;; If `key' does not exist, then we'll silently ignore it
   6058       (when-let ((child (lsp-get structure key)))
   6059         (lsp--fix-nested-boolean child rest)))))
   6060 
   6061 (defvar lsp--formatting-indent-alist
   6062   ;; Taken from `dtrt-indent-mode'
   6063   '(
   6064     (ada-mode                   . ada-indent)                       ; Ada
   6065     (ada-ts-mode                . ada-ts-mode-indent-offset)
   6066     (c++-mode                   . c-basic-offset)                   ; C++
   6067     (c++-ts-mode                . c-ts-mode-indent-offset)
   6068     (c-mode                     . c-basic-offset)                   ; C
   6069     (c-ts-mode                  . c-ts-mode-indent-offset)
   6070     (cperl-mode                 . cperl-indent-level)               ; Perl
   6071     (crystal-mode               . crystal-indent-level)             ; Crystal (Ruby)
   6072     (csharp-mode                . c-basic-offset)                   ; C#
   6073     (csharp-tree-sitter-mode    . csharp-tree-sitter-indent-offset) ; C#
   6074     (csharp-ts-mode             . csharp-ts-mode-indent-offset)     ; C# (tree-sitter, Emacs29)
   6075     (css-mode                   . css-indent-offset)                ; CSS
   6076     (d-mode                     . c-basic-offset)                   ; D
   6077     (enh-ruby-mode              . enh-ruby-indent-level)            ; Ruby
   6078     (erlang-mode                . erlang-indent-level)              ; Erlang
   6079     (ess-mode                   . ess-indent-offset)                ; ESS (R)
   6080     (go-ts-mode                 . go-ts-mode-indent-offset)
   6081     (gpr-mode                   . gpr-indent-offset)                ; GNAT Project
   6082     (gpr-ts-mode                . gpr-ts-mode-indent-offset)
   6083     (hack-mode                  . hack-indent-offset)               ; Hack
   6084     (java-mode                  . c-basic-offset)                   ; Java
   6085     (java-ts-mode               . java-ts-mode-indent-offset)
   6086     (jde-mode                   . c-basic-offset)                   ; Java (JDE)
   6087     (js-mode                    . js-indent-level)                  ; JavaScript
   6088     (js-ts-mode                 . js-indent-level)
   6089     (js2-mode                   . js2-basic-offset)                 ; JavaScript-IDE
   6090     (js3-mode                   . js3-indent-level)                 ; JavaScript-IDE
   6091     (json-mode                  . js-indent-level)                  ; JSON
   6092     (json-ts-mode               . json-ts-mode-indent-offset)
   6093     (lua-mode                   . lua-indent-level)                 ; Lua
   6094     (lua-ts-mode                . lua-ts-indent-offset)
   6095     (nxml-mode                  . nxml-child-indent)                ; XML
   6096     (objc-mode                  . c-basic-offset)                   ; Objective C
   6097     (pascal-mode                . pascal-indent-level)              ; Pascal
   6098     (perl-mode                  . perl-indent-level)                ; Perl
   6099     (php-mode                   . c-basic-offset)                   ; PHP
   6100     (php-ts-mode                . php-ts-mode-indent-offset)        ; PHP
   6101     (powershell-mode            . powershell-indent)                ; PowerShell
   6102     (powershell-ts-mode         . powershell-ts-mode-indent-offset) ; PowerShell
   6103     (raku-mode                  . raku-indent-offset)               ; Perl6/Raku
   6104     (ruby-mode                  . ruby-indent-level)                ; Ruby
   6105     (rust-mode                  . rust-indent-offset)               ; Rust
   6106     (rust-ts-mode               . rust-ts-mode-indent-offset)
   6107     (rustic-mode                . rustic-indent-offset)             ; Rust
   6108     (scala-mode                 . scala-indent:step)                ; Scala
   6109     (sgml-mode                  . sgml-basic-offset)                ; SGML
   6110     (sh-mode                    . sh-basic-offset)                  ; Shell Script
   6111     (toml-ts-mode               . toml-ts-mode-indent-offset)
   6112     (typescript-mode            . typescript-indent-level)          ; Typescript
   6113     (typescript-ts-mode         . typescript-ts-mode-indent-offset) ; Typescript (tree-sitter, Emacs29)
   6114     (yaml-mode                  . yaml-indent-offset)               ; YAML
   6115     (yang-mode                  . c-basic-offset)                   ; YANG (yang-mode)
   6116 
   6117     (default                    . standard-indent))                 ; default fallback
   6118   "A mapping from `major-mode' to its indent variable.")
   6119 
   6120 (defun lsp--get-indent-width (mode)
   6121   "Get indentation offset for MODE."
   6122   (or (alist-get mode lsp--formatting-indent-alist)
   6123       (lsp--get-indent-width (or (get mode 'derived-mode-parent) 'default))))
   6124 
   6125 (defun lsp--make-document-formatting-params ()
   6126   "Create document formatting params."
   6127   (lsp-make-document-formatting-params
   6128    :text-document (lsp--text-document-identifier)
   6129    :options (lsp-make-formatting-options
   6130              :tab-size (symbol-value (lsp--get-indent-width major-mode))
   6131              :insert-spaces (lsp-json-bool (not indent-tabs-mode))
   6132              :trim-trailing-whitespace? (lsp-json-bool lsp-trim-trailing-whitespace)
   6133              :insert-final-newline? (lsp-json-bool lsp-insert-final-newline)
   6134              :trim-final-newlines? (lsp-json-bool lsp-trim-final-newlines))))
   6135 
   6136 (defun lsp-format-buffer ()
   6137   "Ask the server to format this document."
   6138   (interactive "*")
   6139   (cond ((lsp-feature? "textDocument/formatting")
   6140          (let ((edits (lsp-request "textDocument/formatting"
   6141                                    (lsp--make-document-formatting-params))))
   6142            (if (seq-empty-p edits)
   6143                (lsp--info "No formatting changes provided")
   6144              (lsp--apply-text-edits edits 'format))))
   6145         ((lsp-feature? "textDocument/rangeFormatting")
   6146          (save-restriction
   6147            (widen)
   6148            (lsp-format-region (point-min) (point-max))))
   6149         (t (signal 'lsp-capability-not-supported (list "documentFormattingProvider")))))
   6150 
   6151 (defun lsp-format-region (s e)
   6152   "Ask the server to format the region, or if none is selected, the current line."
   6153   (interactive "r")
   6154   (let ((edits (lsp-request
   6155                 "textDocument/rangeFormatting"
   6156                 (lsp--make-document-range-formatting-params s e))))
   6157     (if (seq-empty-p edits)
   6158         (lsp--info "No formatting changes provided")
   6159       (lsp--apply-text-edits edits 'format))))
   6160 
   6161 (defmacro lsp-make-interactive-code-action (func-name code-action-kind)
   6162   "Define an interactive function FUNC-NAME that attempts to
   6163 execute a CODE-ACTION-KIND action."
   6164   `(defun ,(intern (concat "lsp-" (symbol-name func-name))) ()
   6165      ,(format "Perform the %s code action, if available." code-action-kind)
   6166      (interactive)
   6167      ;; Even when `lsp-auto-execute-action' is nil, it still makes sense to
   6168      ;; auto-execute here: the user has specified exactly what they want.
   6169      (let ((lsp-auto-execute-action t))
   6170        (condition-case nil
   6171            (lsp-execute-code-action-by-kind ,code-action-kind)
   6172          (lsp-no-code-actions
   6173           (when (called-interactively-p 'any)
   6174             (lsp--info ,(format "%s action not available" code-action-kind))))))))
   6175 
   6176 (lsp-make-interactive-code-action organize-imports "source.organizeImports")
   6177 
   6178 (defun lsp--make-document-range-formatting-params (start end)
   6179   "Make DocumentRangeFormattingParams for selected region."
   6180   (lsp:set-document-range-formatting-params-range (lsp--make-document-formatting-params)
   6181                                                   (lsp--region-to-range start end)))
   6182 
   6183 (defconst lsp--highlight-kind-face
   6184   '((1 . lsp-face-highlight-textual)
   6185     (2 . lsp-face-highlight-read)
   6186     (3 . lsp-face-highlight-write)))
   6187 
   6188 (defun lsp--remove-overlays (name)
   6189   (save-restriction
   6190     (widen)
   6191     (remove-overlays (point-min) (point-max) name t)))
   6192 
   6193 (defun lsp-document-highlight ()
   6194   "Highlight all relevant references to the symbol under point."
   6195   (interactive)
   6196   (lsp--remove-overlays 'lsp-highlight) ;; clear any previous highlights
   6197   (setq lsp--have-document-highlights nil
   6198         lsp--symbol-bounds-of-last-highlight-invocation nil)
   6199   (let ((lsp-enable-symbol-highlighting t))
   6200     (lsp--document-highlight)))
   6201 
   6202 (defun lsp--document-highlight-callback (highlights)
   6203   "Create a callback to process the reply of a
   6204 `textDocument/documentHighlight' message for the buffer BUF.
   6205 A reference is highlighted only if it is visible in a window."
   6206   (lsp--remove-overlays 'lsp-highlight)
   6207 
   6208   (let* ((wins-visible-pos (-map (lambda (win)
   6209                                    (cons (1- (line-number-at-pos (window-start win) t))
   6210                                          (1+ (line-number-at-pos (window-end win) t))))
   6211                                  (get-buffer-window-list nil nil 'visible))))
   6212     (setq lsp--have-document-highlights t)
   6213     (-map
   6214      (-lambda ((&DocumentHighlight :range (&Range :start (start &as &Position :line start-line)
   6215                                                   :end (end &as &Position :line end-line))
   6216                                    :kind?))
   6217        (-map
   6218         (-lambda ((start-window . end-window))
   6219           ;; Make the overlay only if the reference is visible
   6220           (let ((start-point (lsp--position-to-point start))
   6221                 (end-point (lsp--position-to-point end)))
   6222             (when (and (> (1+ start-line) start-window)
   6223                        (< (1+ end-line) end-window)
   6224                        (not (and lsp-symbol-highlighting-skip-current
   6225                                  (<= start-point (point) end-point))))
   6226               (-doto (make-overlay start-point end-point)
   6227                 (overlay-put 'face (cdr (assq (or kind? 1) lsp--highlight-kind-face)))
   6228                 (overlay-put 'lsp-highlight t)))))
   6229         wins-visible-pos))
   6230      highlights)))
   6231 
   6232 (defcustom lsp-symbol-kinds
   6233   '((1 . "File")
   6234     (2 . "Module")
   6235     (3 . "Namespace")
   6236     (4 . "Package")
   6237     (5 . "Class")
   6238     (6 . "Method")
   6239     (7 . "Property")
   6240     (8 . "Field")
   6241     (9 . "Constructor")
   6242     (10 . "Enum")
   6243     (11 . "Interface")
   6244     (12 . "Function")
   6245     (13 . "Variable")
   6246     (14 . "Constant")
   6247     (15 . "String")
   6248     (16 . "Number")
   6249     (17 . "Boolean")
   6250     (18 . "Array")
   6251     (19 . "Object")
   6252     (20 . "Key")
   6253     (21 . "Null")
   6254     (22 . "Enum Member")
   6255     (23 . "Struct")
   6256     (24 . "Event")
   6257     (25 . "Operator")
   6258     (26 . "Type Parameter"))
   6259   "Alist mapping SymbolKinds to human-readable strings.
   6260 Various Symbol objects in the LSP protocol have an integral type,
   6261 specifying what they are. This alist maps such type integrals to
   6262 readable representations of them. See
   6263 `https://microsoft.github.io/language-server-protocol/specifications/specification-current/',
   6264 namespace SymbolKind."
   6265   :group 'lsp-mode
   6266   :type '(alist :key-type integer :value-type string))
   6267 (defalias 'lsp--symbol-kind 'lsp-symbol-kinds)
   6268 
   6269 (lsp-defun lsp--symbol-information-to-xref
   6270   ((&SymbolInformation :kind :name
   6271                        :location (&Location :uri :range (&Range :start
   6272                                                                 (&Position :line :character)))))
   6273   "Return a `xref-item' from SYMBOL information."
   6274   (xref-make (format "[%s] %s" (alist-get kind lsp-symbol-kinds) name)
   6275              (xref-make-file-location (lsp--uri-to-path uri)
   6276                                       line
   6277                                       character)))
   6278 
   6279 (defun lsp--get-document-symbols ()
   6280   "Get document symbols.
   6281 
   6282 If the buffer has not been modified since symbols were last
   6283 retrieved, simply return the latest result.
   6284 
   6285 Else, if the request was initiated by Imenu updating its menu-bar
   6286 entry, perform it asynchronously; i.e., give Imenu the latest
   6287 result and then force a refresh when a new one is available.
   6288 
   6289 Else (e.g., due to interactive use of `imenu' or `xref'),
   6290 perform the request synchronously."
   6291   (if (= (buffer-chars-modified-tick) lsp--document-symbols-tick)
   6292       lsp--document-symbols
   6293     (let ((method "textDocument/documentSymbol")
   6294           (params `(:textDocument ,(lsp--text-document-identifier)))
   6295           (tick (buffer-chars-modified-tick)))
   6296       (if (not lsp--document-symbols-request-async)
   6297           (prog1
   6298               (setq lsp--document-symbols (lsp-request method params))
   6299             (setq lsp--document-symbols-tick tick))
   6300         (lsp-request-async method params
   6301                            (lambda (document-symbols)
   6302                              (setq lsp--document-symbols document-symbols
   6303                                    lsp--document-symbols-tick tick)
   6304                              (lsp--imenu-refresh))
   6305                            :mode 'alive
   6306                            :cancel-token :document-symbols)
   6307         lsp--document-symbols))))
   6308 
   6309 (advice-add 'imenu-update-menubar :around
   6310             (lambda (oldfun &rest r)
   6311               (let ((lsp--document-symbols-request-async t))
   6312                 (apply oldfun r))))
   6313 
   6314 (defun lsp--document-symbols->document-symbols-hierarchy (document-symbols current-position)
   6315   "Convert DOCUMENT-SYMBOLS to symbols hierarchy on CURRENT-POSITION."
   6316   (-let (((symbol &as &DocumentSymbol? :children?)
   6317           (seq-find (-lambda ((&DocumentSymbol :range))
   6318                       (lsp-point-in-range? current-position range))
   6319                     document-symbols)))
   6320     (if children?
   6321         (cons symbol (lsp--document-symbols->document-symbols-hierarchy children? current-position))
   6322       (when symbol
   6323         (list symbol)))))
   6324 
   6325 (lsp-defun lsp--symbol-information->document-symbol ((&SymbolInformation :name :kind :location :container-name? :deprecated?))
   6326   "Convert a SymbolInformation to a DocumentInformation"
   6327   (lsp-make-document-symbol :name name
   6328                             :kind kind
   6329                             :range (lsp:location-range location)
   6330                             :children? nil
   6331                             :deprecated? deprecated?
   6332                             :selection-range (lsp:location-range location)
   6333                             :detail? container-name?))
   6334 
   6335 (defun lsp--symbols-informations->document-symbols-hierarchy (symbols-informations current-position)
   6336   "Convert SYMBOLS-INFORMATIONS to symbols hierarchy on CURRENT-POSITION."
   6337   (--> symbols-informations
   6338     (-keep (-lambda ((symbol &as &SymbolInformation :location (&Location :range)))
   6339              (when (lsp-point-in-range? current-position range)
   6340                (lsp--symbol-information->document-symbol symbol)))
   6341            it)
   6342     (sort it (-lambda ((&DocumentSymbol :range (&Range :start a-start-position :end a-end-position))
   6343                        (&DocumentSymbol :range (&Range :start b-start-position :end b-end-position)))
   6344                (and (lsp--position-compare b-start-position a-start-position)
   6345                     (lsp--position-compare a-end-position b-end-position))))))
   6346 
   6347 (defun lsp--symbols->document-symbols-hierarchy (symbols)
   6348   "Convert SYMBOLS to symbols-hierarchy."
   6349   (when-let ((first-symbol (lsp-seq-first symbols)))
   6350     (let ((cur-position (lsp-make-position :line (plist-get (lsp--cur-position) :line)
   6351                                            :character (plist-get (lsp--cur-position) :character))))
   6352       (if (lsp-symbol-information? first-symbol)
   6353           (lsp--symbols-informations->document-symbols-hierarchy symbols cur-position)
   6354         (lsp--document-symbols->document-symbols-hierarchy symbols cur-position)))))
   6355 
   6356 (defun lsp--xref-backend () 'xref-lsp)
   6357 
   6358 (cl-defmethod xref-backend-identifier-at-point ((_backend (eql xref-lsp)))
   6359   (propertize (or (thing-at-point 'symbol) "")
   6360               'identifier-at-point t))
   6361 
   6362 (defun lsp--xref-elements-index (symbols path)
   6363   (-mapcat
   6364    (-lambda (sym)
   6365      (pcase-exhaustive sym
   6366        ((DocumentSymbol :name :children? :selection-range (Range :start))
   6367         (cons (cons (concat path name)
   6368                     (lsp--position-to-point start))
   6369               (lsp--xref-elements-index children? (concat path name " / "))))
   6370        ((SymbolInformation :name :location (Location :range (Range :start)))
   6371         (list (cons (concat path name)
   6372                     (lsp--position-to-point start))))))
   6373    symbols))
   6374 
   6375 (defvar-local lsp--symbols-cache nil)
   6376 
   6377 (cl-defmethod xref-backend-identifier-completion-table ((_backend (eql xref-lsp)))
   6378   (if (lsp--find-workspaces-for "textDocument/documentSymbol")
   6379       (progn
   6380         (setq lsp--symbols-cache (lsp--xref-elements-index
   6381                                   (lsp--get-document-symbols) nil))
   6382         lsp--symbols-cache)
   6383     (list (propertize (or (thing-at-point 'symbol) "")
   6384                       'identifier-at-point t))))
   6385 
   6386 (cl-defmethod xref-backend-definitions ((_backend (eql xref-lsp)) identifier)
   6387   (save-excursion
   6388     (unless (get-text-property 0 'identifier-at-point identifier)
   6389       (goto-char (cl-rest (or (assoc identifier lsp--symbols-cache)
   6390                               (user-error "Unable to find symbol %s in current document" identifier)))))
   6391     (lsp--locations-to-xref-items (lsp-request "textDocument/definition"
   6392                                                (lsp--text-document-position-params)))))
   6393 
   6394 (cl-defmethod xref-backend-references ((_backend (eql xref-lsp)) identifier)
   6395   (save-excursion
   6396     (unless (get-text-property 0 'identifier-at-point identifier)
   6397       (goto-char (cl-rest (or (assoc identifier lsp--symbols-cache)
   6398                               (user-error "Unable to find symbol %s" identifier)))))
   6399     (lsp--locations-to-xref-items (lsp-request "textDocument/references"
   6400                                                (lsp--make-reference-params nil lsp-references-exclude-definition)))))
   6401 
   6402 (cl-defmethod xref-backend-apropos ((_backend (eql xref-lsp)) pattern)
   6403   (seq-map #'lsp--symbol-information-to-xref
   6404            (lsp-request "workspace/symbol" `(:query ,pattern))))
   6405 
   6406 (defcustom lsp-rename-use-prepare t
   6407   "Whether `lsp-rename' should do a prepareRename first.
   6408 For some language servers, textDocument/prepareRename might be
   6409 too slow, in which case this variable may be set to nil.
   6410 `lsp-rename' will then use `thing-at-point' `symbol' to determine
   6411 the symbol to rename at point."
   6412   :group 'lsp-mode
   6413   :type 'boolean)
   6414 
   6415 (defun lsp--get-symbol-to-rename ()
   6416   "Get a symbol to rename and placeholder at point.
   6417 Returns a cons ((START . END) . PLACEHOLDER?), and nil if
   6418 renaming is generally supported but cannot be done at point.
   6419 START and END are the bounds of the identifiers being renamed,
   6420 while PLACEHOLDER?, is either nil or a string suggested by the
   6421 language server as the initial input of a new-name prompt."
   6422   (unless (lsp-feature? "textDocument/rename")
   6423     (error "The connected server(s) doesn't support renaming"))
   6424   (if (and lsp-rename-use-prepare (lsp-feature? "textDocument/prepareRename"))
   6425       (when-let ((response
   6426                   (lsp-request "textDocument/prepareRename"
   6427                                (lsp--text-document-position-params))))
   6428         (let* ((bounds (lsp--range-to-region
   6429                         (if (lsp-range? response)
   6430                             response
   6431                           (lsp:prepare-rename-result-range response))))
   6432                (placeholder
   6433                 (and (not (lsp-range? response))
   6434                      (lsp:prepare-rename-result-placeholder response))))
   6435           (cons bounds placeholder)))
   6436     (when-let ((bounds (bounds-of-thing-at-point 'symbol)))
   6437       (cons bounds nil))))
   6438 
   6439 (defface lsp-face-rename '((t :underline t))
   6440   "Face used to highlight the identifier being renamed.
   6441 Renaming can be done using `lsp-rename'."
   6442   :group 'lsp-mode)
   6443 
   6444 (defface lsp-rename-placeholder-face '((t :inherit font-lock-variable-name-face))
   6445   "Face used to display the rename placeholder in.
   6446 When calling `lsp-rename' interactively, this will be the face of
   6447 the new name."
   6448   :group 'lsp-mode)
   6449 
   6450 (defvar lsp-rename-history '()
   6451   "History for `lsp--read-rename'.")
   6452 
   6453 (defun lsp--read-rename (at-point)
   6454   "Read a new name for a `lsp-rename' at `point' from the user.
   6455 AT-POINT shall be a structure as returned by
   6456 `lsp--get-symbol-to-rename'.
   6457 
   6458 Returns a string, which should be the new name for the identifier
   6459 at point. If renaming cannot be done at point (as determined from
   6460 AT-POINT), throw a `user-error'.
   6461 
   6462 This function is for use in `lsp-rename' only, and shall not be
   6463 relied upon."
   6464   (unless at-point
   6465     (user-error "`lsp-rename' is invalid here"))
   6466   (-let* ((((start . end) . placeholder?) at-point)
   6467           ;; Do the `buffer-substring' first to not include `lsp-face-rename'
   6468           (rename-me (buffer-substring start end))
   6469           (placeholder (or placeholder? rename-me))
   6470           (placeholder (propertize placeholder 'face 'lsp-rename-placeholder-face))
   6471 
   6472           overlay)
   6473     ;; We need unwind protect, as the user might cancel here, causing the
   6474     ;; overlay to linger.
   6475     (unwind-protect
   6476         (progn
   6477           (setq overlay (make-overlay start end))
   6478           (overlay-put overlay 'face 'lsp-face-rename)
   6479 
   6480           (read-string (format "Rename %s to: " rename-me) placeholder
   6481                        'lsp-rename-history))
   6482       (and overlay (delete-overlay overlay)))))
   6483 
   6484 (defun lsp-rename (newname)
   6485   "Rename the symbol (and all references to it) under point to NEWNAME."
   6486   (interactive (list (lsp--read-rename (lsp--get-symbol-to-rename))))
   6487   (when-let ((edits (lsp-request "textDocument/rename"
   6488                                  `( :textDocument ,(lsp--text-document-identifier)
   6489                                     :position ,(lsp--cur-position)
   6490                                     :newName ,newname))))
   6491     (lsp--apply-workspace-edit edits 'rename)))
   6492 
   6493 (defun lsp--on-rename-file (old-func old-name new-name &optional ok-if-already-exists?)
   6494   "Advice around function `rename-file'.
   6495 Applies OLD-FUNC with OLD-NAME, NEW-NAME and OK-IF-ALREADY-EXISTS?.
   6496 
   6497 This advice sends workspace/willRenameFiles before renaming file
   6498 to check if server wants to apply any workspaceEdits after renamed."
   6499   (if (and lsp-apply-edits-after-file-operations
   6500            (lsp--send-will-rename-files-p old-name))
   6501       (let ((params (lsp-make-rename-files-params
   6502                      :files (vector (lsp-make-file-rename
   6503                                      :oldUri (lsp--path-to-uri old-name)
   6504                                      :newUri (lsp--path-to-uri new-name))))))
   6505         (when-let ((edits (lsp-request "workspace/willRenameFiles" params)))
   6506           (lsp--apply-workspace-edit edits 'rename-file)
   6507           (funcall old-func old-name new-name ok-if-already-exists?)
   6508           (when (lsp--send-did-rename-files-p)
   6509             (lsp-notify "workspace/didRenameFiles" params))))
   6510     (funcall old-func old-name new-name ok-if-already-exists?)))
   6511 
   6512 (advice-add 'rename-file :around #'lsp--on-rename-file)
   6513 
   6514 (defcustom lsp-xref-force-references nil
   6515   "If non-nil threat everything as references(e. g. jump if only one item.)"
   6516   :group 'lsp-mode
   6517   :type 'boolean)
   6518 
   6519 (defun lsp-show-xrefs (xrefs display-action references?)
   6520   (unless (region-active-p) (push-mark nil t))
   6521   (if (boundp 'xref-show-definitions-function)
   6522       (with-no-warnings
   6523         (xref-push-marker-stack)
   6524         (funcall (if (and references? (not lsp-xref-force-references))
   6525                      xref-show-xrefs-function
   6526                    xref-show-definitions-function)
   6527                  (-const xrefs)
   6528                  `((window . ,(selected-window))
   6529                    (display-action . ,display-action)
   6530                    ,(if (and references? (not lsp-xref-force-references))
   6531                         `(auto-jump . ,xref-auto-jump-to-first-xref)
   6532                       `(auto-jump . ,xref-auto-jump-to-first-definition)))))
   6533     (xref--show-xrefs xrefs display-action)))
   6534 
   6535 (cl-defmethod seq-empty-p ((ht hash-table))
   6536   "Function `seq-empty-p' for hash-table."
   6537   (hash-table-empty-p ht))
   6538 
   6539 (cl-defun lsp-find-locations (method &optional extra &key display-action references?)
   6540   "Send request named METHOD and get cross references of the symbol under point.
   6541 EXTRA is a plist of extra parameters.
   6542 REFERENCES? t when METHOD returns references."
   6543   (let ((loc (lsp-request method
   6544                           (append (lsp--text-document-position-params) extra))))
   6545     (if (seq-empty-p loc)
   6546         (lsp--error "Not found for: %s" (or (thing-at-point 'symbol t) ""))
   6547       (lsp-show-xrefs (lsp--locations-to-xref-items loc) display-action references?))))
   6548 
   6549 (cl-defun lsp-find-declaration (&key display-action)
   6550   "Find declarations of the symbol under point."
   6551   (interactive)
   6552   (lsp-find-locations "textDocument/declaration" nil :display-action display-action))
   6553 
   6554 (cl-defun lsp-find-definition (&key display-action)
   6555   "Find definitions of the symbol under point."
   6556   (interactive)
   6557   (lsp-find-locations "textDocument/definition" nil :display-action display-action))
   6558 
   6559 (defun lsp-find-definition-mouse (click)
   6560   "Click to start `lsp-find-definition' at clicked point."
   6561   (interactive "e")
   6562   (let* ((ec (event-start click))
   6563          (p1 (posn-point ec))
   6564          (w1 (posn-window ec)))
   6565     (select-window w1)
   6566     (goto-char p1)
   6567     (lsp-find-definition)))
   6568 
   6569 (cl-defun lsp-find-implementation (&key display-action)
   6570   "Find implementations of the symbol under point."
   6571   (interactive)
   6572   (lsp-find-locations "textDocument/implementation"
   6573                       nil
   6574                       :display-action display-action
   6575                       :references? t))
   6576 
   6577 (cl-defun lsp-find-references (&optional exclude-declaration &key display-action)
   6578   "Find references of the symbol under point."
   6579   (interactive "P")
   6580   (lsp-find-locations "textDocument/references"
   6581                       (list :context `(:includeDeclaration ,(lsp-json-bool (not (or exclude-declaration lsp-references-exclude-definition)))))
   6582                       :display-action display-action
   6583                       :references? t))
   6584 
   6585 (cl-defun lsp-find-type-definition (&key display-action)
   6586   "Find type definitions of the symbol under point."
   6587   (interactive)
   6588   (lsp-find-locations "textDocument/typeDefinition" nil :display-action display-action))
   6589 
   6590 (defalias 'lsp-find-custom #'lsp-find-locations)
   6591 (defalias 'lsp-goto-implementation #'lsp-find-implementation)
   6592 (defalias 'lsp-goto-type-definition #'lsp-find-type-definition)
   6593 
   6594 (with-eval-after-load 'evil
   6595   (evil-set-command-property 'lsp-find-definition :jump t)
   6596   (evil-set-command-property 'lsp-find-implementation :jump t)
   6597   (evil-set-command-property 'lsp-find-references :jump t)
   6598   (evil-set-command-property 'lsp-find-type-definition :jump t))
   6599 
   6600 (defun lsp--workspace-method-supported? (check-command method capability workspace)
   6601   (with-lsp-workspace workspace
   6602     (if check-command
   6603         (funcall check-command workspace)
   6604       (or
   6605        (when capability (lsp--capability capability))
   6606        (lsp--registered-capability method)
   6607        (and (not capability) (not check-command))))))
   6608 
   6609 (defun lsp-disable-method-for-server (method server-id)
   6610   "Disable METHOD for SERVER-ID."
   6611   (cl-callf
   6612       (lambda (reqs)
   6613         (-let (((&plist :check-command :capability) reqs))
   6614           (list :check-command
   6615                 (lambda (workspace)
   6616                   (unless (-> workspace
   6617                               lsp--workspace-client
   6618                               lsp--client-server-id
   6619                               (eq server-id))
   6620                     (lsp--workspace-method-supported? check-command
   6621                                                       method
   6622                                                       capability
   6623                                                       workspace))))))
   6624       (alist-get method lsp-method-requirements nil nil 'string=)))
   6625 
   6626 (defun lsp--find-workspaces-for (msg-or-method)
   6627   "Find all workspaces in the current project that can handle MSG."
   6628   (let ((method (if (stringp msg-or-method)
   6629                     msg-or-method
   6630                   (plist-get msg-or-method :method))))
   6631     (-if-let (reqs (cdr (assoc method lsp-method-requirements)))
   6632         (-let (((&plist :capability :check-command) reqs))
   6633           (-filter
   6634            (-partial #'lsp--workspace-method-supported?
   6635                      check-command method capability)
   6636            (lsp-workspaces)))
   6637       (lsp-workspaces))))
   6638 
   6639 (defun lsp-can-execute-command? (command-name)
   6640   "Returns non-nil if current language server(s) can execute COMMAND-NAME.
   6641 The command is executed via `workspace/executeCommand'"
   6642   (cl-position
   6643    command-name
   6644    (lsp:execute-command-options-commands
   6645     (lsp:server-capabilities-execute-command-provider?
   6646      (lsp--server-capabilities)))
   6647    :test #'equal))
   6648 
   6649 (defalias 'lsp-feature? 'lsp--find-workspaces-for)
   6650 
   6651 (cl-defmethod lsp-execute-command (_server _command _arguments)
   6652   "Dispatch COMMAND execution."
   6653   (signal 'cl-no-applicable-method nil))
   6654 
   6655 (defun lsp-workspace-command-execute (command &optional args)
   6656   "Execute workspace COMMAND with ARGS."
   6657   (condition-case-unless-debug err
   6658       (let ((params (if args
   6659                         (list :command command :arguments args)
   6660                       (list :command command))))
   6661         (lsp-request "workspace/executeCommand" params))
   6662     (error
   6663      (error "`workspace/executeCommand' with `%s' failed.\n\n%S"
   6664             command err))))
   6665 
   6666 (defun lsp-send-execute-command (command &optional args)
   6667   "Create and send a `workspace/executeCommand' message having command COMMAND
   6668 and optional ARGS."
   6669   (lsp-workspace-command-execute command args))
   6670 
   6671 (defalias 'lsp-point-to-position #'lsp--point-to-position)
   6672 (defalias 'lsp-text-document-identifier #'lsp--text-document-identifier)
   6673 (defalias 'lsp--send-execute-command #'lsp-send-execute-command)
   6674 (defalias 'lsp-on-open #'lsp--text-document-did-open)
   6675 (defalias 'lsp-on-save #'lsp--text-document-did-save)
   6676 
   6677 (defun lsp--set-configuration (settings)
   6678   "Set the SETTINGS for the lsp server."
   6679   (lsp-notify "workspace/didChangeConfiguration" `(:settings ,settings)))
   6680 
   6681 (defun lsp-current-buffer ()
   6682   (or lsp--virtual-buffer
   6683       (current-buffer)))
   6684 
   6685 (defun lsp-buffer-live-p (buffer-id)
   6686   (if-let ((buffer-live (plist-get buffer-id :buffer-live?)))
   6687       (funcall buffer-live buffer-id)
   6688     (buffer-live-p buffer-id)))
   6689 
   6690 (defun lsp--on-set-visited-file-name (old-func &rest args)
   6691   "Advice around function `set-visited-file-name'.
   6692 
   6693 This advice sends textDocument/didClose for the old file and
   6694 textDocument/didOpen for the new file."
   6695   (when lsp--cur-workspace
   6696     (lsp--text-document-did-close t))
   6697   (prog1 (apply old-func args)
   6698     (when lsp--cur-workspace
   6699       (lsp--text-document-did-open))))
   6700 
   6701 (advice-add 'set-visited-file-name :around #'lsp--on-set-visited-file-name)
   6702 
   6703 (defvar lsp--flushing-delayed-changes nil)
   6704 
   6705 (defun lsp--send-no-wait (message proc)
   6706   "Send MESSAGE to PROC without waiting for further output."
   6707 
   6708   (unless lsp--flushing-delayed-changes
   6709     (let ((lsp--flushing-delayed-changes t))
   6710       (lsp--flush-delayed-changes)))
   6711   (lsp-process-send proc message))
   6712 
   6713 (define-error 'lsp-parse-error
   6714   "Error parsing message from language server" 'lsp-error)
   6715 (define-error 'lsp-unknown-message-type
   6716   "Unknown message type" '(lsp-error lsp-parse-error))
   6717 (define-error 'lsp-unknown-json-rpc-version
   6718   "Unknown JSON-RPC protocol version" '(lsp-error lsp-parse-error))
   6719 (define-error 'lsp-no-content-length
   6720   "Content-Length header missing in message" '(lsp-error lsp-parse-error))
   6721 (define-error 'lsp-invalid-header-name
   6722   "Invalid header name" '(lsp-error lsp-parse-error))
   6723 
   6724 ;;  id  method
   6725 ;;   x    x     request
   6726 ;;   x    .     response
   6727 ;;   .    x     notification
   6728 (defun lsp--get-message-type (json-data)
   6729   "Get the message type from JSON-DATA."
   6730   (if (lsp:json-message-id? json-data)
   6731       (if (lsp:json-message-error? json-data)
   6732           'response-error
   6733         (if (lsp:json-message-method? json-data)
   6734             'request
   6735           'response))
   6736     'notification))
   6737 
   6738 (defconst lsp--default-notification-handlers
   6739   (ht ("window/showMessage" #'lsp--window-show-message)
   6740       ("window/logMessage" #'lsp--window-log-message)
   6741       ("window/showInputBox" #'lsp--window-show-input-box)
   6742       ("window/showQuickPick" #'lsp--window-show-quick-pick)
   6743       ("textDocument/publishDiagnostics" #'lsp--on-diagnostics)
   6744       ("textDocument/diagnosticsEnd" #'ignore)
   6745       ("textDocument/diagnosticsBegin" #'ignore)
   6746       ("telemetry/event" #'ignore)
   6747       ("$/progress" (lambda (workspace params)
   6748                       (funcall lsp-progress-function workspace params)))))
   6749 
   6750 (lsp-defun lsp--on-notification (workspace (&JSONNotification :params :method))
   6751   "Call the appropriate handler for NOTIFICATION."
   6752   (-let ((client (lsp--workspace-client workspace)))
   6753     (when (lsp--log-io-p method)
   6754       (lsp--log-entry-new (lsp--make-log-entry method nil params 'incoming-notif)
   6755                           lsp--cur-workspace))
   6756     (if-let ((handler (or (gethash method (lsp--client-notification-handlers client))
   6757                           (gethash method lsp--default-notification-handlers))))
   6758         (funcall handler workspace params)
   6759       (when (and method (not (string-prefix-p "$" method)))
   6760         (lsp-warn "Unknown notification: %s" method)))))
   6761 
   6762 (lsp-defun lsp--build-workspace-configuration-response ((&ConfigurationParams :items))
   6763   "Get section configuration.
   6764 PARAMS are the `workspace/configuration' request params"
   6765   (->> items
   6766        (-map (-lambda ((&ConfigurationItem :section?))
   6767                (-let* ((path-parts (split-string section? "\\."))
   6768                        (path-without-last (s-join "." (-slice path-parts 0 -1)))
   6769                        (path-parts-len (length path-parts)))
   6770                  (cond
   6771                   ((<= path-parts-len 1)
   6772                    (ht-get (lsp-configuration-section section?)
   6773                            (car-safe path-parts)
   6774                            (ht-create)))
   6775                   ((> path-parts-len 1)
   6776                    (when-let ((section (lsp-configuration-section path-without-last))
   6777                               (keys path-parts))
   6778                      (while (and keys section)
   6779                        (setf section (ht-get section (pop keys))))
   6780                      section))))))
   6781        (apply #'vector)))
   6782 
   6783 (defun lsp--ms-since (timestamp)
   6784   "Integer number of milliseconds since TIMESTAMP.  Fractions discarded."
   6785   (floor (* 1000 (float-time (time-since timestamp)))))
   6786 
   6787 (defun lsp--send-request-response (workspace recv-time request response)
   6788   "Send the RESPONSE for REQUEST in WORKSPACE and log if needed."
   6789   (-let* (((&JSONResponse :params :method :id) request)
   6790           (process (lsp--workspace-proc workspace))
   6791           (response (lsp--make-response id response))
   6792           (req-entry (and lsp-log-io
   6793                           (lsp--make-log-entry method id params 'incoming-req)))
   6794           (resp-entry (and lsp-log-io
   6795                            (lsp--make-log-entry method id response 'outgoing-resp
   6796                                                 (lsp--ms-since recv-time)))))
   6797     ;; Send response to the server.
   6798     (when (lsp--log-io-p method)
   6799       (lsp--log-entry-new req-entry workspace)
   6800       (lsp--log-entry-new resp-entry workspace))
   6801     (lsp--send-no-wait response process)))
   6802 
   6803 (lsp-defun lsp--on-request (workspace (request &as &JSONRequest :params :method))
   6804   "Call the appropriate handler for REQUEST, and send the return value to the
   6805 server. WORKSPACE is the active workspace."
   6806   (-let* ((recv-time (current-time))
   6807           (client (lsp--workspace-client workspace))
   6808           (buffers (lsp--workspace-buffers workspace))
   6809           handler
   6810           (response (cond
   6811                      ((setq handler (gethash method (lsp--client-request-handlers client) nil))
   6812                       (funcall handler workspace params))
   6813                      ((setq handler (gethash method (lsp--client-async-request-handlers client) nil))
   6814                       (funcall handler workspace params
   6815                                (-partial #'lsp--send-request-response
   6816                                          workspace recv-time request))
   6817                       'delay-response)
   6818                      ((equal method "client/registerCapability")
   6819                       (mapc #'lsp--server-register-capability
   6820                             (lsp:registration-params-registrations params))
   6821                       (mapc (lambda (buf)
   6822                               (when (lsp-buffer-live-p buf)
   6823                                 (lsp-with-current-buffer buf
   6824                                   (lsp-unconfig-buffer)
   6825                                   (lsp-configure-buffer))))
   6826                             buffers)
   6827                       nil)
   6828                      ((equal method "window/showMessageRequest")
   6829                       (let ((choice (lsp--window-log-message-request params)))
   6830                         `(:title ,choice)))
   6831                      ((equal method "window/showDocument")
   6832                       (let ((success? (lsp--window-show-document params)))
   6833                         (lsp-make-show-document-result :success (or success?
   6834                                                                     :json-false))))
   6835                      ((equal method "client/unregisterCapability")
   6836                       (mapc #'lsp--server-unregister-capability
   6837                             (lsp:unregistration-params-unregisterations params))
   6838                       (mapc (lambda (buf)
   6839                               (when (lsp-buffer-live-p buf)
   6840                                 (lsp-with-current-buffer buf
   6841                                   (lsp-unconfig-buffer)
   6842                                   (lsp-configure-buffer))))
   6843                             buffers)
   6844                       nil)
   6845                      ((equal method "workspace/applyEdit")
   6846                       (list :applied (condition-case err
   6847                                          (prog1 t
   6848                                            (lsp--apply-workspace-edit (lsp:apply-workspace-edit-params-edit params) 'server-requested))
   6849                                        (error
   6850                                         (lsp--error "Failed to apply edits with message %s"
   6851                                                     (error-message-string err))
   6852                                         :json-false))))
   6853                      ((equal method "workspace/configuration")
   6854                       (with-lsp-workspace workspace
   6855                         (if-let ((buf (car buffers)))
   6856                             (lsp-with-current-buffer buf
   6857                               (lsp--build-workspace-configuration-response params))
   6858                           (lsp--with-workspace-temp-buffer (lsp--workspace-root workspace)
   6859                             (lsp--build-workspace-configuration-response params)))))
   6860                      ((equal method "workspace/workspaceFolders")
   6861                       (let ((folders (or (-> workspace
   6862                                              (lsp--workspace-client)
   6863                                              (lsp--client-server-id)
   6864                                              (gethash (lsp-session-server-id->folders (lsp-session))))
   6865                                          (lsp-session-folders (lsp-session)))))
   6866                         (->> folders
   6867                              (-distinct)
   6868                              (-map (lambda (folder)
   6869                                      (list :uri (lsp--path-to-uri folder))))
   6870                              (apply #'vector))))
   6871                      ((equal method "window/workDoneProgress/create")
   6872                       nil ;; no specific reply, no processing required
   6873                       )
   6874                      ((equal method "workspace/semanticTokens/refresh")
   6875                       (when (and lsp-semantic-tokens-enable
   6876                                  (fboundp 'lsp--semantic-tokens-on-refresh))
   6877                         (lsp--semantic-tokens-on-refresh workspace))
   6878                       nil)
   6879                      ((equal method "workspace/codeLens/refresh")
   6880                       (when (and lsp-lens-enable
   6881                                  (fboundp 'lsp--lens-on-refresh))
   6882                         (lsp--lens-on-refresh workspace))
   6883                       nil)
   6884                      (t (lsp-warn "Unknown request method: %s" method) nil))))
   6885     ;; Send response to the server.
   6886     (unless (eq response 'delay-response)
   6887       (lsp--send-request-response workspace recv-time request response))))
   6888 
   6889 (lsp-defun lsp--error-string ((&JSONError :message :code))
   6890   "Format ERR as a user friendly string."
   6891   (format "Error from the Language Server: %s (%s)"
   6892           message
   6893           (or (car (alist-get code lsp--errors)) "Unknown error")))
   6894 
   6895 (defun lsp--get-body-length (headers)
   6896   (let ((content-length (cdr (assoc "Content-Length" headers))))
   6897     (if content-length
   6898         (string-to-number content-length)
   6899 
   6900       ;; This usually means either the server or our parser is
   6901       ;; screwed up with a previous Content-Length
   6902       (error "No Content-Length header"))))
   6903 
   6904 (defun lsp--parse-header (s)
   6905   "Parse string S as a LSP (KEY . VAL) header."
   6906   (let ((pos (string-match "\:" s))
   6907         key val)
   6908     (unless pos
   6909       (signal 'lsp-invalid-header-name (list s)))
   6910     (setq key (substring s 0 pos)
   6911           val (s-trim-left (substring s (+ 1 pos))))
   6912     (when (equal key "Content-Length")
   6913       (cl-assert (cl-loop for c across val
   6914                           when (or (> c ?9) (< c ?0)) return nil
   6915                           finally return t)
   6916                  nil (format "Invalid Content-Length value: %s" val)))
   6917     (cons key val)))
   6918 
   6919 (defmacro lsp--read-json (str)
   6920   "Read json string STR."
   6921   (if (progn
   6922         (require 'json)
   6923         (fboundp 'json-parse-string))
   6924       `(json-parse-string ,str
   6925                           :object-type (if lsp-use-plists
   6926                                            'plist
   6927                                          'hash-table)
   6928                           :null-object nil
   6929                           :false-object nil)
   6930     `(let ((json-array-type 'vector)
   6931            (json-object-type (if lsp-use-plists
   6932                                  'plist
   6933                                'hash-table))
   6934            (json-false nil))
   6935        (json-read-from-string ,str))))
   6936 
   6937 (defmacro lsp-json-read-buffer ()
   6938   "Read json from the current buffer."
   6939   (if (progn
   6940         (require 'json)
   6941         (fboundp 'json-parse-buffer))
   6942       `(json-parse-buffer :object-type (if lsp-use-plists
   6943                                            'plist
   6944                                          'hash-table)
   6945                           :null-object nil
   6946                           :false-object nil)
   6947     `(let ((json-array-type 'vector)
   6948            (json-object-type (if lsp-use-plists
   6949                                  'plist
   6950                                'hash-table))
   6951            (json-false nil))
   6952        (json-read))))
   6953 
   6954 (defun lsp--read-json-file (file-path)
   6955   "Read json file."
   6956   (-> file-path
   6957     (f-read-text)
   6958     (lsp--read-json)))
   6959 
   6960 (defun lsp--parser-on-message (json-data workspace)
   6961   "Called when the parser P read a complete MSG from the server."
   6962   (with-demoted-errors "Error processing message %S."
   6963     (with-lsp-workspace workspace
   6964       (let* ((client (lsp--workspace-client workspace))
   6965              (id (--when-let (lsp:json-response-id json-data)
   6966                    (if (stringp it) (string-to-number it) it)))
   6967              (data (lsp:json-response-result json-data)))
   6968         (pcase (lsp--get-message-type json-data)
   6969           ('response
   6970            (cl-assert id)
   6971            (-let [(callback _ method _ before-send) (gethash id (lsp--client-response-handlers client))]
   6972              (when (lsp--log-io-p method)
   6973                (lsp--log-entry-new
   6974                 (lsp--make-log-entry method id data 'incoming-resp
   6975                                      (lsp--ms-since before-send))
   6976                 workspace))
   6977              (when callback
   6978                (remhash id (lsp--client-response-handlers client))
   6979                (funcall callback (lsp:json-response-result json-data)))))
   6980           ('response-error
   6981            (cl-assert id)
   6982            (-let [(_ callback method _ before-send) (gethash id (lsp--client-response-handlers client))]
   6983              (when (lsp--log-io-p method)
   6984                (lsp--log-entry-new
   6985                 (lsp--make-log-entry method id (lsp:json-response-error-error json-data)
   6986                                      'incoming-resp (lsp--ms-since before-send))
   6987                 workspace))
   6988              (when callback
   6989                (remhash id (lsp--client-response-handlers client))
   6990                (funcall callback (lsp:json-response-error-error json-data)))))
   6991           ('notification
   6992            (lsp--on-notification workspace json-data))
   6993           ('request (lsp--on-request workspace json-data)))))))
   6994 
   6995 (defun lsp--create-filter-function (workspace)
   6996   "Make filter for the workspace."
   6997   (let ((body-received 0)
   6998         leftovers body-length body chunk)
   6999     (lambda (_proc input)
   7000       (setf chunk (if (s-blank? leftovers)
   7001                       input
   7002                     (concat leftovers input)))
   7003 
   7004       (let (messages)
   7005         (while (not (s-blank? chunk))
   7006           (if (not body-length)
   7007               ;; Read headers
   7008               (if-let ((body-sep-pos (string-match-p "\r\n\r\n" chunk)))
   7009                   ;; We've got all the headers, handle them all at once:
   7010                   (setf body-length (lsp--get-body-length
   7011                                      (mapcar #'lsp--parse-header
   7012                                              (split-string
   7013                                               (substring-no-properties chunk
   7014                                                                        (or (string-match-p "Content-Length" chunk)
   7015                                                                            (error "Unable to find Content-Length header."))
   7016                                                                        body-sep-pos)
   7017                                               "\r\n")))
   7018                         body-received 0
   7019                         leftovers nil
   7020                         chunk (substring-no-properties chunk (+ body-sep-pos 4)))
   7021 
   7022                 ;; Haven't found the end of the headers yet. Save everything
   7023                 ;; for when the next chunk arrives and await further input.
   7024                 (setf leftovers chunk
   7025                       chunk nil))
   7026             (let* ((chunk-length (string-bytes chunk))
   7027                    (left-to-receive (- body-length body-received))
   7028                    (this-body (if (< left-to-receive chunk-length)
   7029                                   (prog1 (substring-no-properties chunk 0 left-to-receive)
   7030                                     (setf chunk (substring-no-properties chunk left-to-receive)))
   7031                                 (prog1 chunk
   7032                                   (setf chunk nil))))
   7033                    (body-bytes (string-bytes this-body)))
   7034               (push this-body body)
   7035               (setf body-received (+ body-received body-bytes))
   7036               (when (>= chunk-length left-to-receive)
   7037                 (condition-case err
   7038                     (with-temp-buffer
   7039                       (apply #'insert
   7040                              (nreverse
   7041                               (prog1 body
   7042                                 (setf leftovers nil
   7043                                       body-length nil
   7044                                       body-received nil
   7045                                       body nil))))
   7046                       (decode-coding-region (point-min)
   7047                                             (point-max)
   7048                                             'utf-8)
   7049                       (goto-char (point-min))
   7050                       (push (lsp-json-read-buffer) messages))
   7051 
   7052                   (error
   7053                    (lsp-warn "Failed to parse the following chunk:\n'''\n%s\n'''\nwith message %s"
   7054                              (concat leftovers input)
   7055                              err)))))))
   7056         (mapc (lambda (msg)
   7057                 (lsp--parser-on-message msg workspace))
   7058               (nreverse messages))))))
   7059 
   7060 (defvar-local lsp--line-col-to-point-hash-table nil
   7061   "Hash table with keys (line . col) and values that are either point positions
   7062 or markers.")
   7063 
   7064 (defcustom lsp-imenu-detailed-outline t
   7065   "Whether `lsp-imenu' should include signatures.
   7066 This will be ignored if the server doesn't provide the necessary
   7067 information, for example if it doesn't support DocumentSymbols."
   7068   :group 'lsp-imenu
   7069   :type 'boolean)
   7070 
   7071 (defcustom lsp-imenu-hide-parent-details t
   7072   "Whether `lsp-imenu' should hide signatures of parent nodes."
   7073   :group 'lsp-imenu
   7074   :type 'boolean)
   7075 
   7076 (defface lsp-details-face '((t :height 0.8 :inherit shadow))
   7077   "Used to display additional information throughout `lsp'.
   7078 Things like line numbers, signatures, ... are considered
   7079 additional information. Often, additional faces are defined that
   7080 inherit from this face by default, like `lsp-signature-face', and
   7081 they may be customized for finer control."
   7082   :group 'lsp-mode)
   7083 
   7084 (defface lsp-signature-face '((t :inherit lsp-details-face))
   7085   "Used to display signatures in `imenu', ...."
   7086   :group 'lsp-mode)
   7087 
   7088 (lsp-defun lsp-render-symbol ((&DocumentSymbol :name :detail? :deprecated?)
   7089                               show-detail?)
   7090   "Render INPUT0, an `&DocumentSymbol', to a string.
   7091 If SHOW-DETAIL? is set, make use of its `:detail?' field (often
   7092 the signature)."
   7093   (let ((detail (and show-detail? (s-present? detail?)
   7094                      (propertize (concat " " (s-trim-left detail?))
   7095                                  'face 'lsp-signature-face)))
   7096         (name (if deprecated?
   7097                   (propertize name 'face 'lsp-face-semhl-deprecated) name)))
   7098     (concat name detail)))
   7099 
   7100 (lsp-defun lsp-render-symbol-information ((&SymbolInformation :name :deprecated? :container-name?)
   7101                                           separator)
   7102   "Render a piece of SymbolInformation.
   7103 Handle :deprecated?. If SEPARATOR is non-nil, the
   7104 symbol's (optional) parent, SEPARATOR and the symbol itself are
   7105 concatenated."
   7106   (when (and separator container-name? (not (string-empty-p container-name?)))
   7107     (setq name (concat name separator container-name?)))
   7108   (if deprecated? (propertize name 'face 'lsp-face-semhl-deprecated) name))
   7109 
   7110 (defun lsp--symbol-to-imenu-elem (sym)
   7111   "Convert SYM to imenu element.
   7112 
   7113 SYM is a SymbolInformation message.
   7114 
   7115 Return a cons cell (full-name . start-point)."
   7116   (let ((start-point (ht-get lsp--line-col-to-point-hash-table
   7117                              (lsp--get-line-and-col sym))))
   7118     (cons (lsp-render-symbol-information
   7119            sym (and lsp-imenu-show-container-name
   7120                     lsp-imenu-container-name-separator))
   7121           start-point)))
   7122 
   7123 (lsp-defun lsp--symbol-to-hierarchical-imenu-elem ((sym &as &DocumentSymbol :children?))
   7124   "Convert SYM to hierarchical imenu elements.
   7125 
   7126 SYM is a DocumentSymbol message.
   7127 
   7128 Return cons cell (\"symbol-name (symbol-kind)\" . start-point) if
   7129 SYM doesn't have any children. Otherwise return a cons cell with
   7130 an alist
   7131 
   7132   (\"symbol-name\" . ((\"(symbol-kind)\" . start-point)
   7133                     cons-cells-from-children))"
   7134   (let ((filtered-children (lsp--imenu-filter-symbols children?))
   7135         (signature (lsp-render-symbol sym lsp-imenu-detailed-outline)))
   7136     (if (seq-empty-p filtered-children)
   7137         (cons signature
   7138               (ht-get lsp--line-col-to-point-hash-table
   7139                       (lsp--get-line-and-col sym)))
   7140       (cons signature
   7141             (lsp--imenu-create-hierarchical-index filtered-children)))))
   7142 
   7143 (lsp-defun lsp--symbol-ignore ((&SymbolInformation :kind))
   7144   "Determine if SYM is for the current document and is to be shown."
   7145   ;; It's a SymbolInformation or DocumentSymbol, which is always in the
   7146   ;; current buffer file.
   7147   (and lsp-imenu-index-symbol-kinds
   7148        (numberp kind)
   7149        (let ((clamped-kind (if (< 0 kind (length lsp/symbol-kind-lookup))
   7150                                kind
   7151                              0)))
   7152          (not (memql (aref lsp/symbol-kind-lookup clamped-kind)
   7153                      lsp-imenu-index-symbol-kinds)))))
   7154 
   7155 (lsp-defun lsp--get-symbol-type ((&SymbolInformation :kind))
   7156   "The string name of the kind of SYM."
   7157   (alist-get kind lsp-symbol-kinds "Other"))
   7158 
   7159 (defun lsp--get-line-and-col (sym)
   7160   "Obtain the line and column corresponding to SYM."
   7161   (-let* ((location (lsp:symbol-information-location sym))
   7162           (name-range (or (and location (lsp:location-range location))
   7163                           (lsp:document-symbol-selection-range sym)))
   7164           ((&Range :start (&Position :line :character)) name-range))
   7165     (cons line character)))
   7166 
   7167 (defun lsp--collect-lines-and-cols (symbols)
   7168   "Return a sorted list ((line . col) ...) of the locations of SYMBOLS."
   7169   (let ((stack (mapcar 'identity symbols))
   7170         line-col-list)
   7171     (while stack
   7172       (let ((sym (pop stack)))
   7173         (push (lsp--get-line-and-col sym) line-col-list)
   7174         (unless (seq-empty-p (lsp:document-symbol-children? sym))
   7175           (setf stack (nconc (lsp--imenu-filter-symbols (lsp:document-symbol-children? sym)) stack)))))
   7176     (-sort #'lsp--line-col-comparator line-col-list)))
   7177 
   7178 (defun lsp--convert-line-col-to-points-batch (line-col-list)
   7179   "Convert a sorted list of positions from line-column
   7180 representation to point representation."
   7181   (let ((line-col-to-point-map (ht-create))
   7182         (inhibit-field-text-motion t)
   7183         (curr-line 0))
   7184     (lsp-save-restriction-and-excursion
   7185       (goto-char (point-min))
   7186       (cl-loop for (line . col) in line-col-list do
   7187                (forward-line (- line curr-line))
   7188                (setq curr-line line)
   7189                (let ((line-end (line-end-position)))
   7190                  (if (or (not col) (> col (- line-end (point))))
   7191                      (goto-char line-end)
   7192                    (forward-char col)))
   7193                (ht-set! line-col-to-point-map (cons line col) (if imenu-use-markers
   7194                                                                   (point-marker)
   7195                                                                 (point)))))
   7196     line-col-to-point-map))
   7197 
   7198 (cl-defun lsp--line-col-comparator ((l1 . c1) (l2 . c2))
   7199   (or (< l1 l2)
   7200       (and (= l1 l2)
   7201            (cond ((and c1 c2)
   7202                   (< c1 c2))
   7203                  (c1 t)))))
   7204 
   7205 (defun lsp-imenu-create-uncategorized-index (symbols)
   7206   "Create imenu index from document SYMBOLS.
   7207 This function, unlike `lsp-imenu-create-categorized-index', does
   7208 not categorize by type, but instead returns an `imenu' index
   7209 corresponding to the symbol hierarchy returned by the server
   7210 directly."
   7211   (let* ((lsp--line-col-to-point-hash-table (-> symbols
   7212                                                 lsp--collect-lines-and-cols
   7213                                                 lsp--convert-line-col-to-points-batch)))
   7214     (if (lsp--imenu-hierarchical-p symbols)
   7215         (lsp--imenu-create-hierarchical-index symbols)
   7216       (lsp--imenu-create-non-hierarchical-index symbols))))
   7217 
   7218 (defcustom lsp-imenu-symbol-kinds
   7219   '((1 . "Files")
   7220     (2 . "Modules")
   7221     (3 . "Namespaces")
   7222     (4 . "Packages")
   7223     (5 . "Classes")
   7224     (6 . "Methods")
   7225     (7 . "Properties")
   7226     (8 . "Fields")
   7227     (9 . "Constructors")
   7228     (10 . "Enums")
   7229     (11 . "Interfaces")
   7230     (12 . "Functions")
   7231     (13 . "Variables")
   7232     (14 . "Constants")
   7233     (15 . "Strings")
   7234     (16 . "Numbers")
   7235     (17 . "Booleans")
   7236     (18 . "Arrays")
   7237     (19 . "Objects")
   7238     (20 . "Keys")
   7239     (21 . "Nulls")
   7240     (22 . "Enum Members")
   7241     (23 . "Structs")
   7242     (24 . "Events")
   7243     (25 . "Operators")
   7244     (26 . "Type Parameters"))
   7245   "`lsp-symbol-kinds', but only used by `imenu'.
   7246 A new variable is needed, as it is `imenu' convention to use
   7247 pluralized categories, which `lsp-symbol-kinds' doesn't. If the
   7248 non-pluralized names are preferred, this can be set to
   7249 `lsp-symbol-kinds'."
   7250   :type '(alist :key-type integer :value-type string))
   7251 
   7252 (defun lsp--imenu-kind->name (kind)
   7253   (alist-get kind lsp-imenu-symbol-kinds "?"))
   7254 
   7255 (defun lsp-imenu-create-top-level-categorized-index (symbols)
   7256   "Create an `imenu' index categorizing SYMBOLS by type.
   7257 Only root symbols are categorized.
   7258 
   7259 See `lsp-symbol-kinds' to customize the category naming. SYMBOLS
   7260 shall be a list of DocumentSymbols or SymbolInformation."
   7261   (mapcan
   7262    (-lambda ((type . symbols))
   7263      (let ((cat (lsp--imenu-kind->name type))
   7264            (symbols (lsp-imenu-create-uncategorized-index symbols)))
   7265        ;; If there is no :kind (this is being defensive), or we couldn't look it
   7266        ;; up, just display the symbols inline, without categories.
   7267        (if cat (list (cons cat symbols)) symbols)))
   7268    (sort (seq-group-by #'lsp:document-symbol-kind symbols)
   7269          (-lambda ((kinda) (kindb)) (< kinda kindb)))))
   7270 
   7271 (lsp-defun lsp--symbol->imenu ((sym &as &DocumentSymbol :selection-range (&RangeToPoint :start)))
   7272   "Convert an `&DocumentSymbol' to an `imenu' entry."
   7273   (cons (lsp-render-symbol sym lsp-imenu-detailed-outline) start))
   7274 
   7275 (defun lsp--imenu-create-categorized-index-1 (symbols)
   7276   "Returns an `imenu' index from SYMBOLS categorized by type.
   7277 The result looks like this: ((\"Variables\" . (...)))."
   7278   (->>
   7279    symbols
   7280    (mapcan
   7281     (-lambda ((sym &as &DocumentSymbol :kind :children?))
   7282       (if (seq-empty-p children?)
   7283           (list (list kind (lsp--symbol->imenu sym)))
   7284         (let ((parent (lsp-render-symbol sym (and lsp-imenu-detailed-outline
   7285                                                   (not lsp-imenu-hide-parent-details)))))
   7286           (cons
   7287            (list kind (lsp--symbol->imenu sym))
   7288            (mapcar (-lambda ((type .  imenu-items))
   7289                      (list type (cons parent (mapcan #'cdr imenu-items))))
   7290                    (-group-by #'car (lsp--imenu-create-categorized-index-1 children?))))))))
   7291    (-group-by #'car)
   7292    (mapcar
   7293     (-lambda ((kind . syms))
   7294       (cons kind (mapcan #'cdr syms))))))
   7295 
   7296 (defun lsp--imenu-create-categorized-index (symbols)
   7297   (let ((syms (lsp--imenu-create-categorized-index-1 symbols)))
   7298     (dolist (sym syms)
   7299       (setcar sym (lsp--imenu-kind->name (car sym))))
   7300     syms))
   7301 
   7302 (lsp-defun lsp--symbol-information->imenu ((sym &as &SymbolInformation :location (&Location :range (&RangeToPoint :start))))
   7303   (cons (lsp-render-symbol-information sym nil) start))
   7304 
   7305 (defun lsp--imenu-create-categorized-index-flat (symbols)
   7306   "Create a kind-categorized index for SymbolInformation."
   7307   (mapcar (-lambda ((kind . syms))
   7308             (cons (lsp--imenu-kind->name kind)
   7309                   (mapcan (-lambda ((parent . children))
   7310                             (let ((children (mapcar #'lsp--symbol-information->imenu children)))
   7311                               (if parent (list (cons parent children)) children)))
   7312                           (-group-by #'lsp:symbol-information-container-name? syms))))
   7313           (seq-group-by #'lsp:symbol-information-kind symbols)))
   7314 
   7315 (defun lsp-imenu-create-categorized-index (symbols)
   7316   (if (lsp--imenu-hierarchical-p symbols)
   7317       (lsp--imenu-create-categorized-index symbols)
   7318     (lsp--imenu-create-categorized-index-flat symbols)))
   7319 
   7320 (defcustom lsp-imenu-index-function #'lsp-imenu-create-uncategorized-index
   7321   "Function that should create an `imenu' index.
   7322 It will be called with a list of SymbolInformation or
   7323 DocumentSymbols, whose first level is already filtered. It shall
   7324 then return an appropriate `imenu' index (see
   7325 `imenu-create-index-function').
   7326 
   7327 Note that this interface is not stable, and subject to change any
   7328 time."
   7329   :group 'lsp-imenu
   7330   :type '(radio
   7331           (const :tag "Categorize by type"
   7332                  lsp-imenu-create-categorized-index)
   7333           (const :tag "Categorize root symbols by type"
   7334                  lsp-imenu-create-top-level-categorized-index)
   7335           (const :tag "Uncategorized, inline entries"
   7336                  lsp-imenu-create-uncategorized-index)
   7337           (function :tag "Custom function")))
   7338 
   7339 (defun lsp--imenu-create-index ()
   7340   "Create an `imenu' index based on the language server.
   7341 Respects `lsp-imenu-index-function'."
   7342   (let ((symbols (lsp--imenu-filter-symbols (lsp--get-document-symbols))))
   7343     (funcall lsp-imenu-index-function symbols)))
   7344 
   7345 (defun lsp--imenu-filter-symbols (symbols)
   7346   "Filter out unsupported symbols from SYMBOLS."
   7347   (seq-remove #'lsp--symbol-ignore symbols))
   7348 
   7349 (defun lsp--imenu-hierarchical-p (symbols)
   7350   "Determine whether any element in SYMBOLS has children."
   7351   (seq-some #'lsp-document-symbol? symbols))
   7352 
   7353 (defun lsp--imenu-create-non-hierarchical-index (symbols)
   7354   "Create imenu index for non-hierarchical SYMBOLS.
   7355 
   7356 SYMBOLS are a list of DocumentSymbol messages.
   7357 
   7358 Return a nested alist keyed by symbol names. e.g.
   7359 
   7360    ((\"SomeClass\" (\"(Class)\" . 10)
   7361                  (\"someField (Field)\" . 20)
   7362                  (\"someFunction (Function)\" . 25)
   7363                  (\"SomeSubClass\" (\"(Class)\" . 30)
   7364                                   (\"someSubField (Field)\" . 35))
   7365     (\"someFunction (Function)\" . 40))"
   7366   (seq-map (lambda (nested-alist)
   7367              (cons (car nested-alist)
   7368                    (seq-map #'lsp--symbol-to-imenu-elem (cdr nested-alist))))
   7369            (seq-group-by #'lsp--get-symbol-type symbols)))
   7370 
   7371 (defun lsp--imenu-create-hierarchical-index (symbols)
   7372   "Create imenu index for hierarchical SYMBOLS.
   7373 
   7374 SYMBOLS are a list of DocumentSymbol messages.
   7375 
   7376 Return a nested alist keyed by symbol names. e.g.
   7377 
   7378    ((\"SomeClass\" (\"(Class)\" . 10)
   7379                  (\"someField (Field)\" . 20)
   7380                  (\"someFunction (Function)\" . 25)
   7381                  (\"SomeSubClass\" (\"(Class)\" . 30)
   7382                                   (\"someSubField (Field)\" . 35))
   7383     (\"someFunction (Function)\" . 40))"
   7384   (seq-map #'lsp--symbol-to-hierarchical-imenu-elem
   7385            (seq-sort #'lsp--imenu-symbol-lessp symbols)))
   7386 
   7387 (defun lsp--imenu-symbol-lessp (sym1 sym2)
   7388   (let* ((compare-results (mapcar (lambda (method)
   7389                                     (funcall (alist-get method lsp--imenu-compare-function-alist)
   7390                                              sym1 sym2))
   7391                                   lsp-imenu-sort-methods))
   7392          (result (seq-find (lambda (result)
   7393                              (not (= result 0)))
   7394                            compare-results
   7395                            0)))
   7396     (and (numberp result) (< result 0))))
   7397 
   7398 (lsp-defun lsp--imenu-compare-kind ((&SymbolInformation :kind left)
   7399                                     (&SymbolInformation :kind right))
   7400   "Compare SYM1 and SYM2 by kind."
   7401   (- left right))
   7402 
   7403 (defun lsp--imenu-compare-line-col (sym1 sym2)
   7404   (if (lsp--line-col-comparator
   7405        (lsp--get-line-and-col sym1)
   7406        (lsp--get-line-and-col sym2))
   7407       -1
   7408     1))
   7409 
   7410 (lsp-defun lsp--imenu-compare-name ((&SymbolInformation :name name1)
   7411                                     (&SymbolInformation :name name2))
   7412   "Compare SYM1 and SYM2 by name."
   7413   (let ((result (compare-strings name1 0 (length name1) name2 0 (length name2))))
   7414     (if (numberp result) result 0)))
   7415 
   7416 (defun lsp--imenu-refresh ()
   7417   "Force Imenu to refresh itself."
   7418   (imenu--menubar-select imenu--rescan-item))
   7419 
   7420 (defun lsp-enable-imenu ()
   7421   "Use lsp-imenu for the current buffer."
   7422   (imenu--cleanup)
   7423   (add-function :override (local 'imenu-create-index-function) #'lsp--imenu-create-index)
   7424   (setq-local imenu-menubar-modified-tick -1)
   7425   (setq-local imenu--index-alist nil)
   7426   (when menu-bar-mode
   7427     (lsp--imenu-refresh)))
   7428 
   7429 (defun lsp-resolve-final-command (command &optional test?)
   7430   "Resolve final function COMMAND."
   7431   (let* ((command (lsp-resolve-value command))
   7432          (command (cl-etypecase command
   7433                     (list
   7434                      (cl-assert (seq-every-p (apply-partially #'stringp) command) nil
   7435                                 "Invalid command list")
   7436                      command)
   7437                     (string (list command)))))
   7438     (if (and (file-remote-p default-directory) (not test?))
   7439         (list shell-file-name "-c"
   7440               (string-join (cons "stty raw > /dev/null;"
   7441                                  (mapcar #'shell-quote-argument command))
   7442                            " "))
   7443       command)))
   7444 
   7445 (defun lsp-server-present? (final-command)
   7446   "Check whether FINAL-COMMAND is present."
   7447   (let ((binary-found? (executable-find (cl-first final-command) t)))
   7448     (if binary-found?
   7449         (lsp-log "Command \"%s\" is present on the path." (s-join " " final-command))
   7450       (lsp-log "Command \"%s\" is not present on the path." (s-join " " final-command)))
   7451     binary-found?))
   7452 
   7453 (defun lsp--value-to-string (value)
   7454   "Convert VALUE to a string that can be set as value in an environment
   7455 variable."
   7456   (cond
   7457    ((stringp value) value)
   7458    ((booleanp value) (if value
   7459                          "1"
   7460                        "0"))
   7461    ((and (sequencep value)
   7462          (seq-every-p #'stringp value)) (string-join value ":"))
   7463    (t (user-error "Only strings, booleans, and sequences of strings are supported as environment variables"))))
   7464 
   7465 (defun lsp--compute-process-environment (environment-fn)
   7466   "Append a list of KEY=VALUE from the alist ENVIRONMENT to `process-environment'.
   7467 Ignore non-boolean keys whose value is nil."
   7468   (let ((environment (if environment-fn
   7469                          (funcall environment-fn)
   7470                        nil)))
   7471     (-flatten (cons (cl-loop for (key . value) in environment
   7472                              if (or (eval value)
   7473                                     (eq (get value 'custom-type) 'boolean))
   7474                              collect (concat key "=" (lsp--value-to-string
   7475                                                       (eval value))))
   7476                     process-environment))))
   7477 
   7478 (defun lsp--default-directory-for-connection (&optional path)
   7479   "Return path to be used for the working directory of a LSP process.
   7480 
   7481 If `lsp-use-workspace-root-for-server-default-directory' is
   7482 non-nil, uses `lsp-workspace-root' to find the directory
   7483 corresponding to PATH, else returns `default-directory'."
   7484   (if lsp-use-workspace-root-for-server-default-directory
   7485       (lsp-workspace-root path)
   7486     default-directory))
   7487 
   7488 (defun lsp--fix-remote-cmd (program)
   7489   "Helper for `lsp-stdio-connection'.
   7490 Originally coppied from eglot."
   7491 
   7492   (if (file-remote-p default-directory)
   7493       (list shell-file-name "-c"
   7494             (string-join (cons "stty raw > /dev/null;"
   7495                                (mapcar #'shell-quote-argument program))
   7496                          " "))
   7497     program))
   7498 
   7499 (defvar tramp-use-ssh-controlmaster-options)
   7500 (defvar tramp-ssh-controlmaster-options)
   7501 
   7502 (defun lsp-stdio-connection (command &optional test-command)
   7503   "Returns a connection property list using COMMAND.
   7504 COMMAND can be: A string, denoting the command to launch the
   7505 language server. A list of strings, denoting an executable with
   7506 its command line arguments. A function, that either returns a
   7507 string or a list of strings. In all cases, the launched language
   7508 server should send and receive messages on standard I/O.
   7509 TEST-COMMAND is a function with no arguments which returns
   7510 whether the command is present or not. When not specified
   7511 `lsp-mode' will check whether the first element of the list
   7512 returned by COMMAND is available via `executable-find'"
   7513   (cl-check-type command (or string
   7514                              function
   7515                              (and list
   7516                                   (satisfies (lambda (l)
   7517                                                (seq-every-p (lambda (el)
   7518                                                               (stringp el))
   7519                                                             l))))))
   7520   (list :connect (lambda (filter sentinel name environment-fn workspace)
   7521                    (if (and (functionp 'json-rpc-connection)
   7522                             (not (file-remote-p default-directory)))
   7523                        (lsp-json-rpc-connection workspace (lsp-resolve-final-command command))
   7524                      (let ((final-command (lsp-resolve-final-command command))
   7525                            (process-name (generate-new-buffer-name name))
   7526                            (process-environment
   7527                             (lsp--compute-process-environment environment-fn)))
   7528                        (let* ((stderr-buf (get-buffer-create (format "*%s::stderr*" process-name)))
   7529                               (default-directory (lsp--default-directory-for-connection))
   7530                               (tramp-use-ssh-controlmaster-options 'suppress)
   7531                               (tramp-ssh-controlmaster-options "-o ControlMaster=no -o ControlPath=none")
   7532                               (proc (make-process
   7533                                      :name process-name
   7534                                      :connection-type 'pipe
   7535                                      :buffer (format "*%s*" process-name)
   7536                                      :coding 'no-conversion
   7537                                      :command final-command
   7538                                      :filter filter
   7539                                      :sentinel sentinel
   7540                                      :stderr stderr-buf
   7541                                      :noquery t
   7542                                      :file-handler t)))
   7543                          (set-process-query-on-exit-flag proc nil)
   7544                          (set-process-query-on-exit-flag (get-buffer-process stderr-buf) nil)
   7545                          (with-current-buffer (get-buffer stderr-buf)
   7546                            ;; Make the *NAME::stderr* buffer buffer-read-only, q to bury, etc.
   7547                            (special-mode))
   7548                          (cons proc proc)))))
   7549         :test? (or
   7550                 test-command
   7551                 (lambda ()
   7552                   (lsp-server-present? (lsp-resolve-final-command command t))))))
   7553 
   7554 (defun lsp--open-network-stream (host port name)
   7555   "Open network stream to HOST:PORT.
   7556   NAME will be passed to `open-network-stream'.
   7557   RETRY-COUNT is the number of the retries.
   7558   SLEEP-INTERVAL is the sleep interval between each retry."
   7559   (let* ((retries 0)
   7560          (sleep-interval 0.01)
   7561          (number-of-retries (/ lsp-tcp-connection-timeout sleep-interval))
   7562          connection)
   7563     (while (and (not connection) (< retries number-of-retries))
   7564       (condition-case err
   7565           (setq connection (open-network-stream name nil host port
   7566                                                 :type 'plain
   7567                                                 :coding 'no-conversion))
   7568         (file-error
   7569          (let ((inhibit-message t))
   7570            (lsp--warn "Failed to connect to %s:%s with error message %s"
   7571                       host
   7572                       port
   7573                       (error-message-string err))
   7574            (sleep-for sleep-interval)
   7575            (cl-incf retries)))))
   7576     (or connection (error "Port %s was never taken. Consider increasing `lsp-tcp-connection-timeout'." port))))
   7577 
   7578 (defun lsp--port-available (host port)
   7579   "Return non-nil if HOST and PORT are available."
   7580   (condition-case _err
   7581       (delete-process (open-network-stream "*connection-test*" nil host port :type 'plain))
   7582     (file-error t)))
   7583 
   7584 (defun lsp--find-available-port (host starting-port)
   7585   "Find available port on HOST starting from STARTING-PORT."
   7586   (let ((port starting-port))
   7587     (while (not (lsp--port-available host port))
   7588       (cl-incf port))
   7589     port))
   7590 
   7591 (defun lsp-tcp-connection (command-fn)
   7592   "Returns a connection property list similar to `lsp-stdio-connection'.
   7593 COMMAND-FN can only be a function that takes a single argument, a
   7594 port number. It should return a command for launches a language server
   7595 process listening for TCP connections on the provided port."
   7596   (cl-check-type command-fn function)
   7597   (list
   7598    :connect (lambda (filter sentinel name environment-fn _workspace)
   7599               (let* ((host "localhost")
   7600                      (port (lsp--find-available-port host (cl-incf lsp--tcp-port)))
   7601                      (command (funcall command-fn port))
   7602                      (final-command (if (consp command) command (list command)))
   7603                      (_ (unless (lsp-server-present? final-command)
   7604                           (user-error (format "Couldn't find executable %s" (cl-first final-command)))))
   7605                      (process-environment
   7606                       (lsp--compute-process-environment environment-fn))
   7607                      (proc (make-process :name name :connection-type 'pipe :coding 'no-conversion
   7608                                          :command final-command :sentinel sentinel :stderr (format "*%s::stderr*" name) :noquery t))
   7609                      (tcp-proc (lsp--open-network-stream host port (concat name "::tcp"))))
   7610 
   7611                 ;; TODO: Same :noquery issue (see above)
   7612                 (set-process-query-on-exit-flag proc nil)
   7613                 (set-process-query-on-exit-flag tcp-proc nil)
   7614                 (set-process-filter tcp-proc filter)
   7615                 (cons tcp-proc proc)))
   7616    :test? (lambda () (lsp-server-present? (funcall command-fn 0)))))
   7617 
   7618 (defalias 'lsp-tcp-server 'lsp-tcp-server-command)
   7619 
   7620 (defun lsp-tcp-server-command (command-fn)
   7621   "Create tcp server connection.
   7622 In this mode Emacs is TCP server and the language server connects
   7623 to it. COMMAND is function with one parameter(the port) and it
   7624 should return the command to start the LS server."
   7625   (cl-check-type command-fn function)
   7626   (list
   7627    :connect (lambda (filter sentinel name environment-fn _workspace)
   7628               (let* (tcp-client-connection
   7629                      (tcp-server (make-network-process :name (format "*tcp-server-%s*" name)
   7630                                                        :buffer (format "*tcp-server-%s*" name)
   7631                                                        :family 'ipv4
   7632                                                        :service lsp--tcp-server-port
   7633                                                        :sentinel (lambda (proc _string)
   7634                                                                    (lsp-log "Language server %s is connected." name)
   7635                                                                    (setf tcp-client-connection proc))
   7636                                                        :server 't))
   7637                      (port (process-contact tcp-server :service))
   7638                      (final-command (funcall command-fn port))
   7639                      (process-environment
   7640                       (lsp--compute-process-environment environment-fn))
   7641                      (cmd-proc (make-process :name name
   7642                                              :connection-type 'pipe
   7643                                              :coding 'no-conversion
   7644                                              :command final-command
   7645                                              :stderr (format "*tcp-server-%s*::stderr" name)
   7646                                              :noquery t)))
   7647                 (let ((retries 0))
   7648                   ;; wait for the client to connect (we sit-for 500 ms, so have to double lsp--tcp-server-wait-seconds)
   7649                   (while (and (not tcp-client-connection) (< retries (* 2 lsp--tcp-server-wait-seconds)))
   7650                     (lsp--info "Waiting for connection for %s, retries: %s" name retries)
   7651                     (sit-for 0.500)
   7652                     (cl-incf retries)))
   7653 
   7654                 (unless tcp-client-connection
   7655                   (condition-case nil (delete-process tcp-server) (error))
   7656                   (condition-case nil (delete-process cmd-proc) (error))
   7657                   (error "Failed to create connection to %s on port %s" name port))
   7658                 (lsp--info "Successfully connected to %s" name)
   7659 
   7660                 (set-process-query-on-exit-flag cmd-proc nil)
   7661                 (set-process-query-on-exit-flag tcp-client-connection nil)
   7662                 (set-process-query-on-exit-flag tcp-server nil)
   7663 
   7664                 (set-process-filter tcp-client-connection filter)
   7665                 (set-process-sentinel tcp-client-connection sentinel)
   7666                 (cons tcp-client-connection cmd-proc)))
   7667    :test? (lambda () (lsp-server-present? (funcall command-fn 0)))))
   7668 
   7669 (defalias 'lsp-tramp-connection 'lsp-stdio-connection)
   7670 
   7671 (defun lsp--auto-configure ()
   7672   "Autoconfigure `company', `flycheck', `lsp-ui', etc if they are installed."
   7673   (when (functionp 'lsp-ui-mode)
   7674     (lsp-ui-mode))
   7675 
   7676   (if lsp-headerline-breadcrumb-enable
   7677       (add-hook 'lsp-configure-hook 'lsp-headerline-breadcrumb-mode)
   7678     (remove-hook 'lsp-configure-hook 'lsp-headerline-breadcrumb-mode))
   7679   (if lsp-modeline-code-actions-enable
   7680       (add-hook 'lsp-configure-hook 'lsp-modeline-code-actions-mode)
   7681     (remove-hook 'lsp-configure-hook 'lsp-modeline-code-actions-mode))
   7682   (if lsp-modeline-diagnostics-enable
   7683       (add-hook 'lsp-configure-hook 'lsp-modeline-diagnostics-mode)
   7684     (remove-hook 'lsp-configure-hook 'lsp-modeline-diagnostics-mode))
   7685   (if lsp-modeline-workspace-status-enable
   7686       (add-hook 'lsp-configure-hook 'lsp-modeline-workspace-status-mode)
   7687     (remove-hook 'lsp-configure-hook 'lsp-modeline-workspace-status-mode))
   7688   (if lsp-lens-enable
   7689       (add-hook 'lsp-configure-hook 'lsp-lens--enable)
   7690     (remove-hook 'lsp-configure-hook 'lsp-lens--enable))
   7691   (if lsp-semantic-tokens-enable
   7692       (add-hook 'lsp-configure-hook 'lsp-semantic-tokens--enable)
   7693     (remove-hook 'lsp-configure-hook 'lsp-semantic-tokens--enable))
   7694 
   7695   ;; yas-snippet config
   7696   (setq-local yas-inhibit-overlay-modification-protection t))
   7697 
   7698 (defun lsp--restart-if-needed (workspace)
   7699   "Handler restart for WORKSPACE."
   7700   (when (or (eq lsp-restart 'auto-restart)
   7701             (eq (lsp--workspace-shutdown-action workspace) 'restart)
   7702             (and (eq lsp-restart 'interactive)
   7703                  (let ((query (format
   7704                                "Server %s exited (check corresponding stderr buffer for details). Do you want to restart it?"
   7705                                (lsp--workspace-print workspace))))
   7706                    (y-or-n-p query))))
   7707     (--each (lsp--workspace-buffers workspace)
   7708       (when (lsp-buffer-live-p it)
   7709         (lsp-with-current-buffer it
   7710           (if lsp--buffer-deferred
   7711               (lsp-deferred)
   7712             (lsp--info "Restarting LSP in buffer %s" (buffer-name))
   7713             (lsp)))))))
   7714 
   7715 (defun lsp--update-key (table key fn)
   7716   "Apply FN on value corresponding to KEY in TABLE."
   7717   (let ((existing-value (gethash key table)))
   7718     (if-let ((new-value (funcall fn existing-value)))
   7719         (puthash key new-value table)
   7720       (remhash key table))))
   7721 
   7722 (defun lsp--process-sentinel (workspace process exit-str)
   7723   "Create the sentinel for WORKSPACE."
   7724   (unless (process-live-p process)
   7725     (lsp--handle-process-exit workspace exit-str)))
   7726 
   7727 (defun lsp--handle-process-exit (workspace exit-str)
   7728   (let* ((folder->workspaces (lsp-session-folder->servers (lsp-session)))
   7729          (proc (lsp--workspace-proc workspace)))
   7730     (lsp--warn "%s has exited (%s)"
   7731                (lsp-process-name proc)
   7732                (string-trim-right (or exit-str "")))
   7733     (with-lsp-workspace workspace
   7734       ;; Clean workspace related data in each of the buffers
   7735       ;; in the workspace.
   7736       (--each (lsp--workspace-buffers workspace)
   7737         (when (lsp-buffer-live-p it)
   7738           (lsp-with-current-buffer it
   7739             (setq lsp--buffer-workspaces (delete workspace lsp--buffer-workspaces))
   7740             (lsp--uninitialize-workspace)
   7741             (lsp--spinner-stop)
   7742             (lsp--remove-overlays 'lsp-highlight))))
   7743 
   7744       ;; Cleanup session from references to the closed workspace.
   7745       (--each (hash-table-keys folder->workspaces)
   7746         (lsp--update-key folder->workspaces it (apply-partially 'delete workspace)))
   7747 
   7748       (lsp-process-cleanup proc))
   7749 
   7750     (run-hook-with-args 'lsp-after-uninitialized-functions workspace)
   7751 
   7752     (if (eq (lsp--workspace-shutdown-action workspace) 'shutdown)
   7753         (lsp--info "Workspace %s shutdown." (lsp--workspace-print workspace))
   7754       (lsp--restart-if-needed workspace))
   7755     (lsp--cleanup-hanging-watches)))
   7756 
   7757 (defun lsp-workspace-folders (workspace)
   7758   "Return all folders associated with WORKSPACE."
   7759   (let (result)
   7760     (->> (lsp-session)
   7761          (lsp-session-folder->servers)
   7762          (maphash (lambda (folder workspaces)
   7763                     (when (-contains? workspaces workspace)
   7764                       (push folder result)))))
   7765     result))
   7766 
   7767 (defun lsp--start-workspace (session client-template root &optional initialization-options)
   7768   "Create new workspace for CLIENT-TEMPLATE with project root ROOT.
   7769 INITIALIZATION-OPTIONS are passed to initialize function.
   7770 SESSION is the active session."
   7771   (lsp--spinner-start)
   7772   (-let* ((default-directory root)
   7773           (client (copy-lsp--client client-template))
   7774           (workspace (make-lsp--workspace
   7775                       :root root
   7776                       :client client
   7777                       :status 'starting
   7778                       :buffers (list (lsp-current-buffer))
   7779                       :host-root (file-remote-p root)))
   7780           ((&lsp-cln 'server-id 'environment-fn 'new-connection 'custom-capabilities
   7781                      'multi-root 'initialized-fn) client)
   7782           ((proc . cmd-proc) (funcall
   7783                               (or (plist-get new-connection :connect)
   7784                                   (user-error "Client %s is configured incorrectly" client))
   7785                               (lsp--create-filter-function workspace)
   7786                               (apply-partially #'lsp--process-sentinel workspace)
   7787                               (format "%s" server-id)
   7788                               environment-fn
   7789                               workspace))
   7790           (workspace-folders (gethash server-id (lsp-session-server-id->folders session))))
   7791     (setf (lsp--workspace-proc workspace) proc
   7792           (lsp--workspace-cmd-proc workspace) cmd-proc)
   7793 
   7794     ;; update (lsp-session-folder->servers) depending on whether we are starting
   7795     ;; multi/single folder workspace
   7796     (mapc (lambda (project-root)
   7797             (->> session
   7798                  (lsp-session-folder->servers)
   7799                  (gethash project-root)
   7800                  (cl-pushnew workspace)))
   7801           (or workspace-folders (list root)))
   7802 
   7803     (with-lsp-workspace workspace
   7804       (run-hooks 'lsp-before-initialize-hook)
   7805       (lsp-request-async
   7806        "initialize"
   7807        (append
   7808         (list :processId (unless (file-remote-p (buffer-file-name))
   7809                            (emacs-pid))
   7810               :rootPath (lsp-file-local-name (expand-file-name root))
   7811               :clientInfo (list :name "emacs"
   7812                                 :version (emacs-version))
   7813               :rootUri (lsp--path-to-uri root)
   7814               :capabilities (lsp--client-capabilities custom-capabilities)
   7815               :initializationOptions initialization-options
   7816               :workDoneToken "1")
   7817         (when lsp-server-trace
   7818           (list :trace lsp-server-trace))
   7819         (when multi-root
   7820           (->> workspace-folders
   7821                (-distinct)
   7822                (-map (lambda (folder)
   7823                        (list :uri (lsp--path-to-uri folder)
   7824                              :name (f-filename folder))))
   7825                (apply 'vector)
   7826                (list :workspaceFolders))))
   7827        (-lambda ((&InitializeResult :capabilities))
   7828          ;; we know that Rust Analyzer will send {} which will be parsed as null
   7829          ;; when using plists
   7830          (when (equal 'rust-analyzer server-id)
   7831            (-> capabilities
   7832                (lsp:server-capabilities-text-document-sync?)
   7833                (lsp:set-text-document-sync-options-save? t)))
   7834 
   7835          (setf (lsp--workspace-server-capabilities workspace) capabilities
   7836                (lsp--workspace-status workspace) 'initialized)
   7837 
   7838          (with-lsp-workspace workspace
   7839            (lsp-notify "initialized" lsp--empty-ht))
   7840 
   7841          (when initialized-fn (funcall initialized-fn workspace))
   7842 
   7843          (cl-callf2 -filter #'lsp-buffer-live-p (lsp--workspace-buffers workspace))
   7844          (->> workspace
   7845               (lsp--workspace-buffers)
   7846               (mapc (lambda (buffer)
   7847                       (lsp-with-current-buffer buffer
   7848                         (lsp--open-in-workspace workspace)))))
   7849 
   7850          (with-lsp-workspace workspace
   7851            (run-hooks 'lsp-after-initialize-hook))
   7852          (lsp--info "%s initialized successfully in folders: %s"
   7853                     (lsp--workspace-print workspace)
   7854                     (lsp-workspace-folders workspace)))
   7855        :mode 'detached))
   7856     workspace))
   7857 
   7858 (defun lsp--load-default-session ()
   7859   "Load default session."
   7860   (setq lsp--session (or (condition-case err
   7861                              (lsp--read-from-file lsp-session-file)
   7862                            (error (lsp--error "Failed to parse the session %s, starting with clean one."
   7863                                               (error-message-string err))
   7864                                   nil))
   7865                          (make-lsp-session))))
   7866 
   7867 (defun lsp-session ()
   7868   "Get the session associated with the current buffer."
   7869   (or lsp--session (setq lsp--session (lsp--load-default-session))))
   7870 
   7871 (defun lsp--client-disabled-p (buffer-major-mode client)
   7872   (seq-some
   7873    (lambda (entry)
   7874      (pcase entry
   7875        ((pred symbolp) (eq entry client))
   7876        (`(,mode . ,client-or-list)
   7877         (and (eq mode buffer-major-mode)
   7878              (if (listp client-or-list)
   7879                  (memq client client-or-list)
   7880                (eq client client-or-list))))))
   7881    lsp-disabled-clients))
   7882 
   7883 
   7884 ;; download server
   7885 
   7886 (defcustom lsp-server-install-dir (expand-file-name
   7887                                    (locate-user-emacs-file (f-join ".cache" "lsp")))
   7888   "Directory in which the servers will be installed."
   7889   :risky t
   7890   :type 'directory
   7891   :package-version '(lsp-mode . "6.3")
   7892   :group 'lsp-mode)
   7893 
   7894 (defcustom lsp-verify-signature t
   7895   "Whether to check GPG signatures of downloaded files."
   7896   :type 'boolean
   7897   :package-version '(lsp-mode . "8.0.0")
   7898   :group 'lsp-mode)
   7899 
   7900 (defvar lsp--dependencies (ht))
   7901 
   7902 (defun lsp-dependency (name &rest definitions)
   7903   "Used to specify a language server DEPENDENCY, the server
   7904 executable or other required file path. Typically, the
   7905 DEPENDENCY is found by locating it on the system path using
   7906 `executable-find'.
   7907 
   7908 You can explicitly call lsp-dependency in your environment to
   7909 specify the absolute path to the DEPENDENCY. For example, the
   7910 typescript-language-server requires both the server and the
   7911 typescript compiler. If you have installed them in a team shared
   7912 read-only location, you can instruct lsp-mode to use them via
   7913 
   7914  (eval-after-load `lsp-mode
   7915    `(progn
   7916       (require lsp-javascript)
   7917       (lsp-dependency typescript-language-server (:system ,tls-exe))
   7918       (lsp-dependency typescript (:system ,ts-js))))
   7919 
   7920 where tls-exe is the absolute path to the typescript-language-server
   7921 executable and ts-js is the absolute path to the typescript compiler
   7922 JavaScript file, tsserver.js (the *.js is required for Windows)."
   7923   (ht-set lsp--dependencies name definitions))
   7924 
   7925 (defun lsp--server-binary-present? (client)
   7926   (unless (equal (lsp--client-server-id client) 'lsp-pwsh)
   7927     (condition-case ()
   7928         (-some-> client lsp--client-new-connection (plist-get :test?) funcall)
   7929       (error nil)
   7930       (args-out-of-range nil))))
   7931 
   7932 (define-minor-mode lsp-installation-buffer-mode
   7933   "Mode used in *lsp-installation* buffers.
   7934 It can be used to set-up keybindings, etc. Disabling this mode
   7935 detaches the installation buffer from commands like
   7936 `lsp-select-installation-buffer'."
   7937   :init-value nil
   7938   :lighter nil)
   7939 
   7940 (defface lsp-installation-finished-buffer-face '((t :foreground "orange"))
   7941   "Face used for finished installation buffers.
   7942 Used in `lsp-select-installation-buffer'."
   7943   :group 'lsp-mode)
   7944 
   7945 (defface lsp-installation-buffer-face '((t :foreground "green"))
   7946   "Face used for installation buffers still in progress.
   7947 Used in `lsp-select-installation-buffer'."
   7948   :group 'lsp-mode)
   7949 
   7950 (defun lsp--installation-buffer? (buf)
   7951   "Check whether BUF is an `lsp-async-start-process' buffer."
   7952   (buffer-local-value 'lsp-installation-buffer-mode buf))
   7953 
   7954 (defun lsp-select-installation-buffer (&optional show-finished)
   7955   "Interactively choose an installation buffer.
   7956 If SHOW-FINISHED is set, leftover (finished) installation buffers
   7957 are still shown."
   7958   (interactive "P")
   7959   (let ((bufs (--filter (and (lsp--installation-buffer? it)
   7960                              (or show-finished (get-buffer-process it)))
   7961                         (buffer-list))))
   7962     (pcase bufs
   7963       (`nil (user-error "No installation buffers"))
   7964       (`(,buf) (pop-to-buffer buf))
   7965       (bufs (pop-to-buffer (completing-read "Select installation buffer: "
   7966                                             (--map (propertize (buffer-name it) 'face
   7967                                                                (if (get-buffer-process it)
   7968                                                                    'lsp-installation-buffer-face
   7969                                                                  'lsp-installation-finished-buffer-face))
   7970                                                    bufs)))))))
   7971 
   7972 (defun lsp-cleanup-installation-buffers ()
   7973   "Delete finished *lsp-installation* buffers."
   7974   (interactive)
   7975   (dolist (buf (buffer-list))
   7976     (when (and (lsp--installation-buffer? buf) (not (get-buffer-process buf)))
   7977       (kill-buffer buf))))
   7978 
   7979 (defun lsp--download-status ()
   7980   (-some--> #'lsp--client-download-in-progress?
   7981     (lsp--filter-clients it)
   7982     (-map (-compose #'symbol-name #'lsp--client-server-id) it)
   7983     (format "%s" it)
   7984     (propertize it 'face 'success)
   7985     (format " Installing following servers: %s" it)
   7986     (propertize it
   7987                 'local-map (make-mode-line-mouse-map
   7988                             'mouse-1 #'lsp-select-installation-buffer)
   7989                 'mouse-face 'highlight)))
   7990 
   7991 (defun lsp--install-server-internal (client &optional update?)
   7992   (unless (lsp--client-download-server-fn client)
   7993     (user-error "There is no automatic installation for `%s', you have to install it manually following lsp-mode's documentation."
   7994                 (lsp--client-server-id client)))
   7995 
   7996   (setf (lsp--client-download-in-progress? client) t)
   7997   (add-to-list 'global-mode-string '(t (:eval (lsp--download-status))))
   7998   (cl-flet ((done
   7999              (success? &optional error-message)
   8000              ;; run with idle timer to make sure the lsp command is executed in
   8001              ;; the main thread, see #2739.
   8002              (run-with-timer
   8003               0.0
   8004               nil
   8005               (lambda ()
   8006                 (-let [(&lsp-cln 'server-id 'buffers) client]
   8007                   (setf (lsp--client-download-in-progress? client) nil
   8008                         (lsp--client-buffers client) nil)
   8009                   (if success?
   8010                       (lsp--info "Server %s downloaded, auto-starting in %s buffers." server-id
   8011                                  (length buffers))
   8012                     (lsp--error "Server %s install process failed with the following error message: %s.
   8013 Check `*lsp-install*' and `*lsp-log*' buffer."
   8014                                 server-id
   8015                                 error-message))
   8016                   (seq-do
   8017                    (lambda (buffer)
   8018                      (when (lsp-buffer-live-p buffer)
   8019                        (lsp-with-current-buffer buffer
   8020                          (cl-callf2 -remove-item '(t (:eval (lsp--download-status)))
   8021                                     global-mode-string)
   8022                          (when success? (lsp)))))
   8023                    buffers)
   8024                   (unless (lsp--filter-clients #'lsp--client-download-in-progress?)
   8025                     (cl-callf2 -remove-item '(t (:eval (lsp--download-status)))
   8026                                global-mode-string)))))))
   8027     (lsp--info "Download %s started." (lsp--client-server-id client))
   8028     (condition-case err
   8029         (funcall
   8030          (lsp--client-download-server-fn client)
   8031          client
   8032          (lambda () (done t))
   8033          (lambda (msg) (done nil msg))
   8034          update?)
   8035       (error
   8036        (done nil (error-message-string err))))))
   8037 
   8038 (defun lsp--require-packages ()
   8039   "Load `lsp-client-packages' if needed."
   8040   (when (and lsp-auto-configure (not lsp--client-packages-required))
   8041     (seq-do (lambda (package)
   8042               ;; loading client is slow and `lsp' can be called repeatedly
   8043               (unless (featurep package)
   8044                 (require package nil t)))
   8045             lsp-client-packages)
   8046     (setq lsp--client-packages-required t)))
   8047 
   8048 ;;;###autoload
   8049 (defun lsp-install-server (update? &optional server-id)
   8050   "Interactively install or re-install server.
   8051 When prefix UPDATE? is t force installation even if the server is present."
   8052   (interactive "P")
   8053   (lsp--require-packages)
   8054   (let* ((chosen-client (or (gethash server-id lsp-clients)
   8055                             (lsp--completing-read
   8056                              "Select server to install/re-install: "
   8057                              (or (->> lsp-clients
   8058                                       (ht-values)
   8059                                       (-filter (-andfn
   8060                                                 (-not #'lsp--client-download-in-progress?)
   8061                                                 #'lsp--client-download-server-fn)))
   8062                                  (user-error "There are no servers with automatic installation"))
   8063                              (lambda (client)
   8064                                (let ((server-name (-> client lsp--client-server-id symbol-name)))
   8065                                  (if (lsp--server-binary-present? client)
   8066                                      (concat server-name " (Already installed)")
   8067                                    server-name)))
   8068                              nil
   8069                              t)))
   8070          (update? (or update?
   8071                       (and (not (lsp--client-download-in-progress? chosen-client))
   8072                            (lsp--server-binary-present? chosen-client)))))
   8073     (lsp--install-server-internal chosen-client update?)))
   8074 
   8075 ;;;###autoload
   8076 (defun lsp-uninstall-server (dir)
   8077   "Delete a LSP server from `lsp-server-install-dir'."
   8078   (interactive
   8079    (list (read-directory-name "Uninstall LSP server: " (f-slash lsp-server-install-dir))))
   8080   (unless (file-directory-p dir)
   8081     (user-error "Couldn't find %s directory" dir))
   8082   (delete-directory dir 'recursive)
   8083   (message "Server `%s' uninstalled." (file-name-nondirectory (directory-file-name dir))))
   8084 
   8085 ;;;###autoload
   8086 (defun lsp-uninstall-servers ()
   8087   "Uninstall all installed servers."
   8088   (interactive)
   8089   (let* ((dir lsp-server-install-dir)
   8090          (servers (ignore-errors
   8091                     (directory-files dir t
   8092                                      directory-files-no-dot-files-regexp))))
   8093     (if (or (not (file-directory-p dir)) (zerop (length servers)))
   8094         (user-error "No servers to uninstall")
   8095       (when (yes-or-no-p
   8096              (format "Servers to uninstall: %d (%s), proceed? "
   8097                      (length servers)
   8098                      (mapconcat (lambda (server)
   8099                                   (file-name-nondirectory (directory-file-name server)))
   8100                                 servers " ")))
   8101         (mapc #'lsp-uninstall-server servers)
   8102         (message "All servers uninstalled")))))
   8103 
   8104 ;;;###autoload
   8105 (defun lsp-update-server (&optional server-id)
   8106   "Interactively update (reinstall) a server."
   8107   (interactive)
   8108   (lsp--require-packages)
   8109   (let ((chosen-client (or (gethash server-id lsp-clients)
   8110                            (lsp--completing-read
   8111                             "Select server to update (if not on the list, probably you need to `lsp-install-server`): "
   8112                             (or (->> lsp-clients
   8113                                      (ht-values)
   8114                                      (-filter (-andfn
   8115                                                (-not #'lsp--client-download-in-progress?)
   8116                                                #'lsp--client-download-server-fn
   8117                                                #'lsp--server-binary-present?)))
   8118                                 (user-error "There are no servers to update"))
   8119                             (lambda (client)
   8120                               (-> client lsp--client-server-id symbol-name))
   8121                             nil
   8122                             t))))
   8123     (lsp--install-server-internal chosen-client t)))
   8124 
   8125 ;;;###autoload
   8126 (defun lsp-update-servers ()
   8127   "Update (reinstall) all installed servers."
   8128   (interactive)
   8129   (lsp--require-packages)
   8130   (mapc (lambda (client) (lsp--install-server-internal client t))
   8131         (-filter (-andfn
   8132                   (-not #'lsp--client-download-in-progress?)
   8133                   #'lsp--client-download-server-fn
   8134                   #'lsp--server-binary-present?) (hash-table-values lsp-clients))))
   8135 
   8136 ;;;###autoload
   8137 (defun lsp-ensure-server (server-id)
   8138   "Ensure server SERVER-ID"
   8139   (lsp--require-packages)
   8140   (if-let ((client (gethash server-id lsp-clients)))
   8141       (unless (lsp--server-binary-present? client)
   8142         (lsp--info "Server `%s' is not preset, installing..." server-id)
   8143         (lsp-install-server nil server-id))
   8144     (warn "Unable to find server registration with id %s" server-id)))
   8145 
   8146 (defun lsp-async-start-process (callback error-callback &rest command)
   8147   "Start async process COMMAND with CALLBACK and ERROR-CALLBACK."
   8148   (let ((name (cl-first command)))
   8149     (with-current-buffer (compilation-start (mapconcat #'shell-quote-argument (-filter (lambda (cmd)
   8150                                                                                          (not (null cmd)))
   8151                                                                                        command)
   8152                                                        " ") t
   8153                                             (lambda (&rest _)
   8154                                               (generate-new-buffer-name (format "*lsp-install: %s*" name))))
   8155       (lsp-installation-buffer-mode +1)
   8156       (view-mode +1)
   8157       (add-hook
   8158        'compilation-finish-functions
   8159        (lambda (_buf status)
   8160          (if (string= "finished\n" status)
   8161              (condition-case err
   8162                  (funcall callback)
   8163                (error
   8164                 (funcall error-callback (error-message-string err))))
   8165            (funcall error-callback (s-trim-right status))))
   8166        nil t))))
   8167 
   8168 (defun lsp-resolve-value (value)
   8169   "Resolve VALUE's value.
   8170 If it is function - call it.
   8171 If it is a variable - return it's value
   8172 Otherwise returns value itself."
   8173   (cond
   8174    ((functionp value) (funcall value))
   8175    ((and (symbolp value) (boundp value)) (symbol-value value))
   8176    (value)))
   8177 
   8178 (defvar lsp-deps-providers
   8179   (list :npm (list :path #'lsp--npm-dependency-path
   8180                    :install #'lsp--npm-dependency-install)
   8181         :cargo (list :path #'lsp--cargo-dependency-path
   8182                      :install #'lsp--cargo-dependency-install)
   8183         :system (list :path #'lsp--system-path)
   8184         :download (list :path #'lsp-download-path
   8185                         :install #'lsp-download-install)))
   8186 
   8187 (defun lsp--system-path (path)
   8188   "If PATH is absolute and exists return it as is. Otherwise,
   8189 return the absolute path to the executable defined by PATH or
   8190 nil."
   8191   ;; For node.js 'sub-packages' PATH may point to a *.js file. Consider the
   8192   ;; typescript-language-server. When lsp invokes the server, lsp needs to
   8193   ;; supply the path to the typescript compiler, tsserver.js, as an argument. To
   8194   ;; make code platform independent, one must pass the absolute path to the
   8195   ;; tsserver.js file (Windows requires a *.js file - see help on the JavaScript
   8196   ;; child process spawn command that is invoked by the
   8197   ;; typescript-language-server). This is why we check for existence and not
   8198   ;; that the path is executable.
   8199   (let ((path (lsp-resolve-value path)))
   8200     (cond
   8201      ((and (f-absolute? path)
   8202            (f-exists? path))
   8203       path)
   8204      ((executable-find path t) path))))
   8205 
   8206 (defun lsp-package-path (dependency)
   8207   "Path to the DEPENDENCY each of the registered providers."
   8208   (let (path)
   8209     (-first (-lambda ((provider . rest))
   8210               (setq path (-some-> lsp-deps-providers
   8211                            (plist-get provider)
   8212                            (plist-get :path)
   8213                            (apply rest))))
   8214             (gethash dependency lsp--dependencies))
   8215     path))
   8216 
   8217 (defun lsp-package-ensure (dependency callback error-callback)
   8218   "Asynchronously ensure a package."
   8219   (or (-first (-lambda ((provider . rest))
   8220                 (-some-> lsp-deps-providers
   8221                   (plist-get provider)
   8222                   (plist-get :install)
   8223                   (apply (cl-list* callback error-callback rest))))
   8224               (gethash dependency lsp--dependencies))
   8225       (funcall error-callback (format "Unable to find a way to install %s" dependency))))
   8226 
   8227 
   8228 ;; npm handling
   8229 
   8230 ;; https://docs.npmjs.com/files/folders#executables
   8231 (cl-defun lsp--npm-dependency-path (&key package path &allow-other-keys)
   8232   "Return npm dependency PATH for PACKAGE."
   8233   (let ((path (executable-find
   8234                (f-join lsp-server-install-dir "npm" package
   8235                        (cond ((eq system-type 'windows-nt) "")
   8236                              (t "bin"))
   8237                        path)
   8238                t)))
   8239     (unless (and path (f-exists? path))
   8240       (error "The package %s is not installed.  Unable to find %s" package path))
   8241     path))
   8242 
   8243 (cl-defun lsp--npm-dependency-install (callback error-callback &key package &allow-other-keys)
   8244   (if-let ((npm-binary (executable-find "npm")))
   8245       (progn
   8246         ;; Explicitly `make-directory' to work around NPM bug in
   8247         ;; versions 7.0.0 through 7.4.1. See
   8248         ;; https://github.com/emacs-lsp/lsp-mode/issues/2364 for
   8249         ;; discussion.
   8250         (make-directory (f-join lsp-server-install-dir "npm" package "lib") 'parents)
   8251         (lsp-async-start-process (lambda ()
   8252                                    (if (string-empty-p
   8253                                         (string-trim (shell-command-to-string
   8254                                                       (mapconcat #'shell-quote-argument `(,npm-binary "view" ,package "peerDependencies") " "))))
   8255                                        (funcall callback)
   8256                                      (let ((default-directory (f-dirname (car (last (directory-files-recursively (f-join lsp-server-install-dir "npm" package) "package.json")))))
   8257                                            (process-environment (append '("npm_config_yes=true") process-environment))) ;; Disable prompting for older versions of npx
   8258                                        (when (f-dir-p default-directory)
   8259                                          (lsp-async-start-process callback
   8260                                                                   error-callback
   8261                                                                   (executable-find "npx")
   8262                                                                   "npm-install-peers")))))
   8263                                  error-callback
   8264                                  npm-binary
   8265                                  "-g"
   8266                                  "--prefix"
   8267                                  (f-join lsp-server-install-dir "npm" package)
   8268                                  "install"
   8269                                  package))
   8270     (lsp-log "Unable to install %s via `npm' because it is not present" package)
   8271     nil))
   8272 
   8273 
   8274 ;; Cargo dependency handling
   8275 (cl-defun lsp--cargo-dependency-path (&key package path &allow-other-keys)
   8276   (let ((path (executable-find
   8277                (f-join lsp-server-install-dir
   8278                        "cargo"
   8279                        package
   8280                        "bin"
   8281                        path)
   8282                t)))
   8283     (unless (and path (f-exists? path))
   8284       (error "The package %s is not installed.  Unable to find %s" package path))
   8285     path))
   8286 
   8287 (cl-defun lsp--cargo-dependency-install (callback error-callback &key package git &allow-other-keys)
   8288   (if-let ((cargo-binary (executable-find "cargo")))
   8289       (lsp-async-start-process
   8290        callback
   8291        error-callback
   8292        cargo-binary
   8293        "install"
   8294        package
   8295        (when git
   8296          "--git")
   8297        git
   8298        "--root"
   8299        (f-join lsp-server-install-dir "cargo" package))
   8300     (lsp-log "Unable to install %s via `cargo' because it is not present" package)
   8301     nil))
   8302 
   8303 
   8304 
   8305 ;; Download URL handling
   8306 (cl-defun lsp-download-install (callback error-callback &key url asc-url pgp-key store-path decompress &allow-other-keys)
   8307   (let* ((url (lsp-resolve-value url))
   8308          (store-path (lsp-resolve-value store-path))
   8309          ;; (decompress (lsp-resolve-value decompress))
   8310          (download-path
   8311           (pcase decompress
   8312             (:gzip (concat store-path ".gz"))
   8313             (:zip (concat store-path ".zip"))
   8314             (:targz (concat store-path ".tar.gz"))
   8315             (`nil store-path)
   8316             (_ (error ":decompress must be `:gzip', `:zip', `:targz' or `nil'")))))
   8317     (make-thread
   8318      (lambda ()
   8319        (condition-case err
   8320            (progn
   8321              (when (f-exists? download-path)
   8322                (f-delete download-path))
   8323              (when (f-exists? store-path)
   8324                (f-delete store-path))
   8325              (lsp--info "Starting to download %s to %s..." url download-path)
   8326              (mkdir (f-parent download-path) t)
   8327              (url-copy-file url download-path)
   8328              (lsp--info "Finished downloading %s..." download-path)
   8329              (when (and lsp-verify-signature asc-url pgp-key)
   8330                (if (executable-find epg-gpg-program)
   8331                    (let ((asc-download-path (concat download-path ".asc"))
   8332                          (context (epg-make-context))
   8333                          (fingerprint)
   8334                          (signature))
   8335                      (when (f-exists? asc-download-path)
   8336                        (f-delete asc-download-path))
   8337                      (lsp--info "Starting to download %s to %s..." asc-url asc-download-path)
   8338                      (url-copy-file asc-url asc-download-path)
   8339                      (lsp--info "Finished downloading %s..." asc-download-path)
   8340                      (epg-import-keys-from-string context pgp-key)
   8341                      (setq fingerprint (epg-import-status-fingerprint
   8342                                         (car
   8343                                          (epg-import-result-imports
   8344                                           (epg-context-result-for context 'import)))))
   8345                      (lsp--info "Verifying signature %s..." asc-download-path)
   8346                      (epg-verify-file context asc-download-path download-path)
   8347                      (setq signature (car (epg-context-result-for context 'verify)))
   8348                      (unless (and
   8349                               (eq (epg-signature-status signature) 'good)
   8350                               (equal (epg-signature-fingerprint signature) fingerprint))
   8351                        (error "Failed to verify GPG signature: %s" (epg-signature-to-string signature))))
   8352                  (lsp--warn "GPG is not installed, skipping the signature check.")))
   8353              (when decompress
   8354                (lsp--info "Decompressing %s..." download-path)
   8355                (pcase decompress
   8356                  (:gzip
   8357                   (lsp-gunzip download-path))
   8358                  (:zip (lsp-unzip download-path (f-parent store-path)))
   8359                  (:targz (lsp-tar-gz-decompress download-path (f-parent store-path))))
   8360                (lsp--info "Decompressed %s..." store-path))
   8361              (funcall callback))
   8362          (error (funcall error-callback err)))))))
   8363 
   8364 (cl-defun lsp-download-path (&key store-path binary-path set-executable? &allow-other-keys)
   8365   "Download URL and store it into STORE-PATH.
   8366 
   8367 SET-EXECUTABLE? when non-nil change the executable flags of
   8368 STORE-PATH to make it executable. BINARY-PATH can be specified
   8369 when the binary to start does not match the name of the
   8370 archive (e.g. when the archive has multiple files)"
   8371   (let ((store-path (or (lsp-resolve-value binary-path)
   8372                         (lsp-resolve-value store-path))))
   8373     (cond
   8374      ((executable-find store-path) store-path)
   8375      ((and set-executable? (f-exists? store-path))
   8376       (set-file-modes store-path #o0700)
   8377       store-path)
   8378      ((f-exists? store-path) store-path))))
   8379 
   8380 (defun lsp--find-latest-gh-release-url (url regex)
   8381   "Fetch the latest version in the releases given by URL by using REGEX."
   8382   (let ((url-request-method "GET"))
   8383     (with-current-buffer (url-retrieve-synchronously url)
   8384       (goto-char (point-min))
   8385       (re-search-forward "\n\n" nil 'noerror)
   8386       (delete-region (point-min) (point))
   8387       (let* ((json-result (lsp-json-read-buffer)))
   8388         (message "Latest version found: %s" (lsp-get json-result :tag_name))
   8389         (--> json-result
   8390              (lsp-get it :assets)
   8391              (seq-find (lambda (entry) (string-match-p regex (lsp-get entry :name))) it)
   8392              (lsp-get it :browser_download_url))))))
   8393 
   8394 ;; unzip
   8395 
   8396 (defconst lsp-ext-pwsh-script "powershell -noprofile -noninteractive \
   8397 -nologo -ex bypass -command Expand-Archive -path '%s' -dest '%s'"
   8398   "Powershell script to unzip file.")
   8399 
   8400 (defconst lsp-ext-unzip-script "bash -c 'mkdir -p %2$s && unzip -qq -o %1$s -d %2$s'"
   8401   "Unzip script to unzip file.")
   8402 
   8403 (defcustom lsp-unzip-script (lambda ()
   8404                               (cond ((executable-find "unzip") lsp-ext-unzip-script)
   8405                                     ((executable-find "powershell") lsp-ext-pwsh-script)
   8406                                     (t nil)))
   8407   "The script to unzip."
   8408   :group 'lsp-mode
   8409   :type 'string
   8410   :package-version '(lsp-mode . "8.0.0"))
   8411 
   8412 (defun lsp-unzip (zip-file dest)
   8413   "Unzip ZIP-FILE to DEST."
   8414   (unless lsp-unzip-script
   8415     (error "Unable to find `unzip' or `powershell' on the path, please customize `lsp-unzip-script'"))
   8416   (shell-command (format (lsp-resolve-value lsp-unzip-script) zip-file dest)))
   8417 
   8418 ;; gunzip
   8419 
   8420 (defconst lsp-ext-gunzip-script "gzip -d %1$s"
   8421   "Script to decompress a gzippped file with gzip.")
   8422 
   8423 (defcustom lsp-gunzip-script (lambda ()
   8424                                (cond ((executable-find "gzip") lsp-ext-gunzip-script)
   8425                                      (t nil)))
   8426   "The script to decompress a gzipped file.
   8427 Should be a format string with one argument for the file to be decompressed
   8428 in place."
   8429   :group 'lsp-mode
   8430   :type 'string
   8431   :package-version '(lsp-mode . "8.0.0"))
   8432 
   8433 (defun lsp-gunzip (gz-file)
   8434   "Decompress GZ-FILE in place."
   8435   (unless lsp-gunzip-script
   8436     (error "Unable to find `gzip' on the path, please either customize `lsp-gunzip-script' or manually decompress %s" gz-file))
   8437   (shell-command (format (lsp-resolve-value lsp-gunzip-script) gz-file)))
   8438 
   8439 ;; tar.gz decompression
   8440 
   8441 (defconst lsp-ext-tar-script "bash -c 'mkdir -p %2$s; tar xf %1$s --directory=%2$s'"
   8442   "Script to decompress a .tar.gz file.")
   8443 
   8444 (defcustom lsp-tar-script (lambda ()
   8445                             (cond ((executable-find "tar") lsp-ext-tar-script)
   8446                                   (t nil)))
   8447   "The script to decompress a .tar.gz file.
   8448 Should be a format string with one argument for the file to be decompressed
   8449 in place."
   8450   :group 'lsp-mode
   8451   :type 'string)
   8452 
   8453 (defun lsp-tar-gz-decompress (targz-file dest)
   8454   "Decompress TARGZ-FILE in DEST."
   8455   (unless lsp-tar-script
   8456     (error "Unable to find `tar' on the path, please either customize `lsp-tar-script' or manually decompress %s" targz-file))
   8457   (shell-command (format (lsp-resolve-value lsp-tar-script) targz-file dest)))
   8458 
   8459 
   8460 ;; VSCode marketplace
   8461 
   8462 (defcustom lsp-vscode-ext-url
   8463   "https://marketplace.visualstudio.com/_apis/public/gallery/publishers/%s/vsextensions/%s/%s/vspackage%s"
   8464   "Vscode extension template url."
   8465   :group 'lsp-mode
   8466   :type 'string
   8467   :package-version '(lsp-mode . "8.0.0"))
   8468 
   8469 (defun lsp-vscode-extension-url (publisher name version &optional targetPlatform)
   8470   "Return the URL to vscode extension.
   8471 PUBLISHER is the extension publisher.
   8472 NAME is the name of the extension.
   8473 VERSION is the version of the extension.
   8474 TARGETPLATFORM is the targetPlatform of the extension."
   8475   (format lsp-vscode-ext-url publisher name version (or targetPlatform "")))
   8476 
   8477 
   8478 
   8479 ;; Queueing prompts
   8480 
   8481 (defvar lsp--question-queue nil
   8482   "List of questions yet to be asked by `lsp-ask-question'.")
   8483 
   8484 (defun lsp-ask-question (question options callback)
   8485   "Prompt the user to answer the QUESTION with one of the OPTIONS from the
   8486 minibuffer. Once the user selects an option, the CALLBACK function will be
   8487 called, passing the selected option to it.
   8488 
   8489 If the user is currently being shown a question, the question will be stored in
   8490 `lsp--question-queue', and will be asked once the user has answered the current
   8491 question."
   8492   (add-to-list 'lsp--question-queue `(("question" . ,question)
   8493                                       ("options" . ,options)
   8494                                       ("callback" . ,callback)) t)
   8495   (when (eq (length lsp--question-queue) 1)
   8496     (lsp--process-question-queue)))
   8497 
   8498 (defun lsp--process-question-queue ()
   8499   "Take the first question from `lsp--question-queue', process it, then process
   8500 the next question until the queue is empty."
   8501   (-let* (((&alist "question" "options" "callback") (car lsp--question-queue))
   8502           (answer (completing-read question options nil t)))
   8503     (pop lsp--question-queue)
   8504     (funcall callback answer)
   8505     (when lsp--question-queue
   8506       (lsp--process-question-queue))))
   8507 
   8508 (defun lsp--supports-buffer? (client)
   8509   (and
   8510    ;; both file and client remote or both local
   8511    (eq (---truthy? (file-remote-p (buffer-file-name)))
   8512        (---truthy? (lsp--client-remote? client)))
   8513 
   8514    ;; activation function or major-mode match.
   8515    (if-let ((activation-fn (lsp--client-activation-fn client)))
   8516        (funcall activation-fn (buffer-file-name) major-mode)
   8517      (-contains? (lsp--client-major-modes client) major-mode))
   8518 
   8519    ;; check whether it is enabled if `lsp-enabled-clients' is not null
   8520    (or (null lsp-enabled-clients)
   8521        (or (member (lsp--client-server-id client) lsp-enabled-clients)
   8522            (ignore (lsp--info "Client %s is not in lsp-enabled-clients"
   8523                               (lsp--client-server-id client)))))
   8524 
   8525    ;; check whether it is not disabled.
   8526    (not (lsp--client-disabled-p major-mode (lsp--client-server-id client)))))
   8527 
   8528 (defun lsp--filter-clients (pred)
   8529   (->> lsp-clients hash-table-values (-filter pred)))
   8530 
   8531 (defun lsp--find-clients ()
   8532   "Find clients which can handle current buffer."
   8533   (-when-let (matching-clients (lsp--filter-clients (-andfn #'lsp--supports-buffer?
   8534                                                             #'lsp--server-binary-present?)))
   8535     (lsp-log "Found the following clients for %s: %s"
   8536              (buffer-file-name)
   8537              (s-join ", "
   8538                      (-map (lambda (client)
   8539                              (format "(server-id %s, priority %s)"
   8540                                      (lsp--client-server-id client)
   8541                                      (lsp--client-priority client)))
   8542                            matching-clients)))
   8543     (-let* (((add-on-clients main-clients) (-separate #'lsp--client-add-on? matching-clients))
   8544             (selected-clients (if-let ((main-client (and main-clients
   8545                                                          (--max-by (> (lsp--client-priority it)
   8546                                                                       (lsp--client-priority other))
   8547                                                                    main-clients))))
   8548                                   (cons main-client add-on-clients)
   8549                                 add-on-clients)))
   8550       (lsp-log "The following clients were selected based on priority: %s"
   8551                (s-join ", "
   8552                        (-map (lambda (client)
   8553                                (format "(server-id %s, priority %s)"
   8554                                        (lsp--client-server-id client)
   8555                                        (lsp--client-priority client)))
   8556                              selected-clients)))
   8557       selected-clients)))
   8558 
   8559 (defun lsp-workspace-remove-all-folders()
   8560   "Delete all lsp tracked folders."
   8561   (interactive)
   8562   (--each (lsp-session-folders (lsp-session))
   8563     (lsp-workspace-folders-remove it)))
   8564 
   8565 (defun lsp-register-client (client)
   8566   "Registers LSP client CLIENT."
   8567   (let ((client-id (lsp--client-server-id client)))
   8568     (puthash client-id client lsp-clients)
   8569     (setplist (intern (format "lsp-%s-after-open-hook" client-id))
   8570               `( standard-value (nil) custom-type hook
   8571                  custom-package-version (lsp-mode . "7.0.1")
   8572                  variable-documentation ,(format "Hooks to run after `%s' server is run." client-id)
   8573                  custom-requests nil)))
   8574   (when (and lsp-auto-register-remote-clients
   8575              (not (lsp--client-remote? client)))
   8576     (let ((remote-client (copy-lsp--client client)))
   8577       (setf (lsp--client-remote? remote-client) t
   8578             (lsp--client-server-id remote-client) (intern
   8579                                                    (format "%s-tramp"
   8580                                                            (lsp--client-server-id client)))
   8581             ;; disable automatic download
   8582             (lsp--client-download-server-fn remote-client) nil)
   8583       (lsp-register-client remote-client))))
   8584 
   8585 (defun lsp--create-initialization-options (_session client)
   8586   "Create initialization-options from SESSION and CLIENT.
   8587 Add workspace folders depending on server being multiroot and
   8588 session workspace folder configuration for the server."
   8589   (let* ((initialization-options-or-fn (lsp--client-initialization-options client)))
   8590     (if (functionp initialization-options-or-fn)
   8591         (funcall initialization-options-or-fn)
   8592       initialization-options-or-fn)))
   8593 
   8594 (defvar lsp-client-settings (make-hash-table :test 'equal)
   8595   "For internal use, any external users please use
   8596   `lsp-register-custom-settings' function instead")
   8597 
   8598 (defun lsp-register-custom-settings (props)
   8599   "Register PROPS.
   8600 PROPS is list of triple (path value boolean?) where PATH is the path to the
   8601 property; VALUE can be a literal value, symbol to be evaluated, or either a
   8602 function or lambda function to be called without arguments; BOOLEAN? is an
   8603 optional flag that should be non-nil for boolean settings, when it is nil the
   8604 property will be ignored if the VALUE is nil.
   8605 
   8606 Example: `(lsp-register-custom-settings `((\"foo.bar.buzz.enabled\" t t)))'
   8607 \(note the double parentheses)"
   8608   (mapc
   8609    (-lambda ((path . rest))
   8610      (puthash path rest lsp-client-settings))
   8611    props))
   8612 
   8613 (defun lsp-region-text (region)
   8614   "Get the text for REGION in current buffer."
   8615   (-let (((start . end) (lsp--range-to-region region)))
   8616     (buffer-substring-no-properties start end)))
   8617 
   8618 (defun lsp-ht-set (tbl paths value)
   8619   "Set nested hash table value.
   8620 TBL - a hash table, PATHS is the path to the nested VALUE."
   8621   (pcase paths
   8622     (`(,path) (ht-set! tbl path value))
   8623     (`(,path . ,rst) (let ((nested-tbl (or (gethash path tbl)
   8624                                            (let ((temp-tbl (ht)))
   8625                                              (ht-set! tbl path temp-tbl)
   8626                                              temp-tbl))))
   8627                        (lsp-ht-set nested-tbl rst value)))))
   8628 
   8629 ;; sections
   8630 
   8631 (defalias 'defcustom-lsp 'lsp-defcustom)
   8632 
   8633 (defmacro lsp-defcustom (symbol standard doc &rest args)
   8634   "Defines `lsp-mode' server property."
   8635   (declare (doc-string 3) (debug (name body))
   8636            (indent defun))
   8637   (let ((path (plist-get args :lsp-path)))
   8638     (cl-remf args :lsp-path)
   8639     `(progn
   8640        (lsp-register-custom-settings
   8641         (quote ((,path ,symbol ,(equal ''boolean (plist-get args :type))))))
   8642 
   8643        (defcustom ,symbol ,standard ,doc
   8644          :set (lambda (sym val)
   8645                 (lsp--set-custom-property sym val ,path))
   8646          ,@args))))
   8647 
   8648 (defun lsp--set-custom-property (sym val path)
   8649   (set sym val)
   8650   (let ((section (cl-first (s-split "\\." path))))
   8651     (mapc (lambda (workspace)
   8652             (when (-contains? (lsp--client-synchronize-sections (lsp--workspace-client workspace))
   8653                               section)
   8654               (with-lsp-workspace workspace
   8655                 (lsp--set-configuration (lsp-configuration-section section)))))
   8656           (lsp--session-workspaces (lsp-session)))))
   8657 
   8658 (defun lsp-configuration-section (section)
   8659   "Get settings for SECTION."
   8660   (let ((ret (ht-create)))
   8661     (maphash (-lambda (path (variable boolean?))
   8662                (when (s-matches? (concat (regexp-quote section) "\\..*") path)
   8663                  (let* ((symbol-value (-> variable
   8664                                           lsp-resolve-value
   8665                                           lsp-resolve-value))
   8666                         (value (if (and boolean? (not symbol-value))
   8667                                    :json-false
   8668                                  symbol-value)))
   8669                    (when (or boolean? value)
   8670                      (lsp-ht-set ret (s-split "\\." path) value)))))
   8671              lsp-client-settings)
   8672     ret))
   8673 
   8674 
   8675 (defun lsp--start-connection (session client project-root)
   8676   "Initiates connection created from CLIENT for PROJECT-ROOT.
   8677 SESSION is the active session."
   8678   (when (lsp--client-multi-root client)
   8679     (cl-pushnew project-root (gethash (lsp--client-server-id client)
   8680                                       (lsp-session-server-id->folders session))))
   8681   (run-hook-with-args 'lsp-workspace-folders-changed-functions (list project-root) nil)
   8682 
   8683   (unwind-protect
   8684       (lsp--start-workspace session client project-root (lsp--create-initialization-options session client))
   8685     (lsp--spinner-stop)))
   8686 
   8687 ;; lsp-log-io-mode
   8688 
   8689 (defvar lsp-log-io-mode-map
   8690   (let ((map (make-sparse-keymap)))
   8691     (define-key map (kbd "M-n") #'lsp-log-io-next)
   8692     (define-key map (kbd "M-p") #'lsp-log-io-prev)
   8693     (define-key map (kbd "k") #'lsp--erase-log-buffer)
   8694     (define-key map (kbd "K") #'lsp--erase-session-log-buffers)
   8695     map)
   8696   "Keymap for lsp log buffer mode.")
   8697 
   8698 (define-derived-mode lsp-log-io-mode special-mode "LspLogIo"
   8699   "Special mode for viewing IO logs.")
   8700 
   8701 (defun lsp-workspace-show-log (workspace)
   8702   "Display the log buffer of WORKSPACE."
   8703   (interactive
   8704    (list (if lsp-log-io
   8705              (if (eq (length (lsp-workspaces)) 1)
   8706                  (cl-first (lsp-workspaces))
   8707                (lsp--completing-read "Workspace: " (lsp-workspaces)
   8708                                      #'lsp--workspace-print nil t))
   8709            (user-error "IO logging is disabled"))))
   8710   (pop-to-buffer (lsp--get-log-buffer-create workspace)))
   8711 
   8712 (defalias 'lsp-switch-to-io-log-buffer 'lsp-workspace-show-log)
   8713 
   8714 (defun lsp--get-log-buffer-create (workspace)
   8715   "Return the lsp log buffer of WORKSPACE, creating a new one if needed."
   8716   (let* ((server-id (-> workspace lsp--workspace-client lsp--client-server-id symbol-name))
   8717          (pid (-> workspace lsp--workspace-cmd-proc lsp-process-id)))
   8718     (get-buffer-create (format "*lsp-log: %s:%s*" server-id pid))))
   8719 
   8720 (defun lsp--erase-log-buffer (&optional all)
   8721   "Delete contents of current lsp log buffer.
   8722 When ALL is t, erase all log buffers of the running session."
   8723   (interactive)
   8724   (let* ((workspaces (lsp--session-workspaces (lsp-session)))
   8725          (current-log-buffer (current-buffer)))
   8726     (dolist (w workspaces)
   8727       (let ((b (lsp--get-log-buffer-create w)))
   8728         (when (or all (eq b current-log-buffer))
   8729           (with-current-buffer b
   8730             (let ((inhibit-read-only t))
   8731               (erase-buffer))))))))
   8732 
   8733 (defun lsp--erase-session-log-buffers ()
   8734   "Erase log buffers of the running session."
   8735   (interactive)
   8736   (lsp--erase-log-buffer t))
   8737 
   8738 (defun lsp-log-io-next (arg)
   8739   "Move to next log entry."
   8740   (interactive "P")
   8741   (ewoc-goto-next lsp--log-io-ewoc (or arg 1)))
   8742 
   8743 (defun lsp-log-io-prev (arg)
   8744   "Move to previous log entry."
   8745   (interactive "P")
   8746   (ewoc-goto-prev lsp--log-io-ewoc (or arg 1)))
   8747 
   8748 
   8749 
   8750 (cl-defmethod lsp-process-id ((process process))
   8751   (process-id process))
   8752 
   8753 (cl-defmethod lsp-process-name ((process process)) (process-name process))
   8754 
   8755 (cl-defmethod lsp-process-status ((process process)) (process-status process))
   8756 
   8757 (cl-defmethod lsp-process-kill ((process process))
   8758   (when (process-live-p process)
   8759     (kill-process process)))
   8760 
   8761 (cl-defmethod lsp-process-send ((process process) message)
   8762   (condition-case err
   8763       (process-send-string process (lsp--make-message message))
   8764     (error (lsp--error "Sending to process failed with the following error: %s"
   8765                        (error-message-string err)))))
   8766 
   8767 (cl-defmethod lsp-process-cleanup (process)
   8768   ;; Kill standard error buffer only if the process exited normally.
   8769   ;; Leave it intact otherwise for debugging purposes.
   8770   (let ((buffer (-> process process-name get-buffer)))
   8771     (when (and (eq (process-status process) 'exit)
   8772                (zerop (process-exit-status process))
   8773                (buffer-live-p buffer))
   8774       (kill-buffer buffer))))
   8775 
   8776 
   8777 ;; native JSONRPC
   8778 
   8779 (declare-function json-rpc "ext:json")
   8780 (declare-function json-rpc-connection "ext:json")
   8781 (declare-function json-rpc-send "ext:json")
   8782 (declare-function json-rpc-shutdown "ext:json")
   8783 (declare-function json-rpc-stderr "ext:json")
   8784 (declare-function json-rpc-pid "ext:json")
   8785 
   8786 (defvar lsp-json-rpc-thread nil)
   8787 (defvar lsp-json-rpc-queue nil)
   8788 (defvar lsp-json-rpc-done nil)
   8789 (defvar lsp-json-rpc-mutex (make-mutex))
   8790 (defvar lsp-json-rpc-condition (make-condition-variable lsp-json-rpc-mutex))
   8791 
   8792 (defun lsp-json-rpc-process-queue ()
   8793   (while (not lsp-json-rpc-done)
   8794     (while lsp-json-rpc-queue
   8795       (-let (((proc . message) (pop lsp-json-rpc-queue)))
   8796         (json-rpc-send
   8797          proc message
   8798          :null-object nil
   8799          :false-object :json-false)))
   8800     (with-mutex lsp-json-rpc-mutex
   8801       (condition-wait lsp-json-rpc-condition))))
   8802 
   8803 (cl-defmethod lsp-process-id (process) (json-rpc-pid process))
   8804 
   8805 (cl-defmethod lsp-process-name (_process) "TBD")
   8806 
   8807 (cl-defmethod lsp-process-kill (process) (json-rpc-shutdown process))
   8808 
   8809 (cl-defmethod lsp-process-send (proc message)
   8810   (unless lsp-json-rpc-thread
   8811     (with-current-buffer (get-buffer-create " *json-rpc*")
   8812       (setq lsp-json-rpc-thread (make-thread #'lsp-json-rpc-process-queue "*json-rpc-queue*"))))
   8813 
   8814   (with-mutex lsp-json-rpc-mutex
   8815     (setq lsp-json-rpc-queue (append lsp-json-rpc-queue
   8816                                      (list (cons proc message))))
   8817     (condition-notify lsp-json-rpc-condition)))
   8818 
   8819 (cl-defmethod lsp-process-cleanup (_proc))
   8820 
   8821 (defun lsp-json-rpc-connection (workspace command)
   8822   (let ((con (apply #'json-rpc-connection command))
   8823         (object-type (if lsp-use-plists 'plist 'hash-table)))
   8824     (with-current-buffer (get-buffer-create " *json-rpc*")
   8825       (make-thread
   8826        (lambda ()
   8827          (json-rpc
   8828           con
   8829           (lambda (result err done)
   8830             (run-with-timer
   8831              0.0
   8832              nil
   8833              (lambda ()
   8834                (cond
   8835                 (result (lsp--parser-on-message result workspace))
   8836                 (err (warn "Json parsing failed with the following error: %s" err))
   8837                 (done (lsp--handle-process-exit workspace ""))))))
   8838           :object-type object-type
   8839           :null-object nil
   8840           :false-object nil))
   8841        "*json-rpc-connection*"))
   8842     (cons con con)))
   8843 
   8844 (defun lsp-json-rpc-stderr ()
   8845   (interactive)
   8846   (--when-let (pcase (lsp-workspaces)
   8847                 (`nil (user-error "There are no active servers in the current buffer"))
   8848                 (`(,workspace) workspace)
   8849                 (workspaces (lsp--completing-read "Select server: "
   8850                                                   workspaces
   8851                                                   'lsp--workspace-print nil t)))
   8852     (let ((content (json-rpc-stderr (lsp--workspace-cmd-proc it)))
   8853           (buffer (format "*stderr-%s*" (lsp--workspace-print it)) ))
   8854       (with-current-buffer (get-buffer-create buffer)
   8855         (with-help-window buffer
   8856           (insert content))))))
   8857 
   8858 
   8859 (defun lsp--workspace-print (workspace)
   8860   "Visual representation WORKSPACE."
   8861   (let* ((proc (lsp--workspace-cmd-proc workspace))
   8862          (status (lsp--workspace-status workspace))
   8863          (server-id (-> workspace lsp--workspace-client lsp--client-server-id symbol-name))
   8864          (pid (lsp-process-id proc)))
   8865 
   8866     (if (eq 'initialized status)
   8867         (format "%s:%s" server-id pid)
   8868       (format "%s:%s/%s" server-id pid status))))
   8869 
   8870 (defun lsp--map-tree-widget (m)
   8871   "Build `tree-widget' from a hash-table or plist M."
   8872   (when (lsp-structure-p m)
   8873     (let (nodes)
   8874       (lsp-map (lambda (k v)
   8875                  (push `(tree-widget
   8876                          :tag ,(if (lsp-structure-p v)
   8877                                    (format "%s:" k)
   8878                                  (format "%s: %s" k
   8879                                          (propertize (format "%s" v)
   8880                                                      'face
   8881                                                      'font-lock-string-face)))
   8882                          :open t
   8883                          ,@(lsp--map-tree-widget v))
   8884                        nodes))
   8885                m)
   8886       nodes)))
   8887 
   8888 (defun lsp-buffer-name (buffer-id)
   8889   (if-let ((buffer-name (plist-get buffer-id :buffer-name)))
   8890       (funcall buffer-name buffer-id)
   8891     (buffer-name buffer-id)))
   8892 
   8893 (defun lsp--render-workspace (workspace)
   8894   "Tree node representation of WORKSPACE."
   8895   `(tree-widget :tag ,(lsp--workspace-print workspace)
   8896                 :open t
   8897                 (tree-widget :tag ,(propertize "Buffers" 'face 'font-lock-function-name-face)
   8898                              :open t
   8899                              ,@(->> workspace
   8900                                     (lsp--workspace-buffers)
   8901                                     (--map `(tree-widget
   8902                                              :tag ,(when (lsp-buffer-live-p it)
   8903                                                      (let ((buffer-name (lsp-buffer-name it)))
   8904                                                        (if (lsp-with-current-buffer it buffer-read-only)
   8905                                                            (propertize buffer-name 'face 'font-lock-constant-face)
   8906                                                          buffer-name)))))))
   8907                 (tree-widget :tag ,(propertize "Capabilities" 'face 'font-lock-function-name-face)
   8908                              ,@(-> workspace lsp--workspace-server-capabilities lsp--map-tree-widget))))
   8909 
   8910 (define-derived-mode lsp-browser-mode special-mode "LspBrowser"
   8911   "Define mode for displaying lsp sessions."
   8912   (setq-local display-buffer-base-action '(nil . ((inhibit-same-window . t)))))
   8913 
   8914 (defun lsp-describe-session ()
   8915   "Describes current `lsp-session'."
   8916   (interactive)
   8917   (let ((session (lsp-session))
   8918         (buf (get-buffer-create "*lsp session*"))
   8919         (root (lsp-workspace-root)))
   8920     (with-current-buffer buf
   8921       (lsp-browser-mode)
   8922       (let ((inhibit-read-only t))
   8923         (erase-buffer)
   8924         (--each (lsp-session-folders session)
   8925           (widget-create
   8926            `(tree-widget
   8927              :tag ,(propertize it 'face 'font-lock-keyword-face)
   8928              :open t
   8929              ,@(->> session
   8930                     (lsp-session-folder->servers)
   8931                     (gethash it)
   8932                     (-map 'lsp--render-workspace)))))))
   8933     (pop-to-buffer buf)
   8934     (goto-char (point-min))
   8935     (cl-loop for tag = (widget-get (widget-get (widget-at) :node) :tag)
   8936              until (or (and root (string= tag root)) (eobp))
   8937              do (goto-char (next-overlay-change (point))))))
   8938 
   8939 (defun lsp--session-workspaces (session)
   8940   "Get all workspaces that are part of the SESSION."
   8941   (-> session lsp-session-folder->servers hash-table-values -flatten -uniq))
   8942 
   8943 (defun lsp--find-multiroot-workspace (session client project-root)
   8944   "Look for a multiroot connection in SESSION created from CLIENT for
   8945 PROJECT-ROOT and BUFFER-MAJOR-MODE."
   8946   (when (lsp--client-multi-root client)
   8947     (-when-let (multi-root-workspace (->> session
   8948                                           (lsp--session-workspaces)
   8949                                           (--first (eq (-> it lsp--workspace-client lsp--client-server-id)
   8950                                                        (lsp--client-server-id client)))))
   8951       (with-lsp-workspace multi-root-workspace
   8952         (lsp-notify "workspace/didChangeWorkspaceFolders"
   8953                     (lsp-make-did-change-workspace-folders-params
   8954                      :event (lsp-make-workspace-folders-change-event
   8955                              :added (vector (lsp-make-workspace-folder
   8956                                              :uri (lsp--path-to-uri project-root)
   8957                                              :name (f-filename project-root)))
   8958                              :removed []))))
   8959 
   8960       (->> session (lsp-session-folder->servers) (gethash project-root) (cl-pushnew multi-root-workspace))
   8961       (->> session (lsp-session-server-id->folders) (gethash (lsp--client-server-id client)) (cl-pushnew project-root))
   8962 
   8963       (lsp--persist-session session)
   8964 
   8965       (lsp--info "Opened folder %s in workspace %s" project-root (lsp--workspace-print multi-root-workspace))
   8966       (lsp--open-in-workspace multi-root-workspace)
   8967 
   8968       multi-root-workspace)))
   8969 
   8970 (defun lsp--ensure-lsp-servers (session clients project-root ignore-multi-folder)
   8971   "Ensure that SESSION contain server CLIENTS created for PROJECT-ROOT.
   8972 IGNORE-MULTI-FOLDER to ignore multi folder server."
   8973   (-map (lambda (client)
   8974           (or
   8975            (lsp--find-workspace session client project-root)
   8976            (unless ignore-multi-folder
   8977              (lsp--find-multiroot-workspace session client project-root))
   8978            (lsp--start-connection session client project-root)))
   8979         clients))
   8980 
   8981 (defun lsp--spinner-stop ()
   8982   "Stop the spinner in case all of the workspaces are started."
   8983   (when (--all? (eq (lsp--workspace-status it) 'initialized)
   8984                 lsp--buffer-workspaces)
   8985     (spinner-stop)))
   8986 
   8987 (defun lsp--open-in-workspace (workspace)
   8988   "Open in existing WORKSPACE."
   8989   (if (eq 'initialized (lsp--workspace-status workspace))
   8990       ;; when workspace is initialized just call document did open.
   8991       (progn
   8992         (with-lsp-workspace workspace
   8993           (when-let ((before-document-open-fn (-> workspace
   8994                                                   lsp--workspace-client
   8995                                                   lsp--client-before-file-open-fn)))
   8996             (funcall before-document-open-fn workspace))
   8997           (lsp--text-document-did-open))
   8998         (lsp--spinner-stop))
   8999     ;; when it is not initialized
   9000     (lsp--spinner-start)
   9001     (cl-pushnew (lsp-current-buffer) (lsp--workspace-buffers workspace))))
   9002 
   9003 (defun lsp--find-workspace (session client project-root)
   9004   "Find server connection created with CLIENT in SESSION for PROJECT-ROOT."
   9005   (when-let ((workspace (->> session
   9006                              (lsp-session-folder->servers)
   9007                              (gethash project-root)
   9008                              (--first (eql (-> it lsp--workspace-client lsp--client-server-id)
   9009                                            (lsp--client-server-id client))))))
   9010     (lsp--open-in-workspace workspace)
   9011     workspace))
   9012 
   9013 (defun lsp--read-char (prompt &optional options)
   9014   "Wrapper for `read-char-from-minibuffer' if Emacs +27.
   9015 Fallback to `read-key' otherwise.
   9016 PROMPT is the message and OPTIONS the available options."
   9017   (if (fboundp 'read-char-from-minibuffer)
   9018       (read-char-from-minibuffer prompt options)
   9019     (read-key prompt)))
   9020 
   9021 (defun lsp--find-root-interactively (session)
   9022   "Find project interactively.
   9023 Returns nil if the project should not be added to the current SESSION."
   9024   (condition-case nil
   9025       (let* ((project-root-suggestion (or (lsp--suggest-project-root) default-directory))
   9026              (action (lsp--read-char
   9027                       (format
   9028                        "%s is not part of any project.
   9029 
   9030 %s ==> Import project root %s
   9031 %s ==> Import project by selecting root directory interactively
   9032 %s ==> Import project at current directory %s
   9033 %s ==> Do not ask again for the current project by adding %s to lsp-session-folders-blocklist
   9034 %s ==> Do not ask again for the current project by selecting ignore path interactively
   9035 %s ==> Do nothing: ask again when opening other files from the current project
   9036 
   9037 Select action: "
   9038                        (propertize (buffer-name) 'face 'bold)
   9039                        (propertize "i" 'face 'success)
   9040                        (propertize project-root-suggestion 'face 'bold)
   9041                        (propertize "I" 'face 'success)
   9042                        (propertize "." 'face 'success)
   9043                        (propertize default-directory 'face 'bold)
   9044                        (propertize "d" 'face 'warning)
   9045                        (propertize project-root-suggestion 'face 'bold)
   9046                        (propertize "D" 'face 'warning)
   9047                        (propertize "n" 'face 'warning))
   9048                       '(?i ?\r ?I ?. ?d ?D ?n))))
   9049         (cl-case action
   9050           (?i project-root-suggestion)
   9051           (?\r project-root-suggestion)
   9052           (?I (read-directory-name "Select workspace folder to add: "
   9053                                    (or project-root-suggestion default-directory)
   9054                                    nil
   9055                                    t))
   9056           (?. default-directory)
   9057           (?d (push project-root-suggestion (lsp-session-folders-blocklist session))
   9058               (lsp--persist-session session)
   9059               nil)
   9060           (?D (push (read-directory-name "Select folder to blocklist: "
   9061                                          (or project-root-suggestion default-directory)
   9062                                          nil
   9063                                          t)
   9064                     (lsp-session-folders-blocklist session))
   9065               (lsp--persist-session session)
   9066               nil)
   9067           (t nil)))
   9068     (quit)))
   9069 
   9070 (declare-function tramp-file-name-host "ext:tramp" (file) t)
   9071 (declare-function tramp-dissect-file-name "ext:tramp" (file &optional nodefault))
   9072 
   9073 (defun lsp--files-same-host (f1 f2)
   9074   "Predicate on whether or not two files are on the same host."
   9075   (or (not (or (file-remote-p f1) (file-remote-p f2)))
   9076       (and (file-remote-p f1)
   9077            (file-remote-p f2)
   9078            (progn (require 'tramp)
   9079                   (equal (tramp-file-name-host (tramp-dissect-file-name f1))
   9080                          (tramp-file-name-host (tramp-dissect-file-name f2)))))))
   9081 
   9082 (defun lsp-find-session-folder (session file-name)
   9083   "Look in the current SESSION for folder containing FILE-NAME."
   9084   (let ((file-name-canonical (lsp-f-canonical file-name)))
   9085     (->> session
   9086          (lsp-session-folders)
   9087          (--filter (and (lsp--files-same-host it file-name-canonical)
   9088                         (or (lsp-f-same? it file-name-canonical)
   9089                             (and (f-dir? it)
   9090                                  (lsp-f-ancestor-of? it file-name-canonical)))))
   9091          (--max-by (> (length it)
   9092                       (length other))))))
   9093 
   9094 (defun lsp-find-workspace (server-id &optional file-name)
   9095   "Find workspace for SERVER-ID for FILE-NAME."
   9096   (-when-let* ((session (lsp-session))
   9097                (folder->servers (lsp-session-folder->servers session))
   9098                (workspaces (if file-name
   9099                                (gethash (lsp-find-session-folder session file-name) folder->servers)
   9100                              (lsp--session-workspaces session))))
   9101 
   9102     (--first (eq (lsp--client-server-id (lsp--workspace-client it)) server-id) workspaces)))
   9103 
   9104 (defun lsp--calculate-root (session file-name)
   9105   "Calculate project root for FILE-NAME in SESSION."
   9106   (and
   9107    (->> session
   9108         (lsp-session-folders-blocklist)
   9109         (--first (and (lsp--files-same-host it file-name)
   9110                       (lsp-f-ancestor-of? it file-name)
   9111                       (prog1 t
   9112                         (lsp--info "File %s is in blocklisted directory %s" file-name it))))
   9113         not)
   9114    (or
   9115     (when lsp-auto-guess-root
   9116       (lsp--suggest-project-root))
   9117     (unless lsp-guess-root-without-session
   9118       (lsp-find-session-folder session file-name))
   9119     (unless lsp-auto-guess-root
   9120       (when-let ((root-folder (lsp--find-root-interactively session)))
   9121         (if (or (not (f-equal? root-folder (expand-file-name "~/")))
   9122                 (yes-or-no-p
   9123                  (concat
   9124                   (propertize "[WARNING] " 'face 'warning)
   9125                   "You are trying to import your home folder as project root. This may cause performance issue because some language servers (python, lua, etc) will try to scan all files under project root. To avoid that you may:
   9126 
   9127 1. Use `I' option from the interactive project import to select subfolder(e. g. `~/foo/bar' instead of `~/').
   9128 2. If your file is under `~/' then create a subfolder and move that file in this folder.
   9129 
   9130 Type `No' to go back to project selection.
   9131 Type `Yes' to confirm `HOME' as project root.
   9132 Type `C-g' to cancel project import process and stop `lsp'")))
   9133             root-folder
   9134           (lsp--calculate-root session file-name)))))))
   9135 
   9136 (defun lsp--try-open-in-library-workspace ()
   9137   "Try opening current file as library file in any of the active workspace.
   9138 The library folders are defined by each client for each of the active workspace."
   9139   (when-let ((workspace (->> (lsp-session)
   9140                              (lsp--session-workspaces)
   9141                              ;; Sort the last active workspaces first as they are more likely to be
   9142                              ;; the correct ones, especially when jumping to a definition.
   9143                              (-sort (lambda (a _b)
   9144                                       (-contains? lsp--last-active-workspaces a)))
   9145                              (--first
   9146                               (and (-> it lsp--workspace-client lsp--supports-buffer?)
   9147                                    (when-let ((library-folders-fn
   9148                                                (-> it lsp--workspace-client lsp--client-library-folders-fn)))
   9149                                      (-first (lambda (library-folder)
   9150                                                (lsp-f-ancestor-of? library-folder (buffer-file-name)))
   9151                                              (funcall library-folders-fn it))))))))
   9152     (lsp--open-in-workspace workspace)
   9153     (view-mode t)
   9154     (lsp--info "Opening read-only library file %s." (buffer-file-name))
   9155     (list workspace)))
   9156 
   9157 (defun lsp--persist-session (session)
   9158   "Persist SESSION to `lsp-session-file'."
   9159   (lsp--persist lsp-session-file (make-lsp-session
   9160                                   :folders (lsp-session-folders session)
   9161                                   :folders-blocklist (lsp-session-folders-blocklist session)
   9162                                   :server-id->folders (lsp-session-server-id->folders session))))
   9163 
   9164 (defun lsp--try-project-root-workspaces (ask-for-client ignore-multi-folder)
   9165   "Try create opening file as a project file.
   9166 When IGNORE-MULTI-FOLDER is t the lsp mode will start new
   9167 language server even if there is language server which can handle
   9168 current language. When IGNORE-MULTI-FOLDER is nil current file
   9169 will be opened in multi folder language server if there is
   9170 such."
   9171   (-let ((session (lsp-session)))
   9172     (-if-let (clients (if ask-for-client
   9173                           (list (lsp--completing-read "Select server to start: "
   9174                                                       (ht-values lsp-clients)
   9175                                                       (-compose 'symbol-name 'lsp--client-server-id) nil t))
   9176                         (lsp--find-clients)))
   9177         (-if-let (project-root (-some-> session
   9178                                  (lsp--calculate-root (buffer-file-name))
   9179                                  (lsp-f-canonical)))
   9180             (progn
   9181               ;; update project roots if needed and persist the lsp session
   9182               (unless (-contains? (lsp-session-folders session) project-root)
   9183                 (cl-pushnew project-root (lsp-session-folders session))
   9184                 (lsp--persist-session session))
   9185               (lsp--ensure-lsp-servers session clients project-root ignore-multi-folder))
   9186           (lsp--warn "%s not in project or it is blocklisted." (buffer-name))
   9187           nil)
   9188       (lsp--warn "No LSP server for %s(check *lsp-log*)." major-mode)
   9189       nil)))
   9190 
   9191 (defun lsp-shutdown-workspace ()
   9192   "Shutdown language server."
   9193   (interactive)
   9194   (--when-let (pcase (lsp-workspaces)
   9195                 (`nil (user-error "There are no active servers in the current buffer"))
   9196                 (`(,workspace) (when (y-or-n-p (format "Are you sure you want to stop the server %s?"
   9197                                                        (lsp--workspace-print workspace)))
   9198                                  workspace))
   9199                 (workspaces (lsp--completing-read "Select server: "
   9200                                                   workspaces
   9201                                                   'lsp--workspace-print nil t)))
   9202     (lsp-workspace-shutdown it)))
   9203 
   9204 (make-obsolete 'lsp-shutdown-workspace 'lsp-workspace-shutdown "lsp-mode 6.1")
   9205 
   9206 (defcustom lsp-auto-select-workspace t
   9207   "Shutdown or restart a single workspace.
   9208 If set and the current buffer has only a single workspace
   9209 associated with it, `lsp-shutdown-workspace' and
   9210 `lsp-restart-workspace' will act on it without asking."
   9211   :type 'boolean
   9212   :group 'lsp-mode)
   9213 
   9214 (defun lsp--read-workspace ()
   9215   "Ask the user to select a workspace.
   9216 Errors if there are none."
   9217   (pcase (lsp-workspaces)
   9218     (`nil (error "No workspaces associated with the current buffer"))
   9219     ((and `(,workspace) (guard lsp-auto-select-workspace)) workspace)
   9220     (workspaces (lsp--completing-read "Select workspace: " workspaces
   9221                                       #'lsp--workspace-print nil t))))
   9222 
   9223 (defun lsp-workspace-shutdown (workspace)
   9224   "Shut the workspace WORKSPACE and the language server associated with it"
   9225   (interactive (list (lsp--read-workspace)))
   9226   (lsp--warn "Stopping %s" (lsp--workspace-print workspace))
   9227   (with-lsp-workspace workspace (lsp--shutdown-workspace)))
   9228 
   9229 (defun lsp-disconnect ()
   9230   "Disconnect the buffer from the language server."
   9231   (interactive)
   9232   (lsp--text-document-did-close t)
   9233   (lsp-managed-mode -1)
   9234   (lsp-mode -1)
   9235   (setq lsp--buffer-workspaces nil)
   9236   (lsp--info "Disconnected"))
   9237 
   9238 (defun lsp-restart-workspace ()
   9239   (interactive)
   9240   (--when-let (pcase (lsp-workspaces)
   9241                 (`nil (user-error "There are no active servers in the current buffer"))
   9242                 (`(,workspace) workspace)
   9243                 (workspaces (lsp--completing-read "Select server: "
   9244                                                   workspaces
   9245                                                   'lsp--workspace-print nil t)))
   9246     (lsp-workspace-restart it)))
   9247 
   9248 (make-obsolete 'lsp-restart-workspace 'lsp-workspace-restart "lsp-mode 6.1")
   9249 
   9250 (defun lsp-workspace-restart (workspace)
   9251   "Restart the workspace WORKSPACE and the language server associated with it"
   9252   (interactive (list (lsp--read-workspace)))
   9253   (lsp--warn "Restarting %s" (lsp--workspace-print workspace))
   9254   (with-lsp-workspace workspace (lsp--shutdown-workspace t)))
   9255 
   9256 ;;;###autoload
   9257 (defun lsp (&optional arg)
   9258   "Entry point for the server startup.
   9259 When ARG is t the lsp mode will start new language server even if
   9260 there is language server which can handle current language. When
   9261 ARG is nil current file will be opened in multi folder language
   9262 server if there is such. When `lsp' is called with prefix
   9263 argument ask the user to select which language server to start."
   9264   (interactive "P")
   9265 
   9266   (lsp--require-packages)
   9267 
   9268   (when (buffer-file-name)
   9269     (let (clients
   9270           (matching-clients (lsp--filter-clients
   9271                              (-andfn #'lsp--supports-buffer?
   9272                                      #'lsp--server-binary-present?))))
   9273       (cond
   9274        (matching-clients
   9275         (when (setq lsp--buffer-workspaces
   9276                     (or (and
   9277                          ;; Don't open as library file if file is part of a project.
   9278                          (not (lsp-find-session-folder (lsp-session) (buffer-file-name)))
   9279                          (lsp--try-open-in-library-workspace))
   9280                         (lsp--try-project-root-workspaces (equal arg '(4))
   9281                                                           (and arg (not (equal arg 1))))))
   9282           (lsp-mode 1)
   9283           (when lsp-auto-configure (lsp--auto-configure))
   9284           (setq lsp-buffer-uri (lsp--buffer-uri))
   9285           (lsp--info "Connected to %s."
   9286                      (apply 'concat (--map (format "[%s %s]"
   9287                                                    (lsp--workspace-print it)
   9288                                                    (lsp--workspace-root it))
   9289                                            lsp--buffer-workspaces)))))
   9290        ;; look for servers which are currently being downloaded.
   9291        ((setq clients (lsp--filter-clients (-andfn #'lsp--supports-buffer?
   9292                                                    #'lsp--client-download-in-progress?)))
   9293         (lsp--info "There are language server(%s) installation in progress.
   9294 The server(s) will be started in the buffer when it has finished."
   9295                    (-map #'lsp--client-server-id clients))
   9296         (seq-do (lambda (client)
   9297                   (cl-pushnew (current-buffer) (lsp--client-buffers client)))
   9298                 clients))
   9299        ;; look for servers to install
   9300        ((setq clients (lsp--filter-clients
   9301                        (-andfn #'lsp--supports-buffer?
   9302                                (-const lsp-enable-suggest-server-download)
   9303                                #'lsp--client-download-server-fn
   9304                                (-not #'lsp--client-download-in-progress?))))
   9305         (let ((client (lsp--completing-read
   9306                        (concat "Unable to find installed server supporting this file. "
   9307                                "The following servers could be installed automatically: ")
   9308                        clients
   9309                        (-compose #'symbol-name #'lsp--client-server-id)
   9310                        nil
   9311                        t)))
   9312           (cl-pushnew (current-buffer) (lsp--client-buffers client))
   9313           (lsp--install-server-internal client)))
   9314        ;; ignore other warnings
   9315        ((not lsp-warn-no-matched-clients)
   9316         nil)
   9317        ;; automatic installation disabled
   9318        ((setq clients (unless matching-clients
   9319                         (lsp--filter-clients (-andfn #'lsp--supports-buffer?
   9320                                                      #'lsp--client-download-server-fn
   9321                                                      (-not (-const lsp-enable-suggest-server-download))
   9322                                                      (-not #'lsp--server-binary-present?)))))
   9323         (lsp--warn "The following servers support current file but automatic download is disabled: %s
   9324 \(If you have already installed the server check *lsp-log*)."
   9325                    (mapconcat (lambda (client)
   9326                                 (symbol-name (lsp--client-server-id client)))
   9327                               clients
   9328                               " ")))
   9329        ;; no clients present
   9330        ((setq clients (unless matching-clients
   9331                         (lsp--filter-clients (-andfn #'lsp--supports-buffer?
   9332                                                      (-not #'lsp--server-binary-present?)))))
   9333         (lsp--warn "The following servers support current file but do not have automatic installation: %s
   9334 You may find the installation instructions at https://emacs-lsp.github.io/lsp-mode/page/languages.
   9335 \(If you have already installed the server check *lsp-log*)."
   9336                    (mapconcat (lambda (client)
   9337                                 (symbol-name (lsp--client-server-id client)))
   9338                               clients
   9339                               " ")))
   9340        ;; no matches
   9341        ((-> #'lsp--supports-buffer? lsp--filter-clients not)
   9342         (lsp--error "There are no language servers supporting current mode `%s' registered with `lsp-mode'.
   9343 This issue might be caused by:
   9344 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'.
   9345 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'.
   9346 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/ .
   9347 4. You are over `tramp'. In this case follow https://emacs-lsp.github.io/lsp-mode/page/remote/.
   9348 5. You have disabled the `lsp-mode' clients for that file. (Check `lsp-enabled-clients' and `lsp-disabled-clients').
   9349 You can customize `lsp-warn-no-matched-clients' to disable this message."
   9350                     major-mode major-mode major-mode))))))
   9351 
   9352 (defun lsp--buffer-visible-p ()
   9353   "Return non nil if current buffer is visible."
   9354   (or (buffer-modified-p) (get-buffer-window nil t)))
   9355 
   9356 (defun lsp--init-if-visible ()
   9357   "Run `lsp' for the current buffer if the buffer is visible.
   9358 Returns non nil if `lsp' was run for the buffer."
   9359   (when (lsp--buffer-visible-p)
   9360     (remove-hook 'window-configuration-change-hook #'lsp--init-if-visible t)
   9361     (lsp)
   9362     t))
   9363 
   9364 ;;;###autoload
   9365 (defun lsp-deferred ()
   9366   "Entry point that defers server startup until buffer is visible.
   9367 `lsp-deferred' will wait until the buffer is visible before invoking `lsp'.
   9368 This avoids overloading the server with many files when starting Emacs."
   9369   ;; Workspace may not be initialized yet. Use a buffer local variable to
   9370   ;; remember that we deferred loading of this buffer.
   9371   (setq lsp--buffer-deferred t)
   9372   (let ((buffer (current-buffer)))
   9373     ;; Avoid false positives as desktop-mode restores buffers by deferring
   9374     ;; visibility check until the stack clears.
   9375     (run-with-idle-timer 0 nil (lambda ()
   9376                                  (when (buffer-live-p buffer)
   9377                                    (with-current-buffer buffer
   9378                                      (unless (lsp--init-if-visible)
   9379                                        (add-hook 'window-configuration-change-hook #'lsp--init-if-visible nil t))))))))
   9380 
   9381 
   9382 
   9383 (defvar lsp-file-truename-cache (ht))
   9384 
   9385 (defmacro lsp-with-cached-filetrue-name (&rest body)
   9386   "Executes BODY caching the `file-truename' calls."
   9387   `(let ((old-fn (symbol-function 'file-truename)))
   9388      (unwind-protect
   9389          (progn
   9390            (fset 'file-truename
   9391                  (lambda (file-name &optional counter prev-dirs)
   9392                    (or (gethash file-name lsp-file-truename-cache)
   9393                        (puthash file-name (apply old-fn (list file-name counter prev-dirs))
   9394                                 lsp-file-truename-cache))))
   9395            ,@body)
   9396        (fset 'file-truename old-fn))))
   9397 
   9398 
   9399 (defun lsp-virtual-buffer-call (key &rest args)
   9400   (when lsp--virtual-buffer
   9401     (when-let ((fn (plist-get lsp--virtual-buffer key)))
   9402       (apply fn args))))
   9403 
   9404 (defun lsp-translate-column (column)
   9405   "Translate COLUMN taking into account virtual buffers."
   9406   (or (lsp-virtual-buffer-call :real->virtual-char column)
   9407       column))
   9408 
   9409 (defun lsp-translate-line (line)
   9410   "Translate LINE taking into account virtual buffers."
   9411   (or (lsp-virtual-buffer-call :real->virtual-line line)
   9412       line))
   9413 
   9414 
   9415 ;; lsp internal validation.
   9416 
   9417 (defmacro lsp--doctor (&rest checks)
   9418   `(-let [buf (current-buffer)]
   9419      (with-current-buffer (get-buffer-create "*lsp-performance*")
   9420        (with-help-window (current-buffer)
   9421          ,@(-map (-lambda ((msg form))
   9422                    `(insert (format "%s: %s\n" ,msg
   9423                                     (let ((res (with-current-buffer buf
   9424                                                  ,form)))
   9425                                       (cond
   9426                                        ((eq res :optional) (propertize "OPTIONAL" 'face 'warning))
   9427                                        (res (propertize "OK" 'face 'success))
   9428                                        (t (propertize "ERROR" 'face 'error)))))))
   9429                  (-partition 2 checks))))))
   9430 
   9431 (define-obsolete-function-alias 'lsp-diagnose
   9432   'lsp-doctor "lsp-mode 8.0.0")
   9433 
   9434 (defun lsp-doctor ()
   9435   "Validate performance settings."
   9436   (interactive)
   9437   (lsp--doctor
   9438    "Checking for Native JSON support" (functionp 'json-serialize)
   9439    "Check emacs supports `read-process-output-max'" (boundp 'read-process-output-max)
   9440    "Check `read-process-output-max' default has been changed from 4k"
   9441    (and (boundp 'read-process-output-max)
   9442         (> read-process-output-max 4096))
   9443    "Byte compiled against Native JSON (recompile lsp-mode if failing when Native JSON available)"
   9444    (condition-case _err
   9445        (progn (lsp--make-message (list "a" "b"))
   9446               nil)
   9447      (error t))
   9448    "`gc-cons-threshold' increased?" (> gc-cons-threshold 800000)
   9449    "Using `plist' for deserialized objects? (refer to https://emacs-lsp.github.io/lsp-mode/page/performance/#use-plists-for-deserialization)" (or lsp-use-plists :optional)
   9450    "Using emacs 28+ with native compilation?"
   9451    (or (and (fboundp 'native-comp-available-p)
   9452             (native-comp-available-p))
   9453        :optional)))
   9454 
   9455 (declare-function package-version-join "ext:package")
   9456 (declare-function package-desc-version "ext:package")
   9457 (declare-function package--alist "ext:package")
   9458 
   9459 (defun lsp-version ()
   9460   "Return string describing current version of `lsp-mode'."
   9461   (interactive)
   9462   (unless (featurep 'package)
   9463     (require 'package))
   9464   (let ((ver (format "lsp-mode %s, Emacs %s, %s"
   9465                      (package-version-join
   9466                       (package-desc-version
   9467                        (car (alist-get 'lsp-mode (package--alist)))))
   9468                      emacs-version
   9469                      system-type)))
   9470     (if (called-interactively-p 'interactive)
   9471         (lsp--info "%s" ver)
   9472       ver)))
   9473 
   9474 
   9475 
   9476 ;; org-mode/virtual-buffer
   9477 
   9478 (declare-function org-babel-get-src-block-info "ext:ob-core")
   9479 (declare-function org-do-remove-indentation "ext:org-macs")
   9480 (declare-function org-src-get-lang-mode "ext:org-src")
   9481 (declare-function org-element-context "ext:org-element")
   9482 
   9483 (defun lsp--virtual-buffer-update-position ()
   9484   (-if-let (virtual-buffer (-first (-lambda ((&plist :in-range))
   9485                                      (funcall in-range))
   9486                                    lsp--virtual-buffer-connections))
   9487       (unless (equal virtual-buffer lsp--virtual-buffer)
   9488         (lsp-org))
   9489     (when lsp-managed-mode
   9490       (lsp-managed-mode -1)
   9491       (lsp-mode -1)
   9492       (setq lsp--buffer-workspaces nil)
   9493       (setq lsp--virtual-buffer nil)
   9494       (setq lsp-buffer-uri nil)
   9495 
   9496       ;; force refresh of diagnostics
   9497       (run-hooks 'lsp-after-diagnostics-hook))))
   9498 
   9499 (defun lsp-virtual-buffer-on-change (start end length)
   9500   "Adjust on change event to be executed against the proper language server."
   9501   (let ((max-point (max end
   9502                         (or (plist-get lsp--before-change-vals :end) 0)
   9503                         (+ start length))))
   9504     (when-let ((virtual-buffer (-first (lambda (vb)
   9505                                          (let ((lsp--virtual-buffer vb))
   9506                                            (and (lsp-virtual-buffer-call :in-range start)
   9507                                                 (lsp-virtual-buffer-call :in-range max-point))))
   9508                                        lsp--virtual-buffer-connections)))
   9509       (lsp-with-current-buffer virtual-buffer
   9510         (lsp-on-change start end length
   9511                        (lambda (&rest _)
   9512                          (list :range (lsp--range (list :character 0 :line 0)
   9513                                                   lsp--virtual-buffer-point-max)
   9514                                :text (lsp--buffer-content))))))))
   9515 
   9516 (defun lsp-virtual-buffer-before-change (start _end)
   9517   (when-let ((virtual-buffer (-first (lambda (vb)
   9518                                        (lsp-with-current-buffer vb
   9519                                          (lsp-virtual-buffer-call :in-range start)))
   9520                                      lsp--virtual-buffer-connections)))
   9521     (lsp-with-current-buffer virtual-buffer
   9522       (setq lsp--virtual-buffer-point-max
   9523             (lsp--point-to-position (lsp-virtual-buffer-call :last-point))))))
   9524 
   9525 (defun lsp-patch-on-change-event ()
   9526   (remove-hook 'after-change-functions #'lsp-on-change t)
   9527   (add-hook 'after-change-functions #'lsp-virtual-buffer-on-change nil t)
   9528   (add-hook 'before-change-functions #'lsp-virtual-buffer-before-change nil t))
   9529 
   9530 (defun lsp-kill-virtual-buffers ()
   9531   (mapc #'lsp-virtual-buffer-disconnect lsp--virtual-buffer-connections))
   9532 
   9533 (defun lsp--move-point-in-indentation (point indentation)
   9534   (save-excursion
   9535     (goto-char point)
   9536     (if (<= point (+ (line-beginning-position) indentation))
   9537         (line-beginning-position)
   9538       point)))
   9539 
   9540 (declare-function flycheck-checker-supports-major-mode-p "ext:flycheck")
   9541 (declare-function flycheck-add-mode "ext:flycheck")
   9542 (declare-function lsp-diagnostics-lsp-checker-if-needed "lsp-diagnostics")
   9543 
   9544 (defalias 'lsp-client-download-server-fn 'lsp--client-download-server-fn)
   9545 
   9546 (defun lsp-flycheck-add-mode (mode)
   9547   "Register flycheck support for MODE."
   9548   (lsp-diagnostics-lsp-checker-if-needed)
   9549   (unless (flycheck-checker-supports-major-mode-p 'lsp mode)
   9550     (flycheck-add-mode 'lsp mode)))
   9551 
   9552 (defun lsp-progress-spinner-type ()
   9553   "Retrieve the spinner type value, if value is not a symbol of `spinner-types
   9554 defaults to `progress-bar."
   9555   (or (car (assoc lsp-progress-spinner-type spinner-types)) 'progress-bar))
   9556 
   9557 (defun lsp-org ()
   9558   (interactive)
   9559   (-if-let ((virtual-buffer &as &plist :workspaces) (-first (-lambda ((&plist :in-range))
   9560                                                               (funcall in-range))
   9561                                                             lsp--virtual-buffer-connections))
   9562       (unless (equal lsp--virtual-buffer virtual-buffer)
   9563         (setq lsp--buffer-workspaces workspaces)
   9564         (setq lsp--virtual-buffer virtual-buffer)
   9565         (setq lsp-buffer-uri nil)
   9566         (lsp-mode 1)
   9567         (lsp-managed-mode 1)
   9568         (lsp-patch-on-change-event))
   9569 
   9570     (save-excursion
   9571       (-let* (virtual-buffer
   9572               (wcb (lambda (f)
   9573                      (with-current-buffer (plist-get virtual-buffer :buffer)
   9574                        (-let* (((&plist :major-mode :buffer-file-name
   9575                                         :goto-buffer :workspaces) virtual-buffer)
   9576                                (lsp--virtual-buffer virtual-buffer)
   9577                                (lsp--buffer-workspaces workspaces))
   9578                          (save-excursion
   9579                            (funcall goto-buffer)
   9580                            (funcall f))))))
   9581               ((&plist :begin :end :post-blank :language) (cl-second (org-element-context)))
   9582               ((&alist :tangle file-name) (cl-third (org-babel-get-src-block-info 'light)))
   9583 
   9584               (file-name (if file-name
   9585                              (f-expand file-name)
   9586                            (user-error "You should specify file name in the src block header.")))
   9587               (begin-marker (progn
   9588                               (goto-char begin)
   9589                               (forward-line)
   9590                               (set-marker (make-marker) (point))))
   9591               (end-marker (progn
   9592                             (goto-char end)
   9593                             (forward-line (1- (- post-blank)))
   9594                             (set-marker (make-marker) (1+ (point)))))
   9595               (buf (current-buffer))
   9596               (src-block (buffer-substring-no-properties begin-marker
   9597                                                          (1- end-marker)))
   9598               (indentation (with-temp-buffer
   9599                              (insert src-block)
   9600 
   9601                              (goto-char (point-min))
   9602                              (let ((indentation (current-indentation)))
   9603                                (plist-put lsp--virtual-buffer :indentation indentation)
   9604                                (org-do-remove-indentation)
   9605                                (goto-char (point-min))
   9606                                (- indentation (current-indentation))))))
   9607         (add-hook 'post-command-hook #'lsp--virtual-buffer-update-position nil t)
   9608 
   9609         (when (fboundp 'flycheck-add-mode)
   9610           (lsp-flycheck-add-mode 'org-mode))
   9611 
   9612         (setq lsp--virtual-buffer
   9613               (list
   9614                :in-range (lambda (&optional point)
   9615                            (<= begin-marker (or point (point)) (1- end-marker)))
   9616                :goto-buffer (lambda () (goto-char begin-marker))
   9617                :buffer-string
   9618                (lambda ()
   9619                  (let ((src-block (buffer-substring-no-properties
   9620                                    begin-marker
   9621                                    (1- end-marker))))
   9622                    (with-temp-buffer
   9623                      (insert src-block)
   9624 
   9625                      (goto-char (point-min))
   9626                      (while (not (eobp))
   9627                        (delete-region (point) (if (> (+ (point) indentation) (line-end-position))
   9628                                                   (line-end-position)
   9629                                                 (+ (point) indentation)))
   9630                        (forward-line))
   9631                      (buffer-substring-no-properties (point-min)
   9632                                                      (point-max)))))
   9633                :buffer buf
   9634                :begin begin-marker
   9635                :end end-marker
   9636                :indentation indentation
   9637                :last-point (lambda () (1- end-marker))
   9638                :cur-position (lambda ()
   9639                                (lsp-save-restriction-and-excursion
   9640                                  (list :line (- (lsp--cur-line)
   9641                                                 (lsp--cur-line begin-marker))
   9642                                        :character (let ((character (- (point)
   9643                                                                       (line-beginning-position)
   9644                                                                       indentation)))
   9645                                                     (if (< character 0)
   9646                                                         0
   9647                                                       character)))))
   9648                :line/character->point (-lambda (line character)
   9649                                         (-let [inhibit-field-text-motion t]
   9650                                           (+ indentation
   9651                                              (lsp-save-restriction-and-excursion
   9652                                                (goto-char begin-marker)
   9653                                                (forward-line line)
   9654                                                (-let [line-end (line-end-position)]
   9655                                                  (if (> character (- line-end (point)))
   9656                                                      line-end
   9657                                                    (forward-char character)
   9658                                                    (point)))))))
   9659                :major-mode (org-src-get-lang-mode language)
   9660                :buffer-file-name file-name
   9661                :buffer-uri (lsp--path-to-uri file-name)
   9662                :with-current-buffer wcb
   9663                :buffer-live? (lambda (_) (buffer-live-p buf))
   9664                :buffer-name (lambda (_)
   9665                               (propertize (format "%s(%s:%s)%s"
   9666                                                   (buffer-name buf)
   9667                                                   begin-marker
   9668                                                   end-marker
   9669                                                   language)
   9670                                           'face 'italic))
   9671                :real->virtual-line (lambda (line)
   9672                                      (+ line (line-number-at-pos begin-marker) -1))
   9673                :real->virtual-char (lambda (char) (+ char indentation))
   9674                :cleanup (lambda ()
   9675                           (set-marker begin-marker nil)
   9676                           (set-marker end-marker nil))))
   9677         (setf virtual-buffer lsp--virtual-buffer)
   9678         (puthash file-name virtual-buffer lsp--virtual-buffer-mappings)
   9679         (push virtual-buffer lsp--virtual-buffer-connections)
   9680 
   9681         ;; TODO: tangle only connected sections
   9682         (add-hook 'after-save-hook 'org-babel-tangle nil t)
   9683         (add-hook 'lsp-after-open-hook #'lsp-patch-on-change-event nil t)
   9684         (add-hook 'kill-buffer-hook #'lsp-kill-virtual-buffers nil t)
   9685 
   9686         (setq lsp--buffer-workspaces
   9687               (lsp-with-current-buffer virtual-buffer
   9688                 (lsp)
   9689                 (plist-put virtual-buffer :workspaces (lsp-workspaces))
   9690                 (lsp-workspaces)))))))
   9691 
   9692 (defun lsp-virtual-buffer-disconnect (virtual-buffer)
   9693   (interactive (list (or
   9694                       lsp--virtual-buffer
   9695                       (when lsp--virtual-buffer-connections
   9696                         (lsp--completing-read "Select virtual buffer to disconnect: "
   9697                                               lsp--virtual-buffer-connections
   9698                                               (-lambda ((&plist :buffer-file-name))
   9699                                                 buffer-file-name))))))
   9700   (-if-let ((&plist :buffer-file-name file-name :cleanup) virtual-buffer)
   9701       (progn
   9702         (lsp-with-current-buffer virtual-buffer
   9703           (lsp--text-document-did-close))
   9704         (setq lsp--virtual-buffer-connections (-remove-item virtual-buffer lsp--virtual-buffer-connections))
   9705         (when (eq virtual-buffer lsp--virtual-buffer)
   9706           (setf lsp--virtual-buffer nil))
   9707         (when cleanup (funcall cleanup))
   9708         (remhash file-name lsp--virtual-buffer-mappings)
   9709 
   9710         (lsp--virtual-buffer-update-position)
   9711         (lsp--info "Disconnected from buffer %s" file-name))
   9712     (lsp--error "Nothing to disconnect from?")))
   9713 
   9714 
   9715 ;; inlay hints
   9716 
   9717 (defface lsp-inlay-hint-face
   9718   '((t :inherit font-lock-comment-face))
   9719   "The face to use for the JavaScript inlays."
   9720   :group 'lsp-mode
   9721   :package-version '(lsp-mode . "9.0.0"))
   9722 
   9723 (defface lsp-inlay-hint-type-face
   9724   '((t :inherit lsp-inlay-hint-face))
   9725   "Face for inlay type hints (e.g. inferred variable types)."
   9726   :group 'lsp-mode
   9727   :package-version '(lsp-mode . "9.0.0"))
   9728 
   9729 (defcustom lsp-inlay-hint-type-format "%s"
   9730   "Format string for variable inlays (part of the inlay face)."
   9731   :type '(string :tag "String")
   9732   :group 'lsp-mode
   9733   :package-version '(lsp-mode . "9.0.0"))
   9734 
   9735 (defface lsp-inlay-hint-parameter-face
   9736   '((t :inherit lsp-inlay-hint-face))
   9737   "Face for inlay parameter hints (e.g. function parameter names at
   9738 call-site)."
   9739   :group 'lsp-mode
   9740   :package-version '(lsp-mode . "9.0.0"))
   9741 
   9742 (defcustom lsp-inlay-hint-param-format "%s"
   9743   "Format string for parameter inlays (part of the inlay face)."
   9744   :type '(string :tag "String")
   9745   :group 'lsp-mode
   9746   :package-version '(lsp-mode . "9.0.0"))
   9747 
   9748 (defcustom lsp-update-inlay-hints-on-scroll t
   9749   "If non-nil update inlay hints immediately when scrolling or
   9750 modifying window sizes."
   9751   :type 'boolean
   9752   :package-version '(lsp-mode . "9.0.0"))
   9753 
   9754 (defun lsp--format-inlay (text kind)
   9755   (cond
   9756    ((eql kind lsp/inlay-hint-kind-type-hint) (format lsp-inlay-hint-type-format text))
   9757    ((eql kind lsp/inlay-hint-kind-parameter-hint) (format lsp-inlay-hint-param-format text))
   9758    (t text)))
   9759 
   9760 (defun lsp--face-for-inlay (kind)
   9761   (cond
   9762    ((eql kind lsp/inlay-hint-kind-type-hint) 'lsp-inlay-hint-type-face)
   9763    ((eql kind lsp/inlay-hint-kind-parameter-hint) 'lsp-inlay-hint-parameter-face)
   9764    (t 'lsp-inlay-hint-face)))
   9765 
   9766 (defun lsp--update-inlay-hints-scroll-function (window start)
   9767   (lsp-update-inlay-hints start (window-end window t)))
   9768 
   9769 (defun lsp--update-inlay-hints ()
   9770   (lsp-update-inlay-hints (window-start) (window-end nil t)))
   9771 
   9772 (defun lsp--label-from-inlay-hints-response (label)
   9773   "Returns a string label built from an array of
   9774 InlayHintLabelParts or the argument itself if it's already a
   9775 string."
   9776   (cl-typecase label
   9777     (string label)
   9778     (vector
   9779      (string-join (mapcar (lambda (part)
   9780                             (-let (((&InlayHintLabelPart :value) part))
   9781                               value))
   9782                           label)))))
   9783 
   9784 (defun lsp-update-inlay-hints (start end)
   9785   (lsp-request-async
   9786    "textDocument/inlayHint"
   9787    (lsp-make-inlay-hints-params
   9788     :text-document (lsp--text-document-identifier)
   9789     :range (lsp-make-range :start
   9790                            (lsp-point-to-position start)
   9791                            :end
   9792                            (lsp-point-to-position end)))
   9793    (lambda (res)
   9794      (lsp--remove-overlays 'lsp-inlay-hint)
   9795      (dolist (hint res)
   9796        (-let* (((&InlayHint :label :position :kind? :padding-left? :padding-right?) hint)
   9797                (kind (or kind? lsp/inlay-hint-kind-type-hint))
   9798                (label (lsp--label-from-inlay-hints-response label))
   9799                (pos (lsp--position-to-point position))
   9800                (overlay (make-overlay pos pos nil 'front-advance 'end-advance)))
   9801          (when (stringp label)
   9802            (overlay-put overlay 'lsp-inlay-hint t)
   9803            (overlay-put overlay 'before-string
   9804                         (format "%s%s%s"
   9805                                 (if padding-left? " " "")
   9806                                 (propertize (lsp--format-inlay label kind)
   9807                                             'font-lock-face (lsp--face-for-inlay kind))
   9808                                 (if padding-right? " " "")))))))
   9809    :mode 'tick))
   9810 
   9811 (define-minor-mode lsp-inlay-hints-mode
   9812   "Mode for displaying inlay hints."
   9813   :lighter nil
   9814   (cond
   9815    ((and lsp-inlay-hints-mode lsp--buffer-workspaces)
   9816     (add-hook 'lsp-on-idle-hook #'lsp--update-inlay-hints nil t)
   9817     (when lsp-update-inlay-hints-on-scroll
   9818       (add-to-list (make-local-variable 'window-scroll-functions)
   9819                    #'lsp--update-inlay-hints-scroll-function)))
   9820    (t
   9821     (lsp--remove-overlays 'lsp-inlay-hint)
   9822     (remove-hook 'lsp-on-idle-hook #'lsp--update-inlay-hints t)
   9823     (setf window-scroll-functions
   9824           (delete #'lsp--update-inlay-hints-scroll-function window-scroll-functions)))))
   9825 
   9826 
   9827 
   9828 ;;;###autoload
   9829 (defun lsp-start-plain ()
   9830   "Start `lsp-mode' using minimal configuration using the latest `melpa' version
   9831 of the packages.
   9832 
   9833 In case the major-mode that you are using for "
   9834   (interactive)
   9835   (let ((start-plain (make-temp-file "plain" nil ".el")))
   9836     (url-copy-file "https://raw.githubusercontent.com/emacs-lsp/lsp-mode/master/scripts/lsp-start-plain.el"
   9837                    start-plain t)
   9838     (async-shell-command
   9839      (format "%s -q -l %s %s"
   9840              (expand-file-name invocation-name invocation-directory)
   9841              start-plain
   9842              (or (buffer-file-name) ""))
   9843      (generate-new-buffer " *lsp-start-plain*"))))
   9844 
   9845 
   9846 
   9847 (provide 'lsp-mode)
   9848 ;;; lsp-mode.el ends here