config

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

lsp-mode.el (430738B)


      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-roslyn 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     (feature-mode . "cucumber")
    906     (fortran-mode . "fortran")
    907     (f90-mode . "fortran")
    908     (elm-mode . "elm")
    909     (dart-mode . "dart")
    910     (erlang-mode . "erlang")
    911     (dockerfile-mode . "dockerfile")
    912     (dockerfile-ts-mode . "dockerfile")
    913     (csharp-mode . "csharp")
    914     (csharp-tree-sitter-mode . "csharp")
    915     (csharp-ts-mode . "csharp")
    916     (plain-tex-mode . "plaintex")
    917     (context-mode . "context")
    918     (cypher-mode . "cypher")
    919     (latex-mode . "latex")
    920     (LaTeX-mode . "latex")
    921     (v-mode . "v")
    922     (vhdl-mode . "vhdl")
    923     (vhdl-ts-mode . "vhdl")
    924     (verilog-mode . "verilog")
    925     (terraform-mode . "terraform")
    926     (ess-julia-mode . "julia")
    927     (ess-r-mode . "r")
    928     (crystal-mode . "crystal")
    929     (nim-mode . "nim")
    930     (dhall-mode . "dhall")
    931     (cmake-mode . "cmake")
    932     (cmake-ts-mode . "cmake")
    933     (purescript-mode . "purescript")
    934     (gdscript-mode . "gdscript")
    935     (gdscript-ts-mode . "gdscript")
    936     (perl-mode . "perl")
    937     (cperl-mode . "perl")
    938     (robot-mode . "robot")
    939     (racket-mode . "racket")
    940     (nix-mode . "nix")
    941     (nix-ts-mode . "Nix")
    942     (prolog-mode . "prolog")
    943     (vala-mode . "vala")
    944     (actionscript-mode . "actionscript")
    945     (d-mode . "d")
    946     (zig-mode . "zig")
    947     (text-mode . "plaintext")
    948     (markdown-mode . "markdown")
    949     (gfm-mode . "markdown")
    950     (beancount-mode . "beancount")
    951     (conf-toml-mode . "toml")
    952     (toml-ts-mode . "toml")
    953     (org-mode . "org")
    954     (org-journal-mode . "org")
    955     (nginx-mode . "nginx")
    956     (magik-mode . "magik")
    957     (magik-ts-mode . "magik")
    958     (idris-mode . "idris")
    959     (idris2-mode . "idris2")
    960     (gleam-mode . "gleam")
    961     (gleam-ts-mode . "gleam")
    962     (graphviz-dot-mode . "dot")
    963     (tiltfile-mode . "tiltfile")
    964     (solidity-mode . "solidity")
    965     (bibtex-mode . "bibtex")
    966     (rst-mode . "restructuredtext")
    967     (glsl-mode . "glsl")
    968     (shader-mode . "shaderlab")
    969     (wgsl-mode . "wgsl")
    970     (jq-mode . "jq")
    971     (jq-ts-mode . "jq")
    972     (protobuf-mode . "protobuf")
    973     (nushell-mode . "nushell")
    974     (nushell-ts-mode . "nushell")
    975     (meson-mode . "meson")
    976     (yang-mode . "yang"))
    977   "Language id configuration.")
    978 
    979 (defvar lsp--last-active-workspaces nil
    980   "Keep track of last active workspace.
    981 We want to try the last workspace first when jumping into a library
    982 directory")
    983 
    984 (defvar lsp-method-requirements
    985   '(("textDocument/callHierarchy" :capability :callHierarchyProvider)
    986     ("textDocument/codeAction" :capability :codeActionProvider)
    987     ("codeAction/resolve"
    988      :check-command (lambda (workspace)
    989                       (with-lsp-workspace workspace
    990                         (lsp:code-action-options-resolve-provider?
    991                          (lsp--capability-for-method "textDocument/codeAction")))))
    992     ("textDocument/codeLens" :capability :codeLensProvider)
    993     ("textDocument/completion" :capability :completionProvider)
    994     ("completionItem/resolve"
    995      :check-command (lambda (wk)
    996                       (with-lsp-workspace wk
    997                         (lsp:completion-options-resolve-provider?
    998                          (lsp--capability-for-method "textDocument/completion")))))
    999     ("textDocument/declaration" :capability :declarationProvider)
   1000     ("textDocument/definition" :capability :definitionProvider)
   1001     ("textDocument/documentColor" :capability :colorProvider)
   1002     ("textDocument/documentLink" :capability :documentLinkProvider)
   1003     ("textDocument/inlayHint" :capability :inlayHintProvider)
   1004     ("textDocument/documentHighlight" :capability :documentHighlightProvider)
   1005     ("textDocument/documentSymbol" :capability :documentSymbolProvider)
   1006     ("textDocument/foldingRange" :capability :foldingRangeProvider)
   1007     ("textDocument/formatting" :capability :documentFormattingProvider)
   1008     ("textDocument/hover" :capability :hoverProvider)
   1009     ("textDocument/implementation" :capability :implementationProvider)
   1010     ("textDocument/linkedEditingRange" :capability :linkedEditingRangeProvider)
   1011     ("textDocument/onTypeFormatting" :capability :documentOnTypeFormattingProvider)
   1012     ("textDocument/prepareRename"
   1013      :check-command (lambda (workspace)
   1014                       (with-lsp-workspace workspace
   1015                         (lsp:rename-options-prepare-provider?
   1016                          (lsp--capability-for-method "textDocument/rename")))))
   1017     ("textDocument/rangeFormatting" :capability :documentRangeFormattingProvider)
   1018     ("textDocument/references" :capability :referencesProvider)
   1019     ("textDocument/rename" :capability :renameProvider)
   1020     ("textDocument/selectionRange" :capability :selectionRangeProvider)
   1021     ("textDocument/semanticTokens" :capability :semanticTokensProvider)
   1022     ("textDocument/semanticTokensFull"
   1023      :check-command (lambda (workspace)
   1024                       (with-lsp-workspace workspace
   1025                         (lsp-get (lsp--capability :semanticTokensProvider) :full))))
   1026     ("textDocument/semanticTokensFull/Delta"
   1027      :check-command (lambda (workspace)
   1028                       (with-lsp-workspace workspace
   1029                         (let ((capFull (lsp-get (lsp--capability :semanticTokensProvider) :full)))
   1030                           (and (not (booleanp capFull)) (lsp-get capFull :delta))))))
   1031     ("textDocument/semanticTokensRangeProvider"
   1032      :check-command (lambda (workspace)
   1033                       (with-lsp-workspace workspace
   1034                         (lsp-get (lsp--capability :semanticTokensProvider) :range))))
   1035     ("textDocument/signatureHelp" :capability :signatureHelpProvider)
   1036     ("textDocument/typeDefinition" :capability :typeDefinitionProvider)
   1037     ("textDocument/typeHierarchy" :capability :typeHierarchyProvider)
   1038     ("workspace/executeCommand" :capability :executeCommandProvider)
   1039     ("workspace/symbol" :capability :workspaceSymbolProvider))
   1040 
   1041   "Map methods to requirements.
   1042 It is used by request-sending functions to determine which server
   1043 must be used for handling a particular message.")
   1044 
   1045 (defconst lsp--file-change-type
   1046   `((created . 1)
   1047     (changed . 2)
   1048     (deleted . 3)))
   1049 
   1050 (defconst lsp--watch-kind
   1051   `((create . 1)
   1052     (change . 2)
   1053     (delete . 4)))
   1054 
   1055 (defvar lsp-window-body-width 40
   1056   "Window body width when rendering doc.")
   1057 
   1058 (defface lsp-face-highlight-textual
   1059   '((t :inherit highlight))
   1060   "Face used for textual occurrences of symbols."
   1061   :group 'lsp-mode)
   1062 
   1063 (defface lsp-face-highlight-read
   1064   '((t :inherit highlight :underline t))
   1065   "Face used for highlighting symbols being read."
   1066   :group 'lsp-mode)
   1067 
   1068 (defface lsp-face-highlight-write
   1069   '((t :inherit highlight :weight bold))
   1070   "Face used for highlighting symbols being written to."
   1071   :group 'lsp-mode)
   1072 
   1073 (define-obsolete-variable-alias 'lsp-lens-auto-enable
   1074   'lsp-lens-enable "lsp-mode 7.0.1")
   1075 
   1076 (defcustom lsp-lens-enable t
   1077   "Auto enable lenses if server supports."
   1078   :group 'lsp-lens
   1079   :type 'boolean
   1080   :package-version '(lsp-mode . "6.3"))
   1081 
   1082 (defcustom lsp-symbol-highlighting-skip-current nil
   1083   "If non-nil skip current symbol when setting symbol highlights."
   1084   :group 'lsp-mode
   1085   :type 'boolean)
   1086 
   1087 (defcustom lsp-file-watch-threshold 1000
   1088   "Show warning if the files to watch are more than.
   1089 Set to nil to disable the warning."
   1090   :type 'number
   1091   :group 'lsp-mode)
   1092 ;;;###autoload(put 'lsp-file-watch-threshold 'safe-local-variable (lambda (i) (or (numberp i) (not i))))
   1093 
   1094 (defvar lsp-custom-markup-modes
   1095   '((rust-mode "no_run" "rust,no_run" "rust,ignore" "rust,should_panic"))
   1096   "Mode to uses with markdown code blocks.
   1097 They are added to `markdown-code-lang-modes'")
   1098 
   1099 (defcustom lsp-signature-render-documentation t
   1100   "Display signature documentation in `eldoc'."
   1101   :type 'boolean
   1102   :group 'lsp-mode
   1103   :package-version '(lsp-mode . "6.2"))
   1104 
   1105 (defcustom lsp-signature-auto-activate '(:on-trigger-char :on-server-request)
   1106   "Auto activate signature conditions."
   1107   :type '(repeat (choice (const :tag "On trigger chars pressed." :on-trigger-char)
   1108                          (const :tag "After selected completion." :after-completion)
   1109                          (const :tag "When the server has sent show signature help." :on-server-request)))
   1110   :group 'lsp-mode
   1111   :package-version '(lsp-mode . "6.2"))
   1112 
   1113 (defcustom lsp-signature-doc-lines 20
   1114   "If number, limit the number of lines to show in the docs."
   1115   :type 'number
   1116   :group 'lsp-mode
   1117   :package-version '(lsp-mode . "6.3"))
   1118 
   1119 (defcustom lsp-signature-function 'lsp-lv-message
   1120   "The function used for displaying signature info.
   1121 It will be called with one param - the signature info. When
   1122 called with nil the signature info must be cleared."
   1123   :type 'function
   1124   :group 'lsp-mode
   1125   :package-version '(lsp-mode . "6.3"))
   1126 
   1127 (defcustom lsp-keymap-prefix "s-l"
   1128   "LSP-mode keymap prefix."
   1129   :group 'lsp-mode
   1130   :type 'string
   1131   :package-version '(lsp-mode . "6.3"))
   1132 
   1133 (defvar-local lsp--buffer-workspaces ()
   1134   "List of the buffer workspaces.")
   1135 
   1136 (defvar-local lsp--buffer-deferred nil
   1137   "Whether buffer was loaded via `lsp-deferred'.")
   1138 
   1139 (defvar lsp--session nil
   1140   "Contain the `lsp-session' for the current Emacs instance.")
   1141 
   1142 (defvar lsp--tcp-port 10000)
   1143 
   1144 (defvar lsp--client-packages-required nil
   1145   "If nil, `lsp-client-packages' are yet to be required.")
   1146 
   1147 (defvar lsp--tcp-server-port 0
   1148   "The server socket which is opened when using `lsp-tcp-server' (a server
   1149 socket is opened in Emacs and the language server connects to it).  The
   1150 default value of 0 ensures that a random high port is used. Set it to a positive
   1151 integer to use a specific port.")
   1152 
   1153 (defvar lsp--tcp-server-wait-seconds 10
   1154   "Wait this amount of time for the client to connect to our server socket
   1155 when using `lsp-tcp-server'.")
   1156 
   1157 (defvar-local lsp--document-symbols nil
   1158   "The latest document symbols.")
   1159 
   1160 (defvar-local lsp--document-selection-range-cache nil
   1161   "The document selection cache.")
   1162 
   1163 (defvar-local lsp--document-symbols-request-async nil
   1164   "If non-nil, request document symbols asynchronously.")
   1165 
   1166 (defvar-local lsp--document-symbols-tick -1
   1167   "The value of `buffer-chars-modified-tick' when document
   1168   symbols were last retrieved.")
   1169 
   1170 (defvar-local lsp--have-document-highlights nil
   1171   "Set to `t' on symbol highlighting, cleared on
   1172 `lsp--cleanup-highlights-if-needed'. Checking a separately
   1173 defined flag is substantially faster than unconditionally
   1174 calling `remove-overlays'.")
   1175 
   1176 ;; Buffer local variable for storing number of lines.
   1177 (defvar lsp--log-lines)
   1178 
   1179 (defvar-local lsp--eldoc-saved-message nil)
   1180 
   1181 (defvar lsp--on-change-timer nil)
   1182 (defvar lsp--on-idle-timer nil)
   1183 
   1184 (defvar-local lsp--signature-last nil)
   1185 (defvar-local lsp--signature-last-index nil)
   1186 (defvar lsp--signature-last-buffer nil)
   1187 
   1188 (defvar-local lsp--virtual-buffer-point-max nil)
   1189 
   1190 (cl-defmethod lsp-execute-command (_server _command _arguments)
   1191   "Ask SERVER to execute COMMAND with ARGUMENTS.")
   1192 
   1193 (defun lsp-elt (sequence n)
   1194   "Return Nth element of SEQUENCE or nil if N is out of range."
   1195   (cond
   1196    ((listp sequence) (elt sequence n))
   1197    ((arrayp sequence)
   1198     (and (> (length sequence) n) (aref sequence n)))
   1199    (t (and (> (length sequence) n) (elt sequence n)))))
   1200 
   1201 ;; define seq-first and seq-rest for older emacs
   1202 (defun lsp-seq-first (sequence)
   1203   "Return the first element of SEQUENCE."
   1204   (lsp-elt sequence 0))
   1205 
   1206 (defun lsp-seq-rest (sequence)
   1207   "Return a sequence of the elements of SEQUENCE except the first one."
   1208   (seq-drop sequence 1))
   1209 
   1210 ;;;###autoload
   1211 (defun lsp--string-listp (sequence)
   1212   "Return t if all elements of SEQUENCE are strings, else nil."
   1213   (not (seq-find (lambda (x) (not (stringp x))) sequence)))
   1214 
   1215 (defun lsp--string-vector-p (candidate)
   1216   "Returns true if CANDIDATE is a vector data structure and
   1217 every element of it is of type string, else nil."
   1218   (and
   1219    (vectorp candidate)
   1220    (seq-every-p #'stringp candidate)))
   1221 
   1222 (make-obsolete 'lsp--string-vector-p nil "lsp-mode 8.0.0")
   1223 
   1224 (defun lsp--editable-vector-match (widget value)
   1225   "Function for `lsp-editable-vector' :match."
   1226   ;; Value must be a list or a vector and all the members must match the type.
   1227   (and (or (listp value) (vectorp value))
   1228        (length (cdr (lsp--editable-vector-match-inline widget value)))))
   1229 
   1230 (defun lsp--editable-vector-match-inline (widget value)
   1231   "Value for `lsp-editable-vector' :match-inline."
   1232   (let ((type (nth 0 (widget-get widget :args)))
   1233         (ok t)
   1234         found)
   1235     (while (and value ok)
   1236       (let ((answer (widget-match-inline type value)))
   1237         (if answer
   1238             (let ((head (if (vectorp answer) (aref answer 0) (car answer)))
   1239                   (tail (if (vectorp answer) (seq-drop 1 answer) (cdr answer))))
   1240               (setq found (append found head)
   1241                     value tail))
   1242           (setq ok nil))))
   1243     (cons found value)))
   1244 
   1245 (defun lsp--editable-vector-value-to-external (_widget internal-value)
   1246   "Convert the internal list value to a vector."
   1247   (if (listp internal-value)
   1248       (apply 'vector internal-value)
   1249     internal-value))
   1250 
   1251 (defun lsp--editable-vector-value-to-internal (_widget external-value)
   1252   "Convert the external vector value to a list."
   1253   (if (vectorp external-value)
   1254       (append external-value nil)
   1255     external-value))
   1256 
   1257 (define-widget 'lsp--editable-vector 'editable-list
   1258   "A subclass of `editable-list' that accepts and returns a
   1259 vector instead of a list."
   1260   :value-to-external 'lsp--editable-vector-value-to-external
   1261   :value-to-internal 'lsp--editable-vector-value-to-internal
   1262   :match 'lsp--editable-vector-match
   1263   :match-inline 'lsp--editable-vector-match-inline)
   1264 
   1265 (define-widget 'lsp-repeatable-vector 'lsp--editable-vector
   1266   "A variable length homogeneous vector."
   1267   :tag "Repeat"
   1268   :format "%{%t%}:\n%v%i\n")
   1269 
   1270 (define-widget 'lsp-string-vector 'lazy
   1271   "A vector of zero or more elements, every element of which is a string.
   1272 Appropriate for any language-specific `defcustom' that needs to
   1273 serialize as a JSON array of strings.
   1274 
   1275 Deprecated. Use `lsp-repeatable-vector' instead. "
   1276   :offset 4
   1277   :tag "Vector"
   1278   :type '(lsp-repeatable-vector string))
   1279 
   1280 (make-obsolete 'lsp-string-vector nil "lsp-mode 8.0.0")
   1281 
   1282 (defvar lsp--show-message t
   1283   "If non-nil, show debug message from `lsp-mode'.")
   1284 
   1285 (defun lsp--message  (format &rest args)
   1286   "Wrapper for `message'
   1287 
   1288 We `inhibit-message' the message when the cursor is in the
   1289 minibuffer and when emacs version is before emacs 27 due to the
   1290 fact that we often use `lsp--info', `lsp--warn' and `lsp--error'
   1291 in async context and the call to these function is removing the
   1292 minibuffer prompt. The issue with async messages is already fixed
   1293 in emacs 27.
   1294 
   1295 See #2049"
   1296   (when lsp--show-message
   1297     (let ((inhibit-message (or inhibit-message
   1298                                (and (minibufferp)
   1299                                     (version< emacs-version "27.0")))))
   1300       (apply #'message format args))))
   1301 
   1302 (defun lsp--info (format &rest args)
   1303   "Display lsp info message with FORMAT with ARGS."
   1304   (lsp--message "%s :: %s" (propertize "LSP" 'face 'success) (apply #'format format args)))
   1305 
   1306 (defun lsp--warn (format &rest args)
   1307   "Display lsp warn message with FORMAT with ARGS."
   1308   (lsp--message "%s :: %s" (propertize "LSP" 'face 'warning) (apply #'format format args)))
   1309 
   1310 (defun lsp--error (format &rest args)
   1311   "Display lsp error message with FORMAT with ARGS."
   1312   (lsp--message "%s :: %s" (propertize "LSP" 'face 'error) (apply #'format format args)))
   1313 
   1314 (defun lsp-log (format &rest args)
   1315   "Log message to the ’*lsp-log*’ buffer.
   1316 
   1317 FORMAT and ARGS i the same as for `message'."
   1318   (when lsp-log-max
   1319     (let ((log-buffer (get-buffer "*lsp-log*"))
   1320           (inhibit-read-only t))
   1321       (unless log-buffer
   1322         (setq log-buffer (get-buffer-create "*lsp-log*"))
   1323         (with-current-buffer log-buffer
   1324           (buffer-disable-undo)
   1325           (view-mode 1)
   1326           (set (make-local-variable 'lsp--log-lines) 0)))
   1327       (with-current-buffer log-buffer
   1328         (save-excursion
   1329           (let* ((message (apply 'format format args))
   1330                  ;; Count newlines in message.
   1331                  (newlines (1+ (cl-loop with start = 0
   1332                                         for count from 0
   1333                                         while (string-match "\n" message start)
   1334                                         do (setq start (match-end 0))
   1335                                         finally return count))))
   1336             (goto-char (point-max))
   1337 
   1338             ;; in case the buffer is not empty insert before last \n to preserve
   1339             ;; the point position(in case it is in the end)
   1340             (if (eq (point) (point-min))
   1341                 (progn
   1342                   (insert "\n")
   1343                   (backward-char))
   1344               (backward-char)
   1345               (insert "\n"))
   1346             (insert message)
   1347 
   1348             (setq lsp--log-lines (+ lsp--log-lines newlines))
   1349 
   1350             (when (and (integerp lsp-log-max) (> lsp--log-lines lsp-log-max))
   1351               (let ((to-delete (- lsp--log-lines lsp-log-max)))
   1352                 (goto-char (point-min))
   1353                 (forward-line to-delete)
   1354                 (delete-region (point-min) (point))
   1355                 (setq lsp--log-lines lsp-log-max)))))))))
   1356 
   1357 (defalias 'lsp-message 'lsp-log)
   1358 
   1359 (defalias 'lsp-ht 'ht)
   1360 
   1361 (defalias 'lsp-file-local-name 'file-local-name)
   1362 
   1363 (defun lsp-f-canonical (file-name)
   1364   "Return the canonical FILE-NAME, without a trailing slash."
   1365   (directory-file-name (expand-file-name file-name)))
   1366 
   1367 (defalias 'lsp-canonical-file-name 'lsp-f-canonical)
   1368 
   1369 (defun lsp-f-same? (path-a path-b)
   1370   "Return t if PATH-A and PATH-B are references to the same file.
   1371 Symlinks are not followed."
   1372   (when (and (f-exists? path-a)
   1373              (f-exists? path-b))
   1374     (equal
   1375      (lsp-f-canonical (directory-file-name (f-expand path-a)))
   1376      (lsp-f-canonical (directory-file-name (f-expand path-b))))))
   1377 
   1378 (defun lsp-f-parent (path)
   1379   "Return the parent directory to PATH.
   1380 Symlinks are not followed."
   1381   (let ((parent (file-name-directory
   1382                  (directory-file-name (f-expand path default-directory)))))
   1383     (unless (lsp-f-same? path parent)
   1384       (if (f-relative? path)
   1385           (f-relative parent)
   1386         (directory-file-name parent)))))
   1387 
   1388 (defun lsp-f-ancestor-of? (path-a path-b)
   1389   "Return t if PATH-A is an ancestor of PATH-B.
   1390 Symlinks are not followed."
   1391   (unless (lsp-f-same? path-a path-b)
   1392     (s-prefix? (concat (lsp-f-canonical path-a) (f-path-separator))
   1393                (lsp-f-canonical path-b))))
   1394 
   1395 (defun lsp--merge-results (results method)
   1396   "Merge RESULTS by filtering the empty hash-tables and merging
   1397 the lists according to METHOD."
   1398   (pcase (--map (if (vectorp it)
   1399                     (append it nil) it)
   1400                 (-filter #'identity results))
   1401     (`() ())
   1402     ;; only one result - simply return it
   1403     (`(,fst) fst)
   1404     ;; multiple results merge it based on strategy
   1405     (results
   1406      (pcase method
   1407        ("textDocument/hover" (pcase (seq-filter
   1408                                      (-compose #'not #'lsp-empty?)
   1409                                      results)
   1410                                (`(,hover) hover)
   1411                                (hovers (lsp-make-hover
   1412                                         :contents
   1413                                         (-mapcat
   1414                                          (-lambda ((&Hover :contents))
   1415                                            (if (and (sequencep contents)
   1416                                                     (not (stringp contents)))
   1417                                                (append contents ())
   1418                                              (list contents)))
   1419                                          hovers)))))
   1420        ("textDocument/completion"
   1421         (lsp-make-completion-list
   1422          :is-incomplete (seq-some
   1423                          #'lsp:completion-list-is-incomplete
   1424                          results)
   1425          :items (cl-mapcan (lambda (it) (append (if (lsp-completion-list? it)
   1426                                                     (lsp:completion-list-items it)
   1427                                                   it)
   1428                                                 nil))
   1429                            results)))
   1430        ("completionItem/resolve"
   1431         (let ((item (cl-first results)))
   1432           (when-let ((details (seq-filter #'identity
   1433                                           (seq-map #'lsp:completion-item-detail? results))))
   1434             (lsp:set-completion-item-detail?
   1435              item
   1436              (string-join details " ")))
   1437           (when-let ((docs (seq-filter #'identity
   1438                                        (seq-map #'lsp:completion-item-documentation? results))))
   1439             (lsp:set-completion-item-documentation?
   1440              item
   1441              (lsp-make-markup-content
   1442               :kind (or (seq-some (lambda (it)
   1443                                     (when (equal (lsp:markup-content-kind it)
   1444                                                  lsp/markup-kind-markdown)
   1445                                       lsp/markup-kind-markdown))
   1446                                   docs)
   1447                         lsp/markup-kind-plain-text)
   1448               :value (string-join (seq-map (lambda (doc)
   1449                                              (or (lsp:markup-content-value doc)
   1450                                                  (and (stringp doc) doc)))
   1451                                            docs)
   1452                                   "\n"))))
   1453           (when-let ((edits (seq-filter #'identity
   1454                                         (seq-map #'lsp:completion-item-additional-text-edits? results))))
   1455             (lsp:set-completion-item-additional-text-edits?
   1456              item
   1457              (cl-mapcan (lambda (it) (if (seqp it) it (list it))) edits)))
   1458           item))
   1459        (_ (cl-mapcan (lambda (it) (if (seqp it) it (list it))) results))))))
   1460 
   1461 (defun lsp--spinner-start ()
   1462   "Start spinner indication."
   1463   (condition-case _err (spinner-start (lsp-progress-spinner-type)) (error)))
   1464 
   1465 (defun lsp--propertize (str type)
   1466   "Propertize STR as per TYPE."
   1467   (propertize str 'face (alist-get type lsp--message-type-face)))
   1468 
   1469 (defun lsp-workspaces ()
   1470   "Return the lsp workspaces associated with the current project."
   1471   (if lsp--cur-workspace (list lsp--cur-workspace) lsp--buffer-workspaces))
   1472 
   1473 (defun lsp--completing-read (prompt collection transform-fn &optional predicate
   1474                                     require-match initial-input
   1475                                     hist def inherit-input-method)
   1476   "Wrap `completing-read' to provide transformation function and disable sort.
   1477 
   1478 TRANSFORM-FN will be used to transform each of the items before displaying.
   1479 
   1480 PROMPT COLLECTION PREDICATE REQUIRE-MATCH INITIAL-INPUT HIST DEF
   1481 INHERIT-INPUT-METHOD will be proxied to `completing-read' without changes."
   1482   (let* ((col (--map (cons (funcall transform-fn it) it) collection))
   1483          (completion (completing-read prompt
   1484                                       (lambda (string pred action)
   1485                                         (if (eq action 'metadata)
   1486                                             `(metadata (display-sort-function . identity))
   1487                                           (complete-with-action action col string pred)))
   1488                                       predicate require-match initial-input hist
   1489                                       def inherit-input-method)))
   1490     (cdr (assoc completion col))))
   1491 
   1492 (defconst lsp--system-arch (lambda ()
   1493                              (setq lsp--system-arch
   1494                                    (pcase system-type
   1495                                      ('windows-nt
   1496                                       (pcase system-configuration
   1497                                         ((rx bol "x86_64-") 'x64)
   1498                                         (_ 'x86)))
   1499                                      ('darwin
   1500                                       (pcase system-configuration
   1501                                         ((rx "aarch64-") 'arm64)
   1502                                         (_ 'x64)))
   1503                                      ('gnu/linux
   1504                                        (pcase system-configuration
   1505                                          ((rx bol "x86_64") 'x64)
   1506                                          ((rx bol (| "i386" "i886")) 'x32)))
   1507                                      (_
   1508                                       (pcase system-configuration
   1509                                         ((rx bol "x86_64") 'x64)
   1510                                         ((rx bol (| "i386" "i886")) 'x32))))))
   1511   "Return the system architecture of `Emacs'.
   1512 Special values:
   1513   `x64'       64bit
   1514   `x32'       32bit
   1515   `arm64'     ARM 64bit")
   1516 
   1517 (defmacro lsp-with-current-buffer (buffer-id &rest body)
   1518   (declare (indent 1) (debug t))
   1519   `(if-let ((wcb (plist-get ,buffer-id :with-current-buffer)))
   1520        (with-lsp-workspaces (plist-get ,buffer-id :workspaces)
   1521          (funcall wcb (lambda () ,@body)))
   1522      (with-current-buffer ,buffer-id
   1523        ,@body)))
   1524 
   1525 (defvar lsp--throw-on-input nil
   1526   "Make `lsp-*-while-no-input' throws `input' on interrupted.")
   1527 
   1528 (defmacro lsp--catch (tag bodyform &rest handlers)
   1529   "Catch TAG thrown in BODYFORM.
   1530 The return value from TAG will be handled in HANDLERS by `pcase'."
   1531   (declare (debug (form form &rest (pcase-PAT body))) (indent 2))
   1532   (let ((re-sym (make-symbol "re")))
   1533     `(let ((,re-sym (catch ,tag ,bodyform)))
   1534        (pcase ,re-sym
   1535          ,@handlers))))
   1536 
   1537 (defmacro lsp--while-no-input (&rest body)
   1538   "Wrap BODY in `while-no-input' and respecting `non-essential'.
   1539 If `lsp--throw-on-input' is set, will throw if input is pending, else
   1540 return value of `body' or nil if interrupted."
   1541   (declare (debug t) (indent 0))
   1542   `(if non-essential
   1543        (let ((res (while-no-input ,@body)))
   1544          (cond
   1545           ((and lsp--throw-on-input (equal res t))
   1546            (throw 'input :interrupted))
   1547           ((booleanp res) nil)
   1548           (t res)))
   1549      ,@body))
   1550 
   1551 ;; A ‘lsp--client’ object describes the client-side behavior of a language
   1552 ;; server.  It is used to start individual server processes, each of which is
   1553 ;; represented by a ‘lsp--workspace’ object.  Client objects are normally
   1554 ;; created using ‘lsp-define-stdio-client’ or ‘lsp-define-tcp-client’.  Each
   1555 ;; workspace refers to exactly one client, but there can be multiple workspaces
   1556 ;; for a single client.
   1557 (cl-defstruct lsp--client
   1558   ;; ‘language-id’ is a function that receives a buffer as a single argument
   1559   ;; and should return the language identifier for that buffer.  See
   1560   ;; https://microsoft.github.io/language-server-protocol/specification#textdocumentitem
   1561   ;; for a list of language identifiers.  Also consult the documentation for
   1562   ;; the language server represented by this client to find out what language
   1563   ;; identifiers it supports or expects.
   1564   (language-id nil)
   1565 
   1566   ;; ‘add-on?’ when set to t the server will be started no matter whether there
   1567   ;; is another server handling the same mode.
   1568   (add-on? nil)
   1569   ;; ‘new-connection’ is a function that should start a language server process
   1570   ;; and return a cons (COMMAND-PROCESS . COMMUNICATION-PROCESS).
   1571   ;; COMMAND-PROCESS must be a process object representing the server process
   1572   ;; just started.  COMMUNICATION-PROCESS must be a process (including pipe and
   1573   ;; network processes) that ‘lsp-mode’ uses to communicate with the language
   1574   ;; server using the language server protocol.  COMMAND-PROCESS and
   1575   ;; COMMUNICATION-PROCESS may be the same process; in that case
   1576   ;; ‘new-connection’ may also return that process as a single
   1577   ;; object. ‘new-connection’ is called with two arguments, FILTER and
   1578   ;; SENTINEL.  FILTER should be used as process filter for
   1579   ;; COMMUNICATION-PROCESS, and SENTINEL should be used as process sentinel for
   1580   ;; COMMAND-PROCESS.
   1581   (new-connection nil)
   1582 
   1583   ;; ‘ignore-regexps’ is a list of regexps.  When a data packet from the
   1584   ;; language server matches any of these regexps, it will be ignored.  This is
   1585   ;; intended for dealing with language servers that output non-protocol data.
   1586   (ignore-regexps nil)
   1587 
   1588   ;; ‘ignore-messages’ is a list of regexps.  When a message from the language
   1589   ;; server matches any of these regexps, it will be ignored.  This is useful
   1590   ;; for filtering out unwanted messages; such as servers that send nonstandard
   1591   ;; message types, or extraneous log messages.
   1592   (ignore-messages nil)
   1593 
   1594   ;; ‘notification-handlers’ is a hash table mapping notification method names
   1595   ;; (strings) to functions handling the respective notifications.  Upon
   1596   ;; receiving a notification, ‘lsp-mode’ will call the associated handler
   1597   ;; function passing two arguments, the ‘lsp--workspace’ object and the
   1598   ;; deserialized notification parameters.
   1599   (notification-handlers (make-hash-table :test 'equal))
   1600 
   1601   ;; ‘request-handlers’ is a hash table mapping request method names
   1602   ;; (strings) to functions handling the respective notifications.  Upon
   1603   ;; receiving a request, ‘lsp-mode’ will call the associated handler function
   1604   ;; passing two arguments, the ‘lsp--workspace’ object and the deserialized
   1605   ;; request parameters.
   1606   (request-handlers (make-hash-table :test 'equal))
   1607 
   1608   ;; ‘response-handlers’ is a hash table mapping integral JSON-RPC request
   1609   ;; identifiers for pending asynchronous requests to functions handling the
   1610   ;; respective responses.  Upon receiving a response from the language server,
   1611   ;; ‘lsp-mode’ will call the associated response handler function with a
   1612   ;; single argument, the deserialized response parameters.
   1613   (response-handlers (make-hash-table :test 'eql))
   1614 
   1615   ;; ‘prefix-function’ is called for getting the prefix for completion.
   1616   ;; The function takes no parameter and returns a cons (start . end) representing
   1617   ;; the start and end bounds of the prefix. If it's not set, the client uses a
   1618   ;; default prefix function."
   1619   (prefix-function nil)
   1620 
   1621   ;; Contains mapping of scheme to the function that is going to be used to load
   1622   ;; the file.
   1623   (uri-handlers (make-hash-table :test #'equal))
   1624 
   1625   ;; ‘action-handlers’ is a hash table mapping action to a handler function. It
   1626   ;; can be used in `lsp-execute-code-action' to determine whether the action
   1627   ;; current client is interested in executing the action instead of sending it
   1628   ;; to the server.
   1629   (action-handlers (make-hash-table :test 'equal))
   1630 
   1631   ;; `action-filter' can be set to a function that modifies any incoming
   1632   ;; `CodeAction' in place before it is executed. The return value is ignored.
   1633   ;; This can be used to patch up broken code action requests before they are
   1634   ;; sent back to the LSP server. See `lsp-fix-code-action-booleans' for an
   1635   ;; example of a function that can be useful here.
   1636   (action-filter nil)
   1637 
   1638   ;; major modes supported by the client.
   1639   major-modes
   1640   ;; Function that will be called to decide if this language client
   1641   ;; should manage a particular buffer. The function will be passed
   1642   ;; the file name and major mode to inform the decision. Setting
   1643   ;; `activation-fn' will override `major-modes', if
   1644   ;; present.
   1645   activation-fn
   1646   ;; Break the tie when major-mode is supported by multiple clients.
   1647   (priority 0)
   1648   ;; Unique identifier for representing the client object.
   1649   server-id
   1650   ;; defines whether the client supports multi root workspaces.
   1651   multi-root
   1652   ;; Initialization options or a function that returns initialization options.
   1653   initialization-options
   1654   ;; `semantic-tokens-faces-overrides’ is a plist that can be used to extend, or
   1655   ;; completely replace, the faces used for semantic highlighting on a
   1656   ;; client-by-client basis.
   1657   ;;
   1658   ;; It recognizes four members, all of which are optional: `:types’ and
   1659   ;; `:modifiers’, respectively, should be face definition lists akin to
   1660   ;; `:lsp-semantic-token-faces’. If specified, each of these face lists will be
   1661   ;; merged with the default face definition list.
   1662   ;;
   1663   ;; Alternatively, if the plist members `:discard-default-types’ or
   1664   ;; `:discard-default-modifiers' are non-nil, the default `:type' or `:modifiers'
   1665   ;; face definitions will be replaced entirely by their respective overrides.
   1666   ;;
   1667   ;; For example, setting `:semantic-tokens-faces-overrides' to
   1668   ;; `(:types (("macro" . font-lock-keyword-face)))' will remap "macro" tokens from
   1669   ;; their default face `lsp-face-semhl-macro' to `font-lock-keyword-face'.
   1670   ;;
   1671   ;; `(:types (("macro" . font-lock-keyword-face) ("not-quite-a-macro" . some-face)))'
   1672   ;; will also remap "macro", but on top of that associate the fictional token type
   1673   ;; "not-quite-a-macro" with the face named `some-face'.
   1674   ;;
   1675   ;; `(:types (("macro" . font-lock-keyword-face))
   1676   ;;   :modifiers (("declaration" . lsp-face-semhl-interface))
   1677   ;;   :discard-default-types t
   1678   ;;   :discard-default-modifiers t)'
   1679   ;; will discard all default face definitions, hence leaving the client with
   1680   ;; only one token type "macro", mapped to `font-lock-keyword-face', and one
   1681   ;; modifier type "declaration", mapped to `lsp-face-semhl-interface'.
   1682   semantic-tokens-faces-overrides
   1683   ;; Provides support for registering LSP Server specific capabilities.
   1684   custom-capabilities
   1685   ;; Function which returns the folders that are considered to be not projects but library files.
   1686   ;; The function accepts one parameter currently active workspace.
   1687   ;; See: https://github.com/emacs-lsp/lsp-mode/issues/225.
   1688   library-folders-fn
   1689   ;; function which will be called when opening file in the workspace to perform
   1690   ;; client specific initialization. The function accepts one parameter
   1691   ;; currently active workspace.
   1692   before-file-open-fn
   1693   ;; Function which will be called right after a workspace has been initialized.
   1694   initialized-fn
   1695   ;; ‘remote?’ indicate whether the client can be used for LSP server over TRAMP.
   1696   (remote? nil)
   1697 
   1698   ;; ‘completion-in-comments?’ t if the client supports completion in comments.
   1699   (completion-in-comments? nil)
   1700 
   1701   ;; ‘path->uri-fn’ the function to use for path->uri conversion for the client.
   1702   (path->uri-fn nil)
   1703 
   1704   ;; ‘uri->path-fn’ the function to use for uri->path conversion for the client.
   1705   (uri->path-fn nil)
   1706   ;; Function that returns an environment structure that will be used
   1707   ;; to set some environment variables when starting the language
   1708   ;; server process. These environment variables enable some
   1709   ;; additional features in the language server. The environment
   1710   ;; structure is an alist of the form (KEY . VALUE), where KEY is a
   1711   ;; string (regularly in all caps), and VALUE may be a string, a
   1712   ;; boolean, or a sequence of strings.
   1713   environment-fn
   1714 
   1715   ;; ‘after-open-fn’ workspace after open specific hooks.
   1716   (after-open-fn nil)
   1717 
   1718   ;; ‘async-request-handlers’ is a hash table mapping request method names
   1719   ;; (strings) to functions handling the respective requests that may take
   1720   ;; time to finish.  Upon receiving a request, ‘lsp-mode’ will call the
   1721   ;; associated handler function passing three arguments, the ‘lsp--workspace’
   1722   ;; object, the deserialized request parameters and the callback which accept
   1723   ;; result as its parameter.
   1724   (async-request-handlers (make-hash-table :test 'equal))
   1725   download-server-fn
   1726   download-in-progress?
   1727   buffers
   1728   synchronize-sections)
   1729 
   1730 (defun lsp-clients-executable-find (find-command &rest args)
   1731   "Finds an executable by invoking a search command.
   1732 
   1733 FIND-COMMAND is the executable finder that searches for the
   1734 actual language server executable. ARGS is a list of arguments to
   1735 give to FIND-COMMAND to find the language server.  Returns the
   1736 output of FIND-COMMAND if it exits successfully, nil otherwise.
   1737 
   1738 Typical uses include finding an executable by invoking `find' in
   1739 a project, finding LLVM commands on macOS with `xcrun', or
   1740 looking up project-specific language servers for projects written
   1741 in the various dynamic languages, e.g. `nvm', `pyenv' and `rbenv'
   1742 etc."
   1743   (when-let* ((find-command-path (executable-find find-command))
   1744               (executable-path
   1745                (with-temp-buffer
   1746                  (when (zerop (apply 'call-process find-command-path nil t nil args))
   1747                    (buffer-substring-no-properties (point-min) (point-max))))))
   1748     (string-trim executable-path)))
   1749 
   1750 (defvar lsp--already-widened nil)
   1751 
   1752 (defmacro lsp-save-restriction-and-excursion (&rest form)
   1753   (declare (indent 0) (debug t))
   1754   `(if lsp--already-widened
   1755        (save-excursion ,@form)
   1756      (-let [lsp--already-widened t]
   1757        (save-restriction
   1758          (widen)
   1759          (save-excursion ,@form)))))
   1760 
   1761 ;; from http://emacs.stackexchange.com/questions/8082/how-to-get-buffer-position-given-line-number-and-column-number
   1762 (defun lsp--line-character-to-point (line character)
   1763   "Return the point for character CHARACTER on line LINE."
   1764   (or (lsp-virtual-buffer-call :line/character->point line character)
   1765       (let ((inhibit-field-text-motion t))
   1766         (lsp-save-restriction-and-excursion
   1767           (goto-char (point-min))
   1768           (forward-line line)
   1769           ;; server may send character position beyond the current line and we
   1770           ;; should fallback to line end.
   1771           (-let [line-end (line-end-position)]
   1772             (if (> character (- line-end (point)))
   1773                 line-end
   1774               (forward-char character)
   1775               (point)))))))
   1776 
   1777 (lsp-defun lsp--position-to-point ((&Position :line :character))
   1778   "Convert `Position' object in PARAMS to a point."
   1779   (lsp--line-character-to-point line character))
   1780 
   1781 (lsp-defun lsp--range-to-region ((&RangeToPoint :start :end))
   1782   (cons start end))
   1783 
   1784 (lsp-defun lsp--range-text ((&RangeToPoint :start :end))
   1785   (buffer-substring start end))
   1786 
   1787 (lsp-defun lsp--find-wrapping-range ((&SelectionRange :parent? :range (&RangeToPoint :start :end)))
   1788   (cond
   1789    ((and
   1790      (region-active-p)
   1791      (<= start (region-beginning) end)
   1792      (<= start (region-end) end)
   1793      (or (not (= start (region-beginning)))
   1794          (not (= end (region-end)))))
   1795     (cons start end))
   1796    ((and (<= start (point) end)
   1797          (not (region-active-p)))
   1798     (cons start end))
   1799    (parent? (lsp--find-wrapping-range parent?))))
   1800 
   1801 (defun lsp--get-selection-range ()
   1802   (or
   1803    (-when-let ((cache . cache-tick) lsp--document-selection-range-cache)
   1804      (when (= cache-tick (buffer-modified-tick)) cache))
   1805    (let ((response (cl-first
   1806                     (lsp-request
   1807                      "textDocument/selectionRange"
   1808                      (list :textDocument (lsp--text-document-identifier)
   1809                            :positions (vector (lsp--cur-position)))))))
   1810      (setq lsp--document-selection-range-cache
   1811            (cons response (buffer-modified-tick)))
   1812      response)))
   1813 
   1814 (defun lsp-extend-selection ()
   1815   "Extend selection."
   1816   (interactive)
   1817   (unless (lsp-feature? "textDocument/selectionRange")
   1818     (signal 'lsp-capability-not-supported (list "selectionRangeProvider")))
   1819   (-when-let ((start . end) (lsp--find-wrapping-range (lsp--get-selection-range)))
   1820     (goto-char start)
   1821     (set-mark (point))
   1822     (goto-char end)
   1823     (exchange-point-and-mark)))
   1824 
   1825 (defun lsp-warn (message &rest args)
   1826   "Display a warning message made from (`format-message' MESSAGE ARGS...).
   1827 This is equivalent to `display-warning', using `lsp-mode' as the type and
   1828 `:warning' as the level."
   1829   (display-warning 'lsp-mode (apply #'format-message message args)))
   1830 
   1831 (defun lsp--get-uri-handler (scheme)
   1832   "Get uri handler for SCHEME in the current workspace."
   1833   (--some (gethash scheme (lsp--client-uri-handlers (lsp--workspace-client it)))
   1834           (or (lsp-workspaces) (lsp--session-workspaces (lsp-session)))))
   1835 
   1836 (defun lsp--fix-path-casing (path)
   1837   "On windows, downcases path because the windows file system is
   1838 case-insensitive.
   1839 
   1840 On other systems, returns path without change."
   1841   (if (eq system-type 'windows-nt) (downcase path) path))
   1842 
   1843 (defun lsp--uri-to-path (uri)
   1844   "Convert URI to a file path."
   1845   (if-let ((fn (->> (lsp-workspaces)
   1846                     (-keep (-compose #'lsp--client-uri->path-fn #'lsp--workspace-client))
   1847                     (cl-first))))
   1848       (funcall fn uri)
   1849     (lsp--uri-to-path-1 uri)))
   1850 
   1851 (defun lsp-remap-path-if-needed (file-name)
   1852   (-if-let ((virtual-buffer &as &plist :buffer) (gethash file-name lsp--virtual-buffer-mappings))
   1853       (propertize (buffer-local-value 'buffer-file-name buffer)
   1854                   'lsp-virtual-buffer virtual-buffer)
   1855     file-name))
   1856 
   1857 (defun lsp--uri-to-path-1 (uri)
   1858   "Convert URI to a file path."
   1859   (let* ((url (url-generic-parse-url (url-unhex-string uri)))
   1860          (type (url-type url))
   1861          (target (url-target url))
   1862          (file
   1863           (concat (decode-coding-string (url-filename url)
   1864                                         (or locale-coding-system 'utf-8))
   1865                   (when (and target
   1866                              (not (s-match
   1867                                    (rx "#" (group (1+ num)) (or "," "#")
   1868                                        (group (1+ num))
   1869                                        string-end)
   1870                                    uri)))
   1871                     (concat "#" target))))
   1872          (file-name (if (and type (not (string= type "file")))
   1873                         (if-let ((handler (lsp--get-uri-handler type)))
   1874                             (funcall handler uri)
   1875                           uri)
   1876                       ;; `url-generic-parse-url' is buggy on windows:
   1877                       ;; https://github.com/emacs-lsp/lsp-mode/pull/265
   1878                       (or (and (eq system-type 'windows-nt)
   1879                                (eq (elt file 0) ?\/)
   1880                                (substring file 1))
   1881                           file))))
   1882     (->> file-name
   1883          (concat (-some #'lsp--workspace-host-root (lsp-workspaces)))
   1884          (lsp-remap-path-if-needed))))
   1885 
   1886 (defun lsp--buffer-uri ()
   1887   "Return URI of the current buffer."
   1888   (or lsp-buffer-uri
   1889       (plist-get lsp--virtual-buffer :buffer-uri)
   1890       (lsp--path-to-uri
   1891        (or (buffer-file-name) (buffer-file-name (buffer-base-buffer))))))
   1892 
   1893 (defun lsp-register-client-capabilities (&rest _args)
   1894   "Implemented only to make `company-lsp' happy.
   1895 DELETE when `lsp-mode.el' is deleted.")
   1896 
   1897 (defconst lsp--url-path-allowed-chars
   1898   (url--allowed-chars (append '(?/) url-unreserved-chars))
   1899   "`url-unreserved-chars' with additional delim ?/.
   1900 This set of allowed chars is enough for hexifying local file paths.")
   1901 
   1902 (defun lsp--path-to-uri-1 (path)
   1903   (concat lsp--uri-file-prefix
   1904           (--> path
   1905             (expand-file-name it)
   1906             (or (file-remote-p it 'localname t) it)
   1907             (url-hexify-string it lsp--url-path-allowed-chars))))
   1908 
   1909 (defun lsp--path-to-uri (path)
   1910   "Convert PATH to a uri."
   1911   (if-let ((uri-fn (->> (lsp-workspaces)
   1912                         (-keep (-compose #'lsp--client-path->uri-fn #'lsp--workspace-client))
   1913                         (cl-first))))
   1914       (funcall uri-fn path)
   1915     (lsp--path-to-uri-1 path)))
   1916 
   1917 (defun lsp--string-match-any (regex-list str)
   1918   "Return the first regex, if any, within REGEX-LIST matching STR."
   1919   (--first (string-match it str) regex-list))
   1920 
   1921 (cl-defstruct lsp-watch
   1922   (descriptors (make-hash-table :test 'equal))
   1923   root-directory)
   1924 
   1925 (defun lsp--folder-watch-callback (event callback watch ignored-files ignored-directories)
   1926   (let ((file-name (cl-third event))
   1927         (event-type (cl-second event)))
   1928     (cond
   1929      ((and (file-directory-p file-name)
   1930            (equal 'created event-type)
   1931            (not (lsp--string-match-any ignored-directories file-name)))
   1932 
   1933       (lsp-watch-root-folder (file-truename file-name) callback ignored-files ignored-directories watch)
   1934 
   1935       ;; process the files that are already present in
   1936       ;; the directory.
   1937       (->> (directory-files-recursively file-name ".*" t)
   1938            (seq-do (lambda (f)
   1939                      (unless (file-directory-p f)
   1940                        (funcall callback (list nil 'created f)))))))
   1941      ((and (memq event-type '(created deleted changed))
   1942            (not (file-directory-p file-name))
   1943            (not (lsp--string-match-any ignored-files file-name)))
   1944       (funcall callback event))
   1945      ((and (memq event-type '(renamed))
   1946            (not (file-directory-p file-name))
   1947            (not (lsp--string-match-any ignored-files file-name)))
   1948       (funcall callback `(,(cl-first event) deleted ,(cl-third event)))
   1949       (funcall callback `(,(cl-first event) created ,(cl-fourth event)))))))
   1950 
   1951 (defun lsp--ask-about-watching-big-repo (number-of-directories dir)
   1952   "Ask the user if they want to watch NUMBER-OF-DIRECTORIES from a repository DIR.
   1953 This is useful when there is a lot of files in a repository, as
   1954 that may slow Emacs down. Returns t if the user wants to watch
   1955 the entire repository, nil otherwise."
   1956   (prog1
   1957       (yes-or-no-p
   1958        (format
   1959         "Watching all the files in %s would require adding watches to %s directories, so watching the repo may slow Emacs down.
   1960 Do you want to watch all files in %s? "
   1961         dir
   1962         number-of-directories
   1963         dir))
   1964     (lsp--info
   1965      (concat "You can configure this warning with the `lsp-enable-file-watchers' "
   1966              "and `lsp-file-watch-threshold' variables"))))
   1967 
   1968 
   1969 (defun lsp--path-is-watchable-directory (path dir ignored-directories)
   1970   "Figure out whether PATH (inside of DIR) is meant to have a file watcher set.
   1971 IGNORED-DIRECTORIES is a list of regexes to filter out directories we don't
   1972 want to watch."
   1973   (let
   1974       ((full-path (f-join dir path)))
   1975     (and (file-accessible-directory-p full-path)
   1976          (not (equal path "."))
   1977          (not (equal path ".."))
   1978          (not (lsp--string-match-any ignored-directories full-path)))))
   1979 
   1980 
   1981 (defun lsp--all-watchable-directories (dir ignored-directories)
   1982   "Traverse DIR recursively returning a list of paths that should have watchers.
   1983 IGNORED-DIRECTORIES will be used for exclusions"
   1984   (let* ((dir (if (f-symlink? dir)
   1985                   (file-truename dir)
   1986                 dir)))
   1987     (apply #'nconc
   1988            ;; the directory itself is assumed to be part of the set
   1989            (list dir)
   1990            ;; collect all subdirectories that are watchable
   1991            (-map
   1992             (lambda (path) (lsp--all-watchable-directories (f-join dir path) ignored-directories))
   1993             ;; but only look at subdirectories that are watchable
   1994             (-filter (lambda (path) (lsp--path-is-watchable-directory path dir ignored-directories))
   1995                      (directory-files dir))))))
   1996 
   1997 (defun lsp-watch-root-folder (dir callback ignored-files ignored-directories &optional watch warn-big-repo?)
   1998   "Create recursive file notification watch in DIR.
   1999 CALLBACK will be called when there are changes in any of
   2000 the monitored files. WATCHES is a hash table directory->file
   2001 notification handle which contains all of the watch that
   2002 already have been created. Watches will not be created for
   2003 any directory that matches any regex in IGNORED-DIRECTORIES.
   2004 Watches will not be created for any file that matches any
   2005 regex in IGNORED-FILES."
   2006   (let* ((dir (if (f-symlink? dir)
   2007                   (file-truename dir)
   2008                 dir))
   2009          (watch (or watch (make-lsp-watch :root-directory dir)))
   2010          (dirs-to-watch (lsp--all-watchable-directories dir ignored-directories)))
   2011     (lsp-log "Creating watchers for following %s folders:\n  %s"
   2012              (length dirs-to-watch)
   2013              (s-join "\n  " dirs-to-watch))
   2014     (when (or
   2015            (not warn-big-repo?)
   2016            (not lsp-file-watch-threshold)
   2017            (let ((number-of-directories (length dirs-to-watch)))
   2018              (or
   2019               (< number-of-directories lsp-file-watch-threshold)
   2020               (condition-case nil
   2021                   (lsp--ask-about-watching-big-repo number-of-directories dir)
   2022                 (quit)))))
   2023       (dolist (current-dir dirs-to-watch)
   2024         (condition-case err
   2025             (progn
   2026               (puthash
   2027                current-dir
   2028                (file-notify-add-watch current-dir
   2029                                       '(change)
   2030                                       (lambda (event)
   2031                                         (lsp--folder-watch-callback event callback watch ignored-files ignored-directories)))
   2032                (lsp-watch-descriptors watch)))
   2033           (error (lsp-log "Failed to create a watch for %s: message" (error-message-string err)))
   2034           (file-missing (lsp-log "Failed to create a watch for %s: message" (error-message-string err))))))
   2035     watch))
   2036 
   2037 (defun lsp-kill-watch (watch)
   2038   "Delete WATCH."
   2039   (-> watch lsp-watch-descriptors hash-table-values (-each #'file-notify-rm-watch))
   2040   (ht-clear! (lsp-watch-descriptors watch)))
   2041 
   2042 (defun lsp-json-bool (val)
   2043   "Convert VAL to JSON boolean."
   2044   (if val t :json-false))
   2045 
   2046 (defmacro with-lsp-workspace (workspace &rest body)
   2047   "Helper macro for invoking BODY in WORKSPACE context."
   2048   (declare (debug (form body))
   2049            (indent 1))
   2050   `(let ((lsp--cur-workspace ,workspace)) ,@body))
   2051 
   2052 (defmacro with-lsp-workspaces (workspaces &rest body)
   2053   "Helper macro for invoking BODY against multiple WORKSPACES."
   2054   (declare (debug (form body))
   2055            (indent 1))
   2056   `(let ((lsp--buffer-workspaces ,workspaces)) ,@body))
   2057 
   2058 
   2059 
   2060 (defmacro lsp-consistency-check (package)
   2061   `(defconst ,(intern (concat (symbol-name package)
   2062                               "-plist-value-when-compiled"))
   2063      (eval-when-compile lsp-use-plists)))
   2064 
   2065 
   2066 ;; loading code-workspace files
   2067 
   2068 ;;;###autoload
   2069 (defun lsp-load-vscode-workspace (file)
   2070   "Load vscode workspace from FILE"
   2071   (interactive "fSelect file to import: ")
   2072   (mapc #'lsp-workspace-folders-remove (lsp-session-folders (lsp-session)))
   2073 
   2074   (let ((dir (f-dirname file)))
   2075     (->> file
   2076          (json-read-file)
   2077          (alist-get 'folders)
   2078          (-map (-lambda ((&alist 'path))
   2079                  (lsp-workspace-folders-add (expand-file-name path dir)))))))
   2080 
   2081 ;;;###autoload
   2082 (defun lsp-save-vscode-workspace (file)
   2083   "Save vscode workspace to FILE"
   2084   (interactive "FSelect file to save to: ")
   2085 
   2086   (let ((json-encoding-pretty-print t))
   2087     (f-write-text (json-encode
   2088                    `((folders . ,(->> (lsp-session)
   2089                                       (lsp-session-folders)
   2090                                       (--map `((path . ,it)))))))
   2091                   'utf-8
   2092                   file)))
   2093 
   2094 
   2095 (defmacro lsp-foreach-workspace (&rest body)
   2096   "Execute BODY for each of the current workspaces."
   2097   (declare (debug (form body)))
   2098   `(--map (with-lsp-workspace it ,@body) (lsp-workspaces)))
   2099 
   2100 (defmacro when-lsp-workspace (workspace &rest body)
   2101   "Helper macro for invoking BODY in WORKSPACE context if present."
   2102   (declare (debug (form body))
   2103            (indent 1))
   2104   `(when-let ((lsp--cur-workspace ,workspace)) ,@body))
   2105 
   2106 (lsp-defun lsp--window-show-quick-pick (_workspace (&ShowQuickPickParams :place-holder :can-pick-many :items))
   2107   (if-let* ((selectfunc (if can-pick-many #'completing-read-multiple #'completing-read))
   2108             (itemLabels (seq-map (-lambda ((item &as &QuickPickItem :label)) (format "%s" label))
   2109                                  items))
   2110             (result (funcall-interactively
   2111                      selectfunc
   2112                      (format "%s%s " place-holder (if can-pick-many " (* for all)" "")) itemLabels))
   2113             (choices (if (listp result)
   2114                          (if (equal result '("*"))
   2115                              itemLabels
   2116                            result)
   2117                        (list result))))
   2118       (vconcat (seq-filter #'identity (seq-map (-lambda ((item &as &QuickPickItem :label :user-data))
   2119                                                  (if (member label choices)
   2120                                                      (lsp-make-quick-pick-item :label label :picked t :user-data user-data)
   2121                                                    nil))
   2122                                                items)))))
   2123 
   2124 (lsp-defun lsp--window-show-input-box (_workspace (&ShowInputBoxParams :prompt :value?))
   2125   (read-string (format "%s: " prompt) (or value? "")))
   2126 
   2127 (lsp-defun lsp--window-show-message (_workspace (&ShowMessageRequestParams :message :type))
   2128   "Send the server's messages to log.
   2129 PARAMS - the data sent from _WORKSPACE."
   2130   (funcall (cl-case type
   2131              (1 'lsp--error)
   2132              (2 'lsp--warn)
   2133              (t 'lsp--info))
   2134            "%s"
   2135            message))
   2136 
   2137 (lsp-defun lsp--window-log-message (workspace (&ShowMessageRequestParams :message :type))
   2138   "Send the server's messages to log.
   2139 PARAMS - the data sent from WORKSPACE."
   2140   (ignore
   2141    (let ((client (lsp--workspace-client workspace)))
   2142      (when (or (not client)
   2143                (cl-notany (-rpartial #'string-match-p message)
   2144                           (lsp--client-ignore-messages client)))
   2145        (lsp-log "%s" (lsp--propertize message type))))))
   2146 
   2147 (lsp-defun lsp--window-log-message-request ((&ShowMessageRequestParams :message :type :actions?))
   2148   "Display a message request to user sending the user selection back to server."
   2149   (let* ((message (lsp--propertize message type))
   2150          (choices (seq-map #'lsp:message-action-item-title actions?)))
   2151     (if choices
   2152         (completing-read (concat message " ") (seq-into choices 'list) nil t)
   2153       (lsp-log message))))
   2154 
   2155 (lsp-defun lsp--window-show-document ((&ShowDocumentParams :uri :selection?))
   2156   "Show document URI in a buffer and go to SELECTION if any."
   2157   (let ((path (lsp--uri-to-path uri)))
   2158     (when (f-exists? path)
   2159       (with-current-buffer (find-file path)
   2160         (when selection?
   2161           (goto-char (lsp--position-to-point (lsp:range-start selection?))))
   2162         t))))
   2163 
   2164 (defcustom lsp-progress-prefix "⌛ "
   2165   "Progress prefix."
   2166   :group 'lsp-mode
   2167   :type 'string
   2168   :package-version '(lsp-mode . "8.0.0"))
   2169 
   2170 (defcustom lsp-progress-function #'lsp-on-progress-modeline
   2171   "Function for handling the progress notifications."
   2172   :group 'lsp-mode
   2173   :type '(choice
   2174           (const :tag "Use modeline" lsp-on-progress-modeline)
   2175           (const :tag "Legacy(uses either `progress-reporter' or `spinner' based on `lsp-progress-via-spinner')"
   2176                  lsp-on-progress-legacy)
   2177           (const :tag "Ignore" ignore)
   2178           (function :tag "Other function"))
   2179   :package-version '(lsp-mode . "8.0.0"))
   2180 
   2181 (defcustom lsp-request-while-no-input-may-block nil
   2182   "Have `lsp-request-while-no-input` block unless `non-essential` is t."
   2183   :group 'lsp-mode
   2184   :type 'boolean)
   2185 
   2186 (defun lsp--progress-status ()
   2187   "Returns the status of the progress for the current workspaces."
   2188   (-let ((progress-status
   2189           (s-join
   2190            "|"
   2191            (-keep
   2192             (lambda (workspace)
   2193               (let ((tokens (lsp--workspace-work-done-tokens workspace)))
   2194                 (unless (ht-empty? tokens)
   2195                   (mapconcat
   2196                    (-lambda ((&WorkDoneProgressBegin :message? :title :percentage?))
   2197                      (concat (if percentage?
   2198                                  (if (numberp percentage?)
   2199                                      (format "%.0f%%%% " percentage?)
   2200                                    (format "%s%%%% " percentage?))
   2201                                "")
   2202                              (or message? title)))
   2203                    (ht-values tokens)
   2204                    "|"))))
   2205             (lsp-workspaces)))))
   2206     (unless (s-blank? progress-status)
   2207       (concat lsp-progress-prefix progress-status " "))))
   2208 
   2209 (lsp-defun lsp-on-progress-modeline (workspace (&ProgressParams :token :value
   2210                                                                 (value &as &WorkDoneProgress :kind)))
   2211   "PARAMS contains the progress data.
   2212 WORKSPACE is the workspace that contains the progress token."
   2213   (add-to-list 'global-mode-string '(t (:eval (lsp--progress-status))))
   2214   (pcase kind
   2215     ("begin" (lsp-workspace-set-work-done-token token value workspace))
   2216     ("report" (lsp-workspace-set-work-done-token token value workspace))
   2217     ("end" (lsp-workspace-rem-work-done-token token workspace)))
   2218   (force-mode-line-update))
   2219 
   2220 (lsp-defun lsp-on-progress-legacy (workspace (&ProgressParams :token :value
   2221                                                               (value &as &WorkDoneProgress :kind)))
   2222   "PARAMS contains the progress data.
   2223 WORKSPACE is the workspace that contains the progress token."
   2224   (pcase kind
   2225     ("begin"
   2226      (-let* (((&WorkDoneProgressBegin :title :percentage?) value)
   2227              (reporter
   2228               (if lsp-progress-via-spinner
   2229                   (let* ((spinner-strings (alist-get (lsp-progress-spinner-type) spinner-types))
   2230                          ;; Set message as a tooltip for the spinner strings
   2231                          (propertized-strings
   2232                           (seq-map (lambda (string) (propertize string 'help-echo title))
   2233                                    spinner-strings))
   2234                          (spinner-type (vconcat propertized-strings)))
   2235                     ;; The progress relates to the server as a whole,
   2236                     ;; display it on all buffers.
   2237                     (mapcar (lambda (buffer)
   2238                               (lsp-with-current-buffer buffer
   2239                                 (spinner-start spinner-type))
   2240                               buffer)
   2241                             (lsp--workspace-buffers workspace)))
   2242                 (if percentage?
   2243                     (make-progress-reporter title 0 100 percentage?)
   2244                   ;; No percentage, just progress
   2245                   (make-progress-reporter title nil nil)))))
   2246        (lsp-workspace-set-work-done-token token reporter workspace)))
   2247     ("report"
   2248      (when-let ((reporter (lsp-workspace-get-work-done-token token workspace)))
   2249        (unless lsp-progress-via-spinner
   2250          (progress-reporter-update reporter (lsp:work-done-progress-report-percentage? value)))))
   2251 
   2252     ("end"
   2253      (when-let ((reporter (lsp-workspace-get-work-done-token token workspace)))
   2254        (if lsp-progress-via-spinner
   2255            (mapc (lambda (buffer)
   2256                    (when (lsp-buffer-live-p buffer)
   2257                      (lsp-with-current-buffer buffer
   2258                        (spinner-stop))))
   2259                  reporter)
   2260          (progress-reporter-done reporter))
   2261        (lsp-workspace-rem-work-done-token token workspace)))))
   2262 
   2263 
   2264 ;; diagnostics
   2265 
   2266 (defvar lsp-diagnostic-filter nil
   2267   "A a function which will be called with
   2268   `&PublishDiagnosticsParams' and `workspace' which can be used
   2269   to filter out the diagnostics. The function should return
   2270   `&PublishDiagnosticsParams'.
   2271 
   2272 Common usecase are:
   2273 1. Filter the diagnostics for a particular language server.
   2274 2. Filter out the diagnostics under specific level.")
   2275 
   2276 (defvar lsp-diagnostic-stats (ht))
   2277 
   2278 (defun lsp-diagnostics (&optional current-workspace?)
   2279   "Return the diagnostics from all workspaces."
   2280   (or (pcase (if current-workspace?
   2281                  (lsp-workspaces)
   2282                (lsp--session-workspaces (lsp-session)))
   2283         (`() ())
   2284         (`(,workspace) (lsp--workspace-diagnostics workspace))
   2285         (`,workspaces (let ((result (make-hash-table :test 'equal)))
   2286                         (mapc (lambda (workspace)
   2287                                 (->> workspace
   2288                                      (lsp--workspace-diagnostics)
   2289                                      (maphash (lambda (file-name diagnostics)
   2290                                                 (puthash file-name
   2291                                                          (append (gethash file-name result) diagnostics)
   2292                                                          result)))))
   2293                               workspaces)
   2294                         result)))
   2295       (ht)))
   2296 
   2297 (defun lsp-diagnostics-stats-for (path)
   2298   "Get diagnostics statistics for PATH.
   2299 The result format is vector [_ errors warnings infos hints] or nil."
   2300   (gethash (lsp--fix-path-casing path) lsp-diagnostic-stats))
   2301 
   2302 (defun lsp-diagnostics--update-path (path new-stats)
   2303   (let ((new-stats (copy-sequence new-stats))
   2304         (path (lsp--fix-path-casing (directory-file-name path))))
   2305     (if-let ((old-data (gethash path lsp-diagnostic-stats)))
   2306         (dotimes (idx 5)
   2307           (cl-callf + (aref old-data idx)
   2308             (aref new-stats idx)))
   2309       (puthash path new-stats lsp-diagnostic-stats))))
   2310 
   2311 (lsp-defun lsp--on-diagnostics-update-stats (workspace
   2312                                              (&PublishDiagnosticsParams :uri :diagnostics))
   2313   (let ((path (lsp--fix-path-casing (lsp--uri-to-path uri)))
   2314         (new-stats (make-vector 5 0)))
   2315     (mapc (-lambda ((&Diagnostic :severity?))
   2316             (cl-incf (aref new-stats (or severity? 1))))
   2317           diagnostics)
   2318     (when-let ((old-diags (gethash path (lsp--workspace-diagnostics workspace))))
   2319       (mapc (-lambda ((&Diagnostic :severity?))
   2320               (cl-decf (aref new-stats (or severity? 1))))
   2321             old-diags))
   2322     (lsp-diagnostics--update-path path new-stats)
   2323     (while (not (string= path (setf path (file-name-directory
   2324                                           (directory-file-name path)))))
   2325       (lsp-diagnostics--update-path path new-stats))))
   2326 
   2327 (defun lsp--on-diagnostics (workspace params)
   2328   "Callback for textDocument/publishDiagnostics.
   2329 interface PublishDiagnosticsParams {
   2330     uri: string;
   2331     diagnostics: Diagnostic[];
   2332 }
   2333 PARAMS contains the diagnostics data.
   2334 WORKSPACE is the workspace that contains the diagnostics."
   2335   (when lsp-diagnostic-filter
   2336     (setf params (funcall lsp-diagnostic-filter params workspace)))
   2337 
   2338   (lsp--on-diagnostics-update-stats workspace params)
   2339 
   2340   (-let* (((&PublishDiagnosticsParams :uri :diagnostics) params)
   2341           (lsp--virtual-buffer-mappings (ht))
   2342           (file (lsp--fix-path-casing (lsp--uri-to-path uri)))
   2343           (workspace-diagnostics (lsp--workspace-diagnostics workspace)))
   2344 
   2345     (if (seq-empty-p diagnostics)
   2346         (remhash file workspace-diagnostics)
   2347       (puthash file (append diagnostics nil) workspace-diagnostics))
   2348 
   2349     (run-hooks 'lsp-diagnostics-updated-hook)))
   2350 
   2351 (defun lsp-diagnostics--workspace-cleanup (workspace)
   2352   (->> workspace
   2353        (lsp--workspace-diagnostics)
   2354        (maphash (lambda (key _)
   2355                   (lsp--on-diagnostics-update-stats
   2356                    workspace
   2357                    (lsp-make-publish-diagnostics-params
   2358                     :uri (lsp--path-to-uri key)
   2359                     :diagnostics [])))))
   2360   (clrhash (lsp--workspace-diagnostics workspace)))
   2361 
   2362 
   2363 
   2364 ;; textDocument/foldingRange support
   2365 
   2366 (cl-defstruct lsp--folding-range beg end kind children)
   2367 
   2368 (defvar-local lsp--cached-folding-ranges nil)
   2369 (defvar-local lsp--cached-nested-folding-ranges nil)
   2370 
   2371 (defun lsp--folding-range-width (range)
   2372   (- (lsp--folding-range-end range)
   2373      (lsp--folding-range-beg range)))
   2374 
   2375 (defun lsp--get-folding-ranges ()
   2376   "Get the folding ranges for the current buffer."
   2377   (unless (eq (buffer-chars-modified-tick) (car lsp--cached-folding-ranges))
   2378     (let* ((ranges (lsp-request "textDocument/foldingRange"
   2379                                 `(:textDocument ,(lsp--text-document-identifier))))
   2380            (sorted-line-col-pairs (->> ranges
   2381                                        (cl-mapcan (-lambda ((&FoldingRange :start-line
   2382                                                                            :start-character?
   2383                                                                            :end-line
   2384                                                                            :end-character?))
   2385                                                     (list (cons start-line start-character?)
   2386                                                           (cons end-line end-character?))))
   2387                                        (-sort #'lsp--line-col-comparator)))
   2388            (line-col-to-point-map (lsp--convert-line-col-to-points-batch
   2389                                    sorted-line-col-pairs)))
   2390       (setq lsp--cached-folding-ranges
   2391             (cons (buffer-chars-modified-tick)
   2392                   (--> ranges
   2393                     (seq-map (-lambda ((range &as
   2394                                               &FoldingRange :start-line
   2395                                               :start-character?
   2396                                               :end-line
   2397                                               :end-character?
   2398                                               :kind?))
   2399                                (make-lsp--folding-range
   2400                                 :beg (ht-get line-col-to-point-map
   2401                                              (cons start-line start-character?))
   2402                                 :end (ht-get line-col-to-point-map
   2403                                              (cons end-line end-character?))
   2404                                 :kind kind?))
   2405                              it)
   2406                     (seq-filter (lambda (folding-range)
   2407                                   (< (lsp--folding-range-beg folding-range)
   2408                                      (lsp--folding-range-end folding-range)))
   2409                                 it)
   2410                     (seq-into it 'list)
   2411                     (delete-dups it))))))
   2412   (cdr lsp--cached-folding-ranges))
   2413 
   2414 (defun lsp--get-nested-folding-ranges ()
   2415   "Get a list of nested folding ranges for the current buffer."
   2416   (-let [(tick . _) lsp--cached-folding-ranges]
   2417     (if (and (eq tick (buffer-chars-modified-tick))
   2418              lsp--cached-nested-folding-ranges)
   2419         lsp--cached-nested-folding-ranges
   2420       (setq lsp--cached-nested-folding-ranges
   2421             (lsp--folding-range-build-trees (lsp--get-folding-ranges))))))
   2422 
   2423 (defun lsp--folding-range-build-trees (ranges)
   2424   (setq ranges (seq-sort #'lsp--range-before-p ranges))
   2425   (let* ((dummy-node (make-lsp--folding-range
   2426                       :beg most-negative-fixnum
   2427                       :end most-positive-fixnum))
   2428          (stack (list dummy-node)))
   2429     (dolist (range ranges)
   2430       (while (not (lsp--range-inside-p range (car stack)))
   2431         (pop stack))
   2432       (push range (lsp--folding-range-children (car stack)))
   2433       (push range stack))
   2434     (lsp--folding-range-children dummy-node)))
   2435 
   2436 (defun lsp--range-inside-p (r1 r2)
   2437   "Return non-nil if folding range R1 lies inside R2"
   2438   (and (>= (lsp--folding-range-beg r1) (lsp--folding-range-beg r2))
   2439        (<= (lsp--folding-range-end r1) (lsp--folding-range-end r2))))
   2440 
   2441 (defun lsp--range-before-p (r1 r2)
   2442   "Return non-nil if folding range R1 ends before R2"
   2443   ;; Ensure r1 comes before r2
   2444   (or (< (lsp--folding-range-beg r1)
   2445          (lsp--folding-range-beg r2))
   2446       ;; If beg(r1) == beg(r2) make sure r2 ends first
   2447       (and (= (lsp--folding-range-beg r1)
   2448               (lsp--folding-range-beg r2))
   2449            (< (lsp--folding-range-end r2)
   2450               (lsp--folding-range-end r1)))))
   2451 
   2452 (defun lsp--point-inside-range-p (point range)
   2453   "Return non-nil if POINT lies inside folding range RANGE."
   2454   (and (>= point (lsp--folding-range-beg range))
   2455        (<= point (lsp--folding-range-end range))))
   2456 
   2457 (cl-defun lsp--get-current-innermost-folding-range (&optional (point (point)))
   2458   "Return the innermost folding range POINT lies in."
   2459   (seq-reduce (lambda (innermost-range curr-range)
   2460                 (if (and (lsp--point-inside-range-p point curr-range)
   2461                          (or (null innermost-range)
   2462                              (lsp--range-inside-p curr-range innermost-range)))
   2463                     curr-range
   2464                   innermost-range))
   2465               (lsp--get-folding-ranges)
   2466               nil))
   2467 
   2468 (cl-defun lsp--get-current-outermost-folding-range (&optional (point (point)))
   2469   "Return the outermost folding range POINT lies in."
   2470   (cdr (seq-reduce (-lambda ((best-pair &as outermost-width . _) curr-range)
   2471                      (let ((curr-width (lsp--folding-range-width curr-range)))
   2472                        (if (and (lsp--point-inside-range-p point curr-range)
   2473                                 (or (null best-pair)
   2474                                     (> curr-width outermost-width)))
   2475                            (cons curr-width curr-range)
   2476                          best-pair)))
   2477                    (lsp--get-folding-ranges)
   2478                    nil)))
   2479 
   2480 (defun lsp--folding-range-at-point-bounds ()
   2481   (when (and lsp-enable-folding
   2482              (lsp-feature? "textDocument/foldingRange"))
   2483     (if-let ((range (lsp--get-current-innermost-folding-range)))
   2484         (cons (lsp--folding-range-beg range)
   2485               (lsp--folding-range-end range)))))
   2486 (put 'lsp--folding-range 'bounds-of-thing-at-point
   2487      #'lsp--folding-range-at-point-bounds)
   2488 
   2489 (defun lsp--get-nearest-folding-range (&optional backward)
   2490   (let ((point (point))
   2491         (found nil))
   2492     (while (not
   2493             (or found
   2494                 (if backward
   2495                     (<= point (point-min))
   2496                   (>= point (point-max)))))
   2497       (if backward (cl-decf point) (cl-incf point))
   2498       (setq found (lsp--get-current-innermost-folding-range point)))
   2499     found))
   2500 
   2501 (defun lsp--folding-range-at-point-forward-op (n)
   2502   (when (and lsp-enable-folding
   2503              (not (zerop n))
   2504              (lsp-feature? "textDocument/foldingRange"))
   2505     (cl-block break
   2506       (dotimes (_ (abs n))
   2507         (if-let ((range (lsp--get-nearest-folding-range (< n 0))))
   2508             (goto-char (if (< n 0)
   2509                            (lsp--folding-range-beg range)
   2510                          (lsp--folding-range-end range)))
   2511           (cl-return-from break))))))
   2512 (put 'lsp--folding-range 'forward-op
   2513      #'lsp--folding-range-at-point-forward-op)
   2514 
   2515 (defun lsp--folding-range-at-point-beginning-op ()
   2516   (goto-char (car (lsp--folding-range-at-point-bounds))))
   2517 (put 'lsp--folding-range 'beginning-op
   2518      #'lsp--folding-range-at-point-beginning-op)
   2519 
   2520 (defun lsp--folding-range-at-point-end-op ()
   2521   (goto-char (cdr (lsp--folding-range-at-point-bounds))))
   2522 (put 'lsp--folding-range 'end-op
   2523      #'lsp--folding-range-at-point-end-op)
   2524 
   2525 (defun lsp--range-at-point-bounds ()
   2526   (or (lsp--folding-range-at-point-bounds)
   2527       (when-let ((range (and
   2528                          (lsp-feature? "textDocument/hover")
   2529                          (->> (lsp--text-document-position-params)
   2530                               (lsp-request "textDocument/hover")
   2531                               (lsp:hover-range?)))))
   2532         (lsp--range-to-region range))))
   2533 
   2534 ;; A more general purpose "thing", useful for applications like focus.el
   2535 (put 'lsp--range 'bounds-of-thing-at-point
   2536      #'lsp--range-at-point-bounds)
   2537 
   2538 (defun lsp--log-io-p (method)
   2539   "Return non nil if should log for METHOD."
   2540   (and lsp-log-io
   2541        (or (not lsp-log-io-allowlist-methods)
   2542            (member method lsp-log-io-allowlist-methods))))
   2543 
   2544 
   2545 ;; toggles
   2546 
   2547 (defun lsp-toggle-trace-io ()
   2548   "Toggle client-server protocol logging."
   2549   (interactive)
   2550   (setq lsp-log-io (not lsp-log-io))
   2551   (lsp--info "Server logging %s." (if lsp-log-io "enabled" "disabled")))
   2552 
   2553 (defun lsp-toggle-signature-auto-activate ()
   2554   "Toggle signature auto activate."
   2555   (interactive)
   2556   (setq lsp-signature-auto-activate
   2557         (unless lsp-signature-auto-activate '(:on-trigger-char)))
   2558   (lsp--info "Signature autoactivate %s." (if lsp-signature-auto-activate "enabled" "disabled"))
   2559   (lsp--update-signature-help-hook))
   2560 
   2561 (defun lsp-toggle-on-type-formatting ()
   2562   "Toggle on type formatting."
   2563   (interactive)
   2564   (setq lsp-enable-on-type-formatting (not lsp-enable-on-type-formatting))
   2565   (lsp--info "On type formatting is %s." (if lsp-enable-on-type-formatting "enabled" "disabled"))
   2566   (lsp--update-on-type-formatting-hook))
   2567 
   2568 (defun lsp-toggle-symbol-highlight ()
   2569   "Toggle symbol highlighting."
   2570   (interactive)
   2571   (setq lsp-enable-symbol-highlighting (not lsp-enable-symbol-highlighting))
   2572 
   2573   (cond
   2574    ((and lsp-enable-symbol-highlighting
   2575          (lsp-feature? "textDocument/documentHighlight"))
   2576     (add-hook 'lsp-on-idle-hook #'lsp--document-highlight nil t)
   2577     (lsp--info "Symbol highlighting enabled in current buffer."))
   2578    ((not lsp-enable-symbol-highlighting)
   2579     (remove-hook 'lsp-on-idle-hook #'lsp--document-highlight t)
   2580     (lsp--remove-overlays 'lsp-highlight)
   2581     (lsp--info "Symbol highlighting disabled in current buffer."))))
   2582 
   2583 
   2584 ;; keybindings
   2585 (defvar lsp--binding-descriptions nil
   2586   "List of key binding/short description pair.")
   2587 
   2588 (defmacro lsp-define-conditional-key (keymap key def desc cond &rest bindings)
   2589   "In KEYMAP, define key sequence KEY as DEF conditionally.
   2590 This is like `define-key', except the definition disappears
   2591 whenever COND evaluates to nil.
   2592 DESC is the short-description for the binding.
   2593 BINDINGS is a list of (key def desc cond)."
   2594   (declare (indent defun)
   2595            (debug (form form form form form &rest sexp)))
   2596   (->> (cl-list* key def desc cond bindings)
   2597        (-partition 4)
   2598        (-mapcat (-lambda ((key def desc cond))
   2599                   `((define-key ,keymap ,key
   2600                       '(menu-item
   2601                         ,(format "maybe-%s" def)
   2602                         ,def
   2603                         :filter
   2604                         (lambda (item)
   2605                           (when (with-current-buffer (or (when (buffer-live-p lsp--describe-buffer)
   2606                                                            lsp--describe-buffer)
   2607                                                          (current-buffer))
   2608                                   ,cond)
   2609                             item))))
   2610                     (when (stringp ,key)
   2611                       (setq lsp--binding-descriptions
   2612                             (append lsp--binding-descriptions '(,key ,desc)))))))
   2613        macroexp-progn))
   2614 
   2615 (defvar lsp--describe-buffer nil)
   2616 
   2617 (defun lsp-describe-buffer-bindings-advice (fn buffer &optional prefix menus)
   2618   (let ((lsp--describe-buffer buffer))
   2619     (funcall fn buffer prefix menus)))
   2620 
   2621 (advice-add 'describe-buffer-bindings
   2622             :around
   2623             #'lsp-describe-buffer-bindings-advice)
   2624 
   2625 (defun lsp--prepend-prefix (mappings)
   2626   (->> mappings
   2627        (-partition 2)
   2628        (-mapcat (-lambda ((key description))
   2629                   (list (concat lsp-keymap-prefix " " key)
   2630                         description)))))
   2631 
   2632 (defvar lsp-command-map
   2633   (-doto (make-sparse-keymap)
   2634     (lsp-define-conditional-key
   2635       ;; workspaces
   2636       "wD" lsp-disconnect "disconnect" (lsp-workspaces)
   2637       "wd" lsp-describe-session "describe session" t
   2638       "wq" lsp-workspace-shutdown "shutdown server" (lsp-workspaces)
   2639       "wr" lsp-workspace-restart "restart server" (lsp-workspaces)
   2640       "ws" lsp "start server" t
   2641 
   2642       ;; formatting
   2643       "==" lsp-format-buffer "format buffer" (or (lsp-feature? "textDocument/rangeFormatting")
   2644                                                  (lsp-feature? "textDocument/formatting"))
   2645       "=r" lsp-format-region "format region" (lsp-feature? "textDocument/rangeFormatting")
   2646 
   2647       ;; folders
   2648       "Fa" lsp-workspace-folders-add "add folder" t
   2649       "Fb" lsp-workspace-blocklist-remove "un-blocklist folder" t
   2650       "Fr" lsp-workspace-folders-remove "remove folder" t
   2651 
   2652       ;; toggles
   2653       "TD" lsp-modeline-diagnostics-mode "toggle modeline diagnostics" (lsp-feature?
   2654                                                                         "textDocument/publishDiagnostics")
   2655       "TL" lsp-toggle-trace-io "toggle log io" t
   2656       "TS" lsp-ui-sideline-mode "toggle sideline" (featurep 'lsp-ui-sideline)
   2657       "TT" lsp-treemacs-sync-mode "toggle treemacs integration" (featurep 'lsp-treemacs)
   2658       "Ta" lsp-modeline-code-actions-mode "toggle modeline code actions" (lsp-feature?
   2659                                                                           "textDocument/codeAction")
   2660       "Tb" lsp-headerline-breadcrumb-mode "toggle breadcrumb" (lsp-feature?
   2661                                                                "textDocument/documentSymbol")
   2662       "Td" lsp-ui-doc-mode "toggle documentation popup" (featurep 'lsp-ui-doc)
   2663       "Tf" lsp-toggle-on-type-formatting "toggle on type formatting" (lsp-feature?
   2664                                                                       "textDocument/onTypeFormatting")
   2665       "Th" lsp-toggle-symbol-highlight "toggle highlighting" (lsp-feature? "textDocument/documentHighlight")
   2666       "Tl" lsp-lens-mode "toggle lenses" (lsp-feature? "textDocument/codeLens")
   2667       "Ts" lsp-toggle-signature-auto-activate "toggle signature" (lsp-feature? "textDocument/signatureHelp")
   2668 
   2669       ;; goto
   2670       "ga" xref-find-apropos "find symbol in workspace" (lsp-feature? "workspace/symbol")
   2671       "gd" lsp-find-declaration "find declarations" (lsp-feature? "textDocument/declaration")
   2672       "ge" lsp-treemacs-errors-list "show errors" (fboundp 'lsp-treemacs-errors-list)
   2673       "gg" lsp-find-definition "find definitions" (lsp-feature? "textDocument/definition")
   2674       "gh" lsp-treemacs-call-hierarchy "call hierarchy" (and (lsp-feature? "callHierarchy/incomingCalls")
   2675                                                              (fboundp 'lsp-treemacs-call-hierarchy))
   2676       "gi" lsp-find-implementation "find implementations" (lsp-feature? "textDocument/implementation")
   2677       "gr" lsp-find-references "find references" (lsp-feature? "textDocument/references")
   2678       "gt" lsp-find-type-definition "find type definition" (lsp-feature? "textDocument/typeDefinition")
   2679 
   2680       ;; help
   2681       "hg" lsp-ui-doc-glance "glance symbol" (and (featurep 'lsp-ui-doc)
   2682                                                   (lsp-feature? "textDocument/hover"))
   2683       "hh" lsp-describe-thing-at-point "describe symbol at point" (lsp-feature? "textDocument/hover")
   2684       "hs" lsp-signature-activate "signature help" (lsp-feature? "textDocument/signatureHelp")
   2685 
   2686       ;; refactoring
   2687       "ro" lsp-organize-imports "organize imports" (lsp-feature? "textDocument/codeAction")
   2688       "rr" lsp-rename "rename" (lsp-feature? "textDocument/rename")
   2689 
   2690       ;; actions
   2691       "aa" lsp-execute-code-action "code actions" (lsp-feature? "textDocument/codeAction")
   2692       "ah" lsp-document-highlight "highlight symbol" (lsp-feature? "textDocument/documentHighlight")
   2693       "al" lsp-avy-lens "lens" (and (bound-and-true-p lsp-lens-mode) (featurep 'avy))
   2694 
   2695       ;; peeks
   2696       "Gg" lsp-ui-peek-find-definitions "peek definitions" (and (lsp-feature? "textDocument/definition")
   2697                                                                 (fboundp 'lsp-ui-peek-find-definitions))
   2698       "Gi" lsp-ui-peek-find-implementation "peek implementations" (and
   2699                                                                    (fboundp 'lsp-ui-peek-find-implementation)
   2700                                                                    (lsp-feature? "textDocument/implementation"))
   2701       "Gr" lsp-ui-peek-find-references "peek references" (and (fboundp 'lsp-ui-peek-find-references)
   2702                                                               (lsp-feature? "textDocument/references"))
   2703       "Gs" lsp-ui-peek-find-workspace-symbol "peek workspace symbol" (and (fboundp
   2704                                                                            'lsp-ui-peek-find-workspace-symbol)
   2705                                                                           (lsp-feature? "workspace/symbol")))))
   2706 
   2707 
   2708 ;; which-key integration
   2709 
   2710 (declare-function which-key-add-major-mode-key-based-replacements "ext:which-key")
   2711 (declare-function which-key-add-key-based-replacements "ext:which-key")
   2712 
   2713 (defun lsp-enable-which-key-integration (&optional all-modes)
   2714   "Adds descriptions for `lsp-mode-map' to `which-key-mode' for the current
   2715 active `major-mode', or for all major modes when ALL-MODES is t."
   2716   (cl-flet ((which-key-fn (if all-modes
   2717                               'which-key-add-key-based-replacements
   2718                             (apply-partially 'which-key-add-major-mode-key-based-replacements major-mode))))
   2719     (apply
   2720      #'which-key-fn
   2721      (lsp--prepend-prefix
   2722       (cl-list*
   2723        ""    "lsp"
   2724        "w"   "workspaces"
   2725        "F"   "folders"
   2726        "="   "formatting"
   2727        "T"   "toggle"
   2728        "g"   "goto"
   2729        "h"   "help"
   2730        "r"   "refactor"
   2731        "a"   "code actions"
   2732        "G"   "peek"
   2733        lsp--binding-descriptions)))))
   2734 
   2735 
   2736 ;; Globbing syntax
   2737 
   2738 ;; We port VSCode's glob-to-regexp code
   2739 ;; (https://github.com/Microsoft/vscode/blob/466da1c9013c624140f6d1473b23a870abc82d44/src/vs/base/common/glob.ts)
   2740 ;; since the LSP globbing syntax seems to be the same as that of
   2741 ;; VSCode.
   2742 
   2743 (defconst lsp-globstar "**"
   2744   "Globstar pattern.")
   2745 
   2746 (defconst lsp-glob-split ?/
   2747   "The character by which we split path components in a glob
   2748 pattern.")
   2749 
   2750 (defconst lsp-path-regexp "[/\\\\]"
   2751   "Forward or backslash to be used as a path separator in
   2752 computed regexps.")
   2753 
   2754 (defconst lsp-non-path-regexp "[^/\\\\]"
   2755   "A regexp matching anything other than a slash.")
   2756 
   2757 (defconst lsp-globstar-regexp
   2758   (format "\\(?:%s\\|%s+%s\\|%s%s+\\)*?"
   2759           lsp-path-regexp
   2760           lsp-non-path-regexp lsp-path-regexp
   2761           lsp-path-regexp lsp-non-path-regexp)
   2762   "Globstar in regexp form.")
   2763 
   2764 (defun lsp-split-glob-pattern (pattern split-char)
   2765   "Split PATTERN at SPLIT-CHAR while respecting braces and brackets."
   2766   (when pattern
   2767     (let ((segments nil)
   2768           (in-braces nil)
   2769           (in-brackets nil)
   2770           (current-segment ""))
   2771       (dolist (char (string-to-list pattern))
   2772         (cl-block 'exit-point
   2773           (if (eq char split-char)
   2774               (when (and (null in-braces)
   2775                          (null in-brackets))
   2776                 (push current-segment segments)
   2777                 (setq current-segment "")
   2778                 (cl-return-from 'exit-point))
   2779             (pcase char
   2780               (?{
   2781                (setq in-braces t))
   2782               (?}
   2783                (setq in-braces nil))
   2784               (?\[
   2785                (setq in-brackets t))
   2786               (?\]
   2787                (setq in-brackets nil))))
   2788           (setq current-segment (concat current-segment
   2789                                         (char-to-string char)))))
   2790       (unless (string-empty-p current-segment)
   2791         (push current-segment segments))
   2792       (nreverse segments))))
   2793 
   2794 (defun lsp--glob-to-regexp (pattern)
   2795   "Helper function to convert a PATTERN from LSP's glob syntax to
   2796 an Elisp regexp."
   2797   (if (string-empty-p pattern)
   2798       ""
   2799     (let ((current-regexp "")
   2800           (glob-segments (lsp-split-glob-pattern pattern lsp-glob-split)))
   2801       (if (-all? (lambda (segment) (eq segment lsp-globstar))
   2802                  glob-segments)
   2803           ".*"
   2804         (let ((prev-segment-was-globstar nil))
   2805           (seq-do-indexed
   2806            (lambda (segment index)
   2807              (if (string-equal segment lsp-globstar)
   2808                  (unless prev-segment-was-globstar
   2809                    (setq current-regexp (concat current-regexp
   2810                                                 lsp-globstar-regexp))
   2811                    (setq prev-segment-was-globstar t))
   2812                (let ((in-braces nil)
   2813                      (brace-val "")
   2814                      (in-brackets nil)
   2815                      (bracket-val ""))
   2816                  (dolist (char (string-to-list segment))
   2817                    (cond
   2818                     ((and (not (char-equal char ?\}))
   2819                           in-braces)
   2820                      (setq brace-val (concat brace-val
   2821                                              (char-to-string char))))
   2822                     ((and in-brackets
   2823                           (or (not (char-equal char ?\]))
   2824                               (string-empty-p bracket-val)))
   2825                      (let ((curr (cond
   2826                                   ((char-equal char ?-)
   2827                                    "-")
   2828                                   ;; NOTE: ?\^ and ?^ are different characters
   2829                                   ((and (memq char '(?^ ?!))
   2830                                         (string-empty-p bracket-val))
   2831                                    "^")
   2832                                   ((char-equal char lsp-glob-split)
   2833                                    "")
   2834                                   (t
   2835                                    (regexp-quote (char-to-string char))))))
   2836                        (setq bracket-val (concat bracket-val curr))))
   2837                     (t
   2838                      (cl-case char
   2839                        (?{
   2840                         (setq in-braces t))
   2841                        (?\[
   2842                         (setq in-brackets t))
   2843                        (?}
   2844                         (let* ((choices (lsp-split-glob-pattern brace-val ?\,))
   2845                                (brace-regexp (concat "\\(?:"
   2846                                                      (mapconcat #'lsp--glob-to-regexp choices "\\|")
   2847                                                      "\\)")))
   2848                           (setq current-regexp (concat current-regexp
   2849                                                        brace-regexp))
   2850                           (setq in-braces nil)
   2851                           (setq brace-val "")))
   2852                        (?\]
   2853                         (setq current-regexp
   2854                               (concat current-regexp
   2855                                       "[" bracket-val "]"))
   2856                         (setq in-brackets nil)
   2857                         (setq bracket-val ""))
   2858                        (??
   2859                         (setq current-regexp
   2860                               (concat current-regexp
   2861                                       lsp-non-path-regexp)))
   2862                        (?*
   2863                         (setq current-regexp
   2864                               (concat current-regexp
   2865                                       lsp-non-path-regexp "*?")))
   2866                        (t
   2867                         (setq current-regexp
   2868                               (concat current-regexp
   2869                                       (regexp-quote (char-to-string char)))))))))
   2870                  (when (and (< index (1- (length glob-segments)))
   2871                             (or (not (string-equal (nth (1+ index) glob-segments)
   2872                                                    lsp-globstar))
   2873                                 (< (+ index 2)
   2874                                    (length glob-segments))))
   2875                    (setq current-regexp
   2876                          (concat current-regexp
   2877                                  lsp-path-regexp)))
   2878                  (setq prev-segment-was-globstar nil))))
   2879            glob-segments)
   2880           current-regexp)))))
   2881 
   2882 ;; See https://github.com/emacs-lsp/lsp-mode/issues/2365
   2883 (defun lsp-glob-unbrace-at-top-level (glob-pattern)
   2884   "If GLOB-PATTERN does not start with a brace, return a singleton list
   2885 containing GLOB-PATTERN.
   2886 
   2887 If GLOB-PATTERN does start with a brace, return a list of the
   2888 comma-separated globs within the top-level braces."
   2889   (if (not (string-prefix-p "{" glob-pattern))
   2890       (list glob-pattern)
   2891     (lsp-split-glob-pattern (substring glob-pattern 1 -1) ?\,)))
   2892 
   2893 (defun lsp-glob-convert-to-wrapped-regexp (glob-pattern)
   2894   "Convert GLOB-PATTERN to a regexp wrapped with the beginning-
   2895 and end-of-string meta-characters."
   2896   (concat "\\`" (lsp--glob-to-regexp (string-trim glob-pattern)) "\\'"))
   2897 
   2898 (defun lsp-glob-to-regexps (glob-pattern)
   2899   "Convert a GLOB-PATTERN to a list of Elisp regexps."
   2900   (when-let*
   2901       ((glob-pattern (cond ((hash-table-p glob-pattern)
   2902                             (ht-get glob-pattern "pattern"))
   2903                            ((stringp glob-pattern) glob-pattern)
   2904                            (t (error "Unknown glob-pattern type: %s" glob-pattern))))
   2905        (trimmed-pattern (string-trim glob-pattern))
   2906        (top-level-unbraced-patterns (lsp-glob-unbrace-at-top-level trimmed-pattern)))
   2907     (seq-map #'lsp-glob-convert-to-wrapped-regexp
   2908              top-level-unbraced-patterns)))
   2909 
   2910 
   2911 
   2912 (defvar lsp-mode-menu)
   2913 
   2914 (defun lsp-mouse-click (event)
   2915   (interactive "e")
   2916   (let* ((ec (event-start event))
   2917          (choice (x-popup-menu event lsp-mode-menu))
   2918          (action (lookup-key lsp-mode-menu (apply 'vector choice))))
   2919 
   2920     (select-window (posn-window ec))
   2921 
   2922     (unless (and (region-active-p) (eq action 'lsp-execute-code-action))
   2923       (goto-char (posn-point ec)))
   2924     (run-with-idle-timer
   2925      0.001 nil
   2926      (lambda ()
   2927        (cl-labels ((check (value) (not (null value))))
   2928          (when choice
   2929            (call-interactively action)))))))
   2930 
   2931 (defvar lsp-mode-map
   2932   (let ((map (make-sparse-keymap)))
   2933     (define-key map (kbd "C-<down-mouse-1>") #'lsp-find-definition-mouse)
   2934     (define-key map (kbd "C-<mouse-1>") #'ignore)
   2935     (define-key map (kbd "<mouse-3>") #'lsp-mouse-click)
   2936     (define-key map (kbd "C-S-SPC") #'lsp-signature-activate)
   2937     (when lsp-keymap-prefix
   2938       (define-key map (kbd lsp-keymap-prefix) lsp-command-map))
   2939     map)
   2940   "Keymap for `lsp-mode'.")
   2941 
   2942 (define-minor-mode lsp-mode "Mode for LSP interaction."
   2943   :keymap lsp-mode-map
   2944   :lighter
   2945   (" LSP["
   2946    (lsp--buffer-workspaces
   2947     (:eval (mapconcat #'lsp--workspace-print lsp--buffer-workspaces "]["))
   2948     (:propertize "Disconnected" face warning))
   2949    "]")
   2950   :group 'lsp-mode
   2951   (when (and lsp-mode (not lsp--buffer-workspaces) (not lsp--buffer-deferred))
   2952     ;; fire up `lsp' when someone calls `lsp-mode' instead of `lsp'
   2953     (lsp)))
   2954 
   2955 (defvar lsp-mode-menu
   2956   (easy-menu-create-menu
   2957    nil
   2958    `(["Go to definition" lsp-find-definition
   2959       :active (lsp-feature? "textDocument/definition")]
   2960      ["Find references" lsp-find-references
   2961       :active (lsp-feature? "textDocument/references")]
   2962      ["Find implementations" lsp-find-implementation
   2963       :active (lsp-feature? "textDocument/implementation")]
   2964      ["Find declarations" lsp-find-declaration
   2965       :active (lsp-feature? "textDocument/declaration")]
   2966      ["Go to type declaration" lsp-find-type-definition
   2967       :active (lsp-feature? "textDocument/typeDefinition")]
   2968      "--"
   2969      ["Describe" lsp-describe-thing-at-point]
   2970      ["Code action" lsp-execute-code-action]
   2971      ["Format" lsp-format-buffer]
   2972      ["Highlight references" lsp-document-highlight]
   2973      ["Type Hierarchy" lsp-java-type-hierarchy
   2974       :visible (lsp-can-execute-command? "java.navigate.resolveTypeHierarchy")]
   2975      ["Type Hierarchy" lsp-treemacs-type-hierarchy
   2976       :visible (and (not (lsp-can-execute-command? "java.navigate.resolveTypeHierarchy"))
   2977                     (functionp 'lsp-treemacs-type-hierarchy)
   2978                     (lsp-feature? "textDocument/typeHierarchy"))]
   2979      ["Call Hierarchy" lsp-treemacs-call-hierarchy
   2980       :visible (and (functionp 'lsp-treemacs-call-hierarchy)
   2981                     (lsp-feature? "textDocument/callHierarchy"))]
   2982      ["Rename" lsp-rename
   2983       :active (lsp-feature? "textDocument/rename")]
   2984      "--"
   2985      ("Session"
   2986       ["View logs" lsp-workspace-show-log]
   2987       ["Describe" lsp-describe-session]
   2988       ["Shutdown" lsp-shutdown-workspace]
   2989       ["Restart" lsp-restart-workspace])
   2990      ("Workspace Folders"
   2991       ["Add" lsp-workspace-folders-add]
   2992       ["Remove" lsp-workspace-folders-remove]
   2993       ["Open" lsp-workspace-folders-open])
   2994      ("Toggle features"
   2995       ["Lenses" lsp-lens-mode]
   2996       ["Headerline breadcrumb" lsp-headerline-breadcrumb-mode]
   2997       ["Modeline code actions" lsp-modeline-code-actions-mode]
   2998       ["Modeline diagnostics" lsp-modeline-diagnostics-mode])
   2999      "---"
   3000      ("Debug"
   3001       :active (bound-and-true-p dap-ui-mode)
   3002       :filter ,(lambda (_)
   3003                  (and (boundp 'dap-ui-menu-items)
   3004                       (nthcdr 3 dap-ui-menu-items))))))
   3005   "Menu for lsp-mode.")
   3006 
   3007 (defalias 'make-lsp-client 'make-lsp--client)
   3008 
   3009 (cl-defstruct lsp--registered-capability
   3010   (id "")
   3011   (method " ")
   3012   (options nil))
   3013 
   3014 ;; A ‘lsp--workspace’ object represents exactly one language server process.
   3015 (cl-defstruct lsp--workspace
   3016   ;; the `ewoc' object for displaying I/O to and from the server
   3017   (ewoc nil)
   3018 
   3019   ;; ‘server-capabilities’ is a hash table of the language server capabilities.
   3020   ;; It is the hash table representation of a LSP ServerCapabilities structure;
   3021   ;; cf. https://microsoft.github.io/language-server-protocol/specification#initialize.
   3022   (server-capabilities nil)
   3023 
   3024   ;; ‘registered-server-capabilities’ is a list of hash tables that represent
   3025   ;; dynamically-registered Registration objects.  See
   3026   ;; https://microsoft.github.io/language-server-protocol/specification#client_registerCapability.
   3027   (registered-server-capabilities nil)
   3028 
   3029   ;; ‘root’ is a directory name or a directory file name for the workspace
   3030   ;; root.  ‘lsp-mode’ passes this directory to the ‘initialize’ method of the
   3031   ;; language server; see
   3032   ;; https://microsoft.github.io/language-server-protocol/specification#initialize.
   3033   (root nil)
   3034 
   3035   ;; ‘client’ is the ‘lsp--client’ object associated with this workspace.
   3036   (client nil)
   3037 
   3038   ;; ‘host-root’ contains the host root info as derived from `file-remote-p'. It
   3039   ;; used to derive the file path in `lsp--uri-to-path' when using tramp
   3040   ;; connection.
   3041   (host-root nil)
   3042 
   3043   ;; ‘proc’ is a process object; it may represent a regular process, a pipe, or
   3044   ;; a network connection.  ‘lsp-mode’ communicates with ‘proc’ using the
   3045   ;; language server protocol.  ‘proc’ corresponds to the COMMUNICATION-PROCESS
   3046   ;; element of the return value of the client’s ‘get-root’ field, which see.
   3047   (proc nil)
   3048 
   3049   ;; ‘proc’ is a process object; it must represent a regular process, not a
   3050   ;; pipe or network process.  It represents the actual server process that
   3051   ;; corresponds to this workspace.  ‘cmd-proc’ corresponds to the
   3052   ;; COMMAND-PROCESS element of the return value of the client’s ‘get-root’
   3053   ;; field, which see.
   3054   (cmd-proc nil)
   3055 
   3056   ;; ‘buffers’ is a list of buffers associated with this workspace.
   3057   (buffers nil)
   3058 
   3059   ;; if semantic tokens is enabled, `semantic-tokens-faces' contains
   3060   ;; one face (or nil) for each token type supported by the language server.
   3061   (semantic-tokens-faces nil)
   3062 
   3063   ;; If semantic highlighting is enabled, `semantic-tokens-modifier-faces'
   3064   ;; contains one face (or nil) for each modifier type supported by the language
   3065   ;; server
   3066   (semantic-tokens-modifier-faces nil)
   3067 
   3068   ;; Extra client capabilities provided by third-party packages using
   3069   ;; `lsp-register-client-capabilities'. It's value is an alist of (PACKAGE-NAME
   3070   ;; . CAPS), where PACKAGE-NAME is a symbol of the third-party package name,
   3071   ;; and CAPS is either a plist of the client capabilities, or a function that
   3072   ;; takes no argument and returns a plist of the client capabilities or nil.
   3073   (extra-client-capabilities nil)
   3074 
   3075   ;; Workspace status
   3076   (status nil)
   3077 
   3078   ;; ‘metadata’ is a generic storage for workspace specific data. It is
   3079   ;; accessed via `lsp-workspace-set-metadata' and `lsp-workspace-set-metadata'
   3080   (metadata (make-hash-table :test 'equal))
   3081 
   3082   ;; contains all the file notification watches that have been created for the
   3083   ;; current workspace in format filePath->file notification handle.
   3084   (watches (make-hash-table :test 'equal))
   3085 
   3086   ;; list of workspace folders
   3087   (workspace-folders nil)
   3088 
   3089   ;; ‘last-id’ the last request id for the current workspace.
   3090   (last-id 0)
   3091 
   3092   ;; ‘status-string’ allows extensions to specify custom status string based on
   3093   ;; the Language Server specific messages.
   3094   (status-string nil)
   3095 
   3096   ;; ‘shutdown-action’ flag used to mark that workspace should not be restarted (e.g. it
   3097   ;; was stopped).
   3098   shutdown-action
   3099 
   3100   ;; ‘diagnostics’ a hashmap with workspace diagnostics.
   3101   (diagnostics (make-hash-table :test 'equal))
   3102 
   3103   ;; contains all the workDone progress tokens that have been created
   3104   ;; for the current workspace.
   3105   (work-done-tokens (make-hash-table :test 'equal)))
   3106 
   3107 
   3108 (cl-defstruct lsp-session
   3109   ;; contains the folders that are part of the current session
   3110   folders
   3111   ;; contains the folders that must not be imported in the current workspace.
   3112   folders-blocklist
   3113   ;; contains the list of folders that must be imported in a project in case of
   3114   ;; multi root LSP server.
   3115   (server-id->folders (make-hash-table :test 'equal))
   3116   ;; folder to list of the servers that are associated with the folder.
   3117   (folder->servers (make-hash-table :test 'equal))
   3118   ;; ‘metadata’ is a generic storage for workspace specific data. It is
   3119   ;; accessed via `lsp-workspace-set-metadata' and `lsp-workspace-set-metadata'
   3120   (metadata (make-hash-table :test 'equal)))
   3121 
   3122 (defun lsp-workspace-status (status-string &optional workspace)
   3123   "Set current workspace status to STATUS-STRING.
   3124 If WORKSPACE is not specified defaults to lsp--cur-workspace."
   3125   (let ((status-string (when status-string (replace-regexp-in-string "%" "%%" status-string))))
   3126     (setf (lsp--workspace-status-string (or workspace lsp--cur-workspace)) status-string)))
   3127 
   3128 (defun lsp-session-set-metadata (key value &optional _workspace)
   3129   "Associate KEY with VALUE in the WORKSPACE metadata.
   3130 If WORKSPACE is not provided current workspace will be used."
   3131   (puthash key value (lsp-session-metadata (lsp-session))))
   3132 
   3133 (defalias 'lsp-workspace-set-metadata 'lsp-session-set-metadata)
   3134 
   3135 (defun lsp-session-get-metadata (key &optional _workspace)
   3136   "Lookup KEY in WORKSPACE metadata.
   3137 If WORKSPACE is not provided current workspace will be used."
   3138   (gethash key (lsp-session-metadata (lsp-session))))
   3139 
   3140 (defalias 'lsp-workspace-get-metadata 'lsp-session-get-metadata)
   3141 
   3142 (defun lsp-workspace-set-work-done-token (token value workspace)
   3143   "Associate TOKEN with VALUE in the WORKSPACE work-done-tokens."
   3144   (puthash token value (lsp--workspace-work-done-tokens workspace)))
   3145 
   3146 (defun lsp-workspace-get-work-done-token (token workspace)
   3147   "Lookup TOKEN in the WORKSPACE work-done-tokens."
   3148   (gethash token (lsp--workspace-work-done-tokens workspace)))
   3149 
   3150 (defun lsp-workspace-rem-work-done-token (token workspace)
   3151   "Remove TOKEN from the WORKSPACE work-done-tokens."
   3152   (remhash token (lsp--workspace-work-done-tokens workspace)))
   3153 
   3154 
   3155 (defun lsp--make-notification (method &optional params)
   3156   "Create notification body for method METHOD and parameters PARAMS."
   3157   (list :jsonrpc "2.0" :method method :params params))
   3158 
   3159 (defalias 'lsp--make-request 'lsp--make-notification)
   3160 (defalias 'lsp-make-request 'lsp--make-notification)
   3161 
   3162 (defun lsp--make-response (id result)
   3163   "Create response for REQUEST with RESULT."
   3164   `(:jsonrpc "2.0" :id ,id :result ,result))
   3165 
   3166 (defun lsp-make-notification (method &optional params)
   3167   "Create notification body for method METHOD and parameters PARAMS."
   3168   (lsp--make-notification method params))
   3169 
   3170 (defmacro lsp--json-serialize (params)
   3171   (if (progn
   3172         (require 'json)
   3173         (fboundp 'json-serialize))
   3174       `(json-serialize ,params
   3175                        :null-object nil
   3176                        :false-object :json-false)
   3177     `(let ((json-false :json-false))
   3178        (json-encode ,params))))
   3179 
   3180 (defun lsp--make-message (params)
   3181   "Create a LSP message from PARAMS, after encoding it to a JSON string."
   3182   (let ((body (lsp--json-serialize params)))
   3183     (concat "Content-Length: "
   3184             (number-to-string (1+ (string-bytes body)))
   3185             "\r\n\r\n"
   3186             body
   3187             "\n")))
   3188 
   3189 (cl-defstruct lsp--log-entry timestamp process-time type method id body)
   3190 
   3191 (defun lsp--make-log-entry (method id body type &optional process-time)
   3192   "Create an outgoing log object from BODY with method METHOD and id ID.
   3193 If ID is non-nil, then the body is assumed to be a notification.
   3194 TYPE can either be `incoming' or `outgoing'"
   3195   (cl-assert (memq type '(incoming-req outgoing-req incoming-notif
   3196                                        outgoing-notif incoming-resp
   3197                                        outgoing-resp)))
   3198   (make-lsp--log-entry
   3199    :timestamp (format-time-string "%I:%M:%S %p")
   3200    :process-time process-time
   3201    :method method
   3202    :id id
   3203    :type type
   3204    :body body))
   3205 
   3206 (defun lsp--log-font-lock-json (body)
   3207   "Font lock JSON BODY."
   3208   (with-temp-buffer
   3209     (insert body)
   3210     ;; We set the temp buffer file-name extension to .json and call `set-auto-mode'
   3211     ;; so the users configured json mode is used which could be
   3212     ;; `json-mode', `json-ts-mode', `jsonian-mode', etc.
   3213     (let ((buffer-file-name "lsp-log.json"))
   3214       (delay-mode-hooks
   3215         (set-auto-mode)
   3216         (if (fboundp 'font-lock-ensure)
   3217             (font-lock-ensure)
   3218           (with-no-warnings
   3219             (font-lock-fontify-buffer)))))
   3220     (buffer-string)))
   3221 
   3222 (defun lsp--log-entry-pp (entry)
   3223   (cl-assert (lsp--log-entry-p entry))
   3224   (pcase-let (((cl-struct lsp--log-entry timestamp method id type process-time
   3225                           body)
   3226                entry)
   3227               (json-false :json-false)
   3228               (json-encoding-pretty-print t)
   3229               (str nil))
   3230     (setq str
   3231           (concat (format "[Trace - %s] " timestamp)
   3232                   (pcase type
   3233                     ('incoming-req (format "Received request '%s - (%s)." method id))
   3234                     ('outgoing-req (format "Sending request '%s - (%s)'." method id))
   3235 
   3236                     ('incoming-notif (format "Received notification '%s'." method))
   3237                     ('outgoing-notif (format "Sending notification '%s'." method))
   3238 
   3239                     ('incoming-resp (format "Received response '%s - (%s)' in %dms."
   3240                                             method id process-time))
   3241                     ('outgoing-resp
   3242                      (format
   3243                       "Sending response '%s - (%s)'. Processing request took %dms"
   3244                       method id process-time)))
   3245                   "\n"
   3246                   (if (memq type '(incoming-resp ougoing-resp))
   3247                       "Result: "
   3248                     "Params: ")
   3249                   (lsp--log-font-lock-json (json-encode body))
   3250                   "\n\n\n"))
   3251     (setq str (propertize str 'mouse-face 'highlight 'read-only t))
   3252     (insert str)))
   3253 
   3254 (defvar-local lsp--log-io-ewoc nil)
   3255 
   3256 (defun lsp--get-create-io-ewoc (workspace)
   3257   (if (and (lsp--workspace-ewoc workspace)
   3258            (buffer-live-p (ewoc-buffer (lsp--workspace-ewoc workspace))))
   3259       (lsp--workspace-ewoc workspace)
   3260     (with-current-buffer (lsp--get-log-buffer-create workspace)
   3261       (unless (eq 'lsp-log-io-mode major-mode) (lsp-log-io-mode))
   3262       (setq-local window-point-insertion-type t)
   3263       (setq lsp--log-io-ewoc (ewoc-create #'lsp--log-entry-pp nil nil t))
   3264       (setf (lsp--workspace-ewoc workspace) lsp--log-io-ewoc))
   3265     (lsp--workspace-ewoc workspace)))
   3266 
   3267 (defun lsp--ewoc-count (ewoc)
   3268   (let* ((count 0)
   3269          (count-fn (lambda (_) (setq count (1+ count)))))
   3270     (ewoc-map count-fn ewoc)
   3271     count))
   3272 
   3273 (defun lsp--log-entry-new (entry workspace)
   3274   (let* ((ewoc (lsp--get-create-io-ewoc workspace))
   3275          (count (and (not (eq lsp-io-messages-max t)) (lsp--ewoc-count ewoc)))
   3276          (node (if (or (eq lsp-io-messages-max t)
   3277                        (>= lsp-io-messages-max count))
   3278                    nil
   3279                  (ewoc-nth ewoc (1- lsp-io-messages-max))))
   3280          (prev nil)
   3281          (inhibit-read-only t))
   3282     (while node
   3283       (setq prev (ewoc-prev ewoc node))
   3284       (ewoc-delete ewoc node)
   3285       (setq node prev))
   3286     (ewoc-enter-last ewoc entry)))
   3287 
   3288 (defun lsp--send-notification (body)
   3289   "Send BODY as a notification to the language server."
   3290   (lsp-foreach-workspace
   3291    (when (lsp--log-io-p (plist-get body :method))
   3292      (lsp--log-entry-new (lsp--make-log-entry
   3293                           (plist-get body :method)
   3294                           nil (plist-get body :params) 'outgoing-notif)
   3295                          lsp--cur-workspace))
   3296    (lsp--send-no-wait body
   3297                       (lsp--workspace-proc lsp--cur-workspace))))
   3298 
   3299 (defalias 'lsp-send-notification 'lsp--send-notification)
   3300 
   3301 (defun lsp-notify (method params)
   3302   "Send notification METHOD with PARAMS."
   3303   (lsp--send-notification (lsp--make-notification method params)))
   3304 
   3305 (defun lsp--cur-workspace-check ()
   3306   "Check whether buffer lsp workspace(s) are set."
   3307   (cl-assert (lsp-workspaces) nil
   3308              "No language server(s) is associated with this buffer."))
   3309 
   3310 (defun lsp--send-request (body &optional no-wait no-merge)
   3311   "Send BODY as a request to the language server, get the response.
   3312 If NO-WAIT is non-nil, don't synchronously wait for a response.
   3313 If NO-MERGE is non-nil, don't merge the results but return an
   3314 alist mapping workspace->result."
   3315   (lsp-request (plist-get body :method)
   3316                (plist-get body :params)
   3317                :no-wait no-wait
   3318                :no-merge no-merge))
   3319 
   3320 (defalias 'lsp-send-request 'lsp--send-request
   3321   "Send BODY as a request to the language server and return the response
   3322 synchronously.
   3323 \n(fn BODY)")
   3324 
   3325 (cl-defun lsp-request (method params &key no-wait no-merge)
   3326   "Send request METHOD with PARAMS.
   3327 If NO-MERGE is non-nil, don't merge the results but return alist
   3328 workspace->result.
   3329 If NO-WAIT is non-nil send the request as notification."
   3330   (if no-wait
   3331       (lsp-notify method params)
   3332     (let* ((send-time (float-time))
   3333            ;; max time by which we must get a response
   3334            (expected-time
   3335             (and
   3336              lsp-response-timeout
   3337              (+ send-time lsp-response-timeout)))
   3338            resp-result resp-error done?)
   3339       (unwind-protect
   3340           (progn
   3341             (lsp-request-async method params
   3342                                (lambda (res) (setf resp-result (or res :finished)) (throw 'lsp-done '_))
   3343                                :error-handler (lambda (err) (setf resp-error err) (throw 'lsp-done '_))
   3344                                :no-merge no-merge
   3345                                :mode 'detached
   3346                                :cancel-token :sync-request)
   3347             (while (not (or resp-error resp-result))
   3348               (if (functionp 'json-rpc-connection)
   3349                   (catch 'lsp-done (sit-for 0.01))
   3350                 (catch 'lsp-done
   3351                   (accept-process-output
   3352                    nil
   3353                    (if expected-time (- expected-time send-time) 1))))
   3354               (setq send-time (float-time))
   3355               (when (and expected-time (< expected-time send-time))
   3356                 (error "Timeout while waiting for response.  Method: %s" method)))
   3357             (setq done? t)
   3358             (cond
   3359              ((eq resp-result :finished) nil)
   3360              (resp-result resp-result)
   3361              ((lsp-json-error? resp-error) (error (lsp:json-error-message resp-error)))
   3362              ((lsp-json-error? (cl-first resp-error))
   3363               (error (lsp:json-error-message (cl-first resp-error))))))
   3364         (unless done?
   3365           (lsp-cancel-request-by-token :sync-request))))))
   3366 
   3367 (cl-defun lsp-request-while-no-input (method params)
   3368   "Send request METHOD with PARAMS and waits until there is no input.
   3369 Return same value as `lsp--while-no-input' and respecting `non-essential'."
   3370   (if (or non-essential (not lsp-request-while-no-input-may-block))
   3371       (let* ((send-time (float-time))
   3372              ;; max time by which we must get a response
   3373              (expected-time
   3374               (and
   3375                lsp-response-timeout
   3376                (+ send-time lsp-response-timeout)))
   3377              resp-result resp-error done?)
   3378         (unwind-protect
   3379             (progn
   3380               (lsp-request-async method params
   3381                                  (lambda (res) (setf resp-result (or res :finished)) (throw 'lsp-done '_))
   3382                                  :error-handler (lambda (err) (setf resp-error err) (throw 'lsp-done '_))
   3383                                  :mode 'detached
   3384                                  :cancel-token :sync-request)
   3385               (while (not (or resp-error resp-result (input-pending-p)))
   3386                 (catch 'lsp-done
   3387                   (sit-for
   3388                    (if expected-time (- expected-time send-time) 1)))
   3389                 (setq send-time (float-time))
   3390                 (when (and expected-time (< expected-time send-time))
   3391                   (error "Timeout while waiting for response.  Method: %s" method)))
   3392               (setq done? (or resp-error resp-result))
   3393               (cond
   3394                ((eq resp-result :finished) nil)
   3395                (resp-result resp-result)
   3396                ((lsp-json-error? resp-error) (error (lsp:json-error-message resp-error)))
   3397                ((lsp-json-error? (cl-first resp-error))
   3398                 (error (lsp:json-error-message (cl-first resp-error))))))
   3399           (unless done?
   3400             (lsp-cancel-request-by-token :sync-request))
   3401           (when (and (input-pending-p) lsp--throw-on-input)
   3402             (throw 'input :interrupted))))
   3403     (lsp-request method params)))
   3404 
   3405 (defvar lsp--cancelable-requests (ht))
   3406 
   3407 (cl-defun lsp-request-async (method params callback
   3408                                     &key mode error-handler cancel-handler no-merge cancel-token)
   3409   "Send METHOD with PARAMS as a request to the language server.
   3410 Call CALLBACK with the response received from the server
   3411 asynchronously.
   3412 MODE determines when the callback will be called depending on the
   3413 condition of the original buffer.  It could be:
   3414 - `detached' which means that the callback will be executed no
   3415 matter what has happened to the buffer.
   3416 - `alive' - the callback will be executed only if the buffer from
   3417 which the call was executed is still alive.
   3418 - `current' the callback will be executed only if the original buffer
   3419 is still selected.
   3420 - `tick' - the callback will be executed only if the buffer was not modified.
   3421 - `unchanged' - the callback will be executed only if the buffer hasn't
   3422 changed and if the buffer is not modified.
   3423 
   3424 ERROR-HANDLER will be called in case the request has failed.
   3425 CANCEL-HANDLER will be called in case the request is being canceled.
   3426 If NO-MERGE is non-nil, don't merge the results but return alist
   3427 workspace->result.
   3428 CANCEL-TOKEN is the token that can be used to cancel request."
   3429   (lsp--send-request-async `(:jsonrpc "2.0" :method ,method :params ,params)
   3430                            callback mode error-handler cancel-handler no-merge cancel-token))
   3431 
   3432 (defun lsp--create-request-cancel (id workspaces hook buf method cancel-callback)
   3433   (lambda (&rest _)
   3434     (unless (and (equal 'post-command-hook hook)
   3435                  (equal (current-buffer) buf))
   3436       (lsp--request-cleanup-hooks id)
   3437       (with-lsp-workspaces workspaces
   3438         (lsp--cancel-request id)
   3439         (when cancel-callback (funcall cancel-callback)))
   3440       (lsp-log "Cancelling %s(%s) in hook %s" method id hook))))
   3441 
   3442 (defun lsp--create-async-callback
   3443     (callback method no-merge workspaces)
   3444   "Create async handler expecting COUNT results, merge them and call CALLBACK.
   3445 MODE determines when the callback will be called depending on the
   3446 condition of the original buffer. METHOD is the invoked method.
   3447 If NO-MERGE is non-nil, don't merge the results but return alist
   3448 workspace->result. ID is the request id."
   3449   (let (results errors)
   3450     (lambda (result)
   3451       (push (cons lsp--cur-workspace result)
   3452             (if (eq result :error) errors results))
   3453       (when (and (not (eq (length errors) (length workspaces)))
   3454                  (eq (+ (length errors) (length results)) (length workspaces)))
   3455         (funcall callback
   3456                  (if no-merge
   3457                      results
   3458                    (lsp--merge-results (-map #'cl-rest results) method)))))))
   3459 
   3460 (defcustom lsp-default-create-error-handler-fn nil
   3461   "Default error handler customization.
   3462 Handler should give METHOD as argument and return function of one argument
   3463 ERROR."
   3464   :type 'function
   3465   :group 'lsp-mode
   3466   :package-version '(lsp-mode . "9.0.0"))
   3467 
   3468 (defun lsp--create-default-error-handler (method)
   3469   "Default error handler.
   3470 METHOD is the executed method."
   3471   (if lsp-default-create-error-handler-fn
   3472       (funcall lsp-default-create-error-handler-fn method)
   3473     (lambda (error)
   3474       (lsp--warn "%s" (or (lsp--error-string error)
   3475                           (format "%s Request has failed" method))))))
   3476 
   3477 (defvar lsp--request-cleanup-hooks (ht))
   3478 
   3479 (defun lsp--request-cleanup-hooks (request-id)
   3480   (when-let ((cleanup-function (gethash request-id lsp--request-cleanup-hooks)))
   3481     (funcall cleanup-function)
   3482     (remhash request-id lsp--request-cleanup-hooks)))
   3483 
   3484 (defun lsp-cancel-request-by-token (cancel-token)
   3485   "Cancel request using CANCEL-TOKEN."
   3486   (-when-let ((request-id . workspaces) (gethash cancel-token lsp--cancelable-requests))
   3487     (with-lsp-workspaces workspaces
   3488       (lsp--cancel-request request-id))
   3489     (remhash cancel-token lsp--cancelable-requests)
   3490     (lsp--request-cleanup-hooks request-id)))
   3491 
   3492 (defun lsp--send-request-async (body callback
   3493                                      &optional mode error-callback cancel-callback
   3494                                      no-merge cancel-token)
   3495   "Send BODY as a request to the language server.
   3496 Call CALLBACK with the response received from the server
   3497 asynchronously.
   3498 MODE determines when the callback will be called depending on the
   3499 condition of the original buffer.  It could be:
   3500 - `detached' which means that the callback will be executed no
   3501 matter what has happened to the buffer.
   3502 - `alive' - the callback will be executed only if the buffer from
   3503 which the call was executed is still alive.
   3504 - `current' the callback will be executed only if the original buffer
   3505 is still selected.
   3506 - `tick' - the callback will be executed only if the buffer was not modified.
   3507 - `unchanged' - the callback will be executed only if the buffer hasn't
   3508 changed and if the buffer is not modified.
   3509 
   3510 ERROR-CALLBACK will be called in case the request has failed.
   3511 CANCEL-CALLBACK will be called in case the request is being canceled.
   3512 If NO-MERGE is non-nil, don't merge the results but return alist
   3513 workspace->result.
   3514 CANCEL-TOKEN is the token that can be used to cancel request."
   3515   (when cancel-token
   3516     (lsp-cancel-request-by-token cancel-token))
   3517 
   3518   (if-let ((target-workspaces (lsp--find-workspaces-for body)))
   3519       (let* ((start-time (current-time))
   3520              (method (plist-get body :method))
   3521              (id (cl-incf lsp-last-id))
   3522              (buf (current-buffer))
   3523              (cancel-callback (when cancel-callback
   3524                                 (pcase mode
   3525                                   ((or 'alive 'tick 'unchanged)
   3526                                    (lambda ()
   3527                                      (with-current-buffer buf
   3528                                        (funcall cancel-callback))))
   3529                                   (_ cancel-callback))))
   3530              ;; calculate what are the (hook . local) pairs which will cancel
   3531              ;; the request
   3532              (hooks (pcase mode
   3533                       ('alive     '((kill-buffer-hook . t)))
   3534                       ('tick      '((kill-buffer-hook . t) (after-change-functions . t)))
   3535                       ('unchanged '((after-change-functions . t) (post-command-hook . nil)))
   3536                       ('current   '((post-command-hook . nil)))))
   3537              ;; note: lambdas in emacs can be compared but we should make sure
   3538              ;; that all of the captured arguments are the same - in our case
   3539              ;; `lsp--create-request-cancel' will return the same lambda when
   3540              ;; called with the same params.
   3541              (cleanup-hooks
   3542               (lambda () (mapc
   3543                           (-lambda ((hook . local))
   3544                             (if local
   3545                                 (when (buffer-live-p buf)
   3546                                   (with-current-buffer buf
   3547                                     (remove-hook hook
   3548                                                  (lsp--create-request-cancel
   3549                                                   id target-workspaces hook buf method cancel-callback)
   3550                                                  t)))
   3551                               (remove-hook hook (lsp--create-request-cancel
   3552                                                  id target-workspaces hook buf method cancel-callback))))
   3553                           hooks)
   3554                 (remhash cancel-token lsp--cancelable-requests)))
   3555              (callback (pcase mode
   3556                          ((or 'alive 'tick 'unchanged) (lambda (&rest args)
   3557                                                          (with-current-buffer buf
   3558                                                            (apply callback args))))
   3559                          (_ callback)))
   3560              (callback (lsp--create-async-callback callback
   3561                                                    method
   3562                                                    no-merge
   3563                                                    target-workspaces))
   3564              (callback (lambda (result)
   3565                          (lsp--request-cleanup-hooks id)
   3566                          (funcall callback result)))
   3567              (error-callback (lsp--create-async-callback
   3568                               (or error-callback
   3569                                   (lsp--create-default-error-handler method))
   3570                               method
   3571                               nil
   3572                               target-workspaces))
   3573              (error-callback (lambda (error)
   3574                                (funcall callback :error)
   3575                                (lsp--request-cleanup-hooks id)
   3576                                (funcall error-callback error)))
   3577              (body (plist-put body :id id)))
   3578 
   3579         ;; cancel request in any of the hooks
   3580         (mapc (-lambda ((hook . local))
   3581                 (add-hook hook
   3582                           (lsp--create-request-cancel
   3583                            id target-workspaces hook buf method cancel-callback)
   3584                           nil local))
   3585               hooks)
   3586         (puthash id cleanup-hooks lsp--request-cleanup-hooks)
   3587 
   3588         (setq lsp--last-active-workspaces target-workspaces)
   3589 
   3590         (when cancel-token
   3591           (puthash cancel-token (cons id target-workspaces) lsp--cancelable-requests))
   3592 
   3593         (seq-doseq (workspace target-workspaces)
   3594           (when (lsp--log-io-p method)
   3595             (lsp--log-entry-new (lsp--make-log-entry method id
   3596                                                      (plist-get body :params)
   3597                                                      'outgoing-req)
   3598                                 workspace))
   3599           (puthash id
   3600                    (list callback error-callback method start-time (current-time))
   3601                    (-> workspace
   3602                        (lsp--workspace-client)
   3603                        (lsp--client-response-handlers)))
   3604           (lsp--send-no-wait body (lsp--workspace-proc workspace)))
   3605         body)
   3606     (error "The connected server(s) does not support method %s.
   3607 To find out what capabilities support your server use `M-x lsp-describe-session'
   3608 and expand the capabilities section"
   3609            (plist-get body :method))))
   3610 
   3611 ;; deprecated, use lsp-request-async.
   3612 (defalias 'lsp-send-request-async 'lsp--send-request-async)
   3613 (make-obsolete 'lsp-send-request-async 'lsp-request-async "lsp-mode 7.0.1")
   3614 
   3615 ;; Clean up the entire state of lsp mode when Emacs is killed, to get rid of any
   3616 ;; pending language servers.
   3617 (add-hook 'kill-emacs-hook #'lsp--global-teardown)
   3618 
   3619 (defun lsp--global-teardown ()
   3620   "Unload working workspaces."
   3621   (lsp-foreach-workspace (lsp--shutdown-workspace)))
   3622 
   3623 (defun lsp--shutdown-workspace (&optional restart)
   3624   "Shut down the language server process for ‘lsp--cur-workspace’."
   3625   (with-demoted-errors "LSP error: %S"
   3626     (let ((lsp-response-timeout 0.5))
   3627       (condition-case err
   3628           (lsp-request "shutdown" nil)
   3629         (error (lsp--error "%s" err))))
   3630     (lsp-notify "exit" nil))
   3631   (setf (lsp--workspace-shutdown-action lsp--cur-workspace) (or (and restart 'restart) 'shutdown))
   3632   (lsp--uninitialize-workspace))
   3633 
   3634 (defcustom lsp-inlay-hint-enable nil
   3635   "If non-nil it will enable inlay hints."
   3636   :type 'boolean
   3637   :group 'lsp-mode
   3638   :package-version '(lsp-mode . "9.0.0"))
   3639 
   3640 (defun lsp--uninitialize-workspace ()
   3641   "Cleanup buffer state.
   3642 When a workspace is shut down, by request or from just
   3643 disappearing, unset all the variables related to it."
   3644   (-let [(&lsp-wks 'cmd-proc 'buffers) lsp--cur-workspace]
   3645     (lsp-process-kill cmd-proc)
   3646     (mapc (lambda (buf)
   3647             (when (lsp-buffer-live-p buf)
   3648               (lsp-with-current-buffer buf
   3649                                        (lsp-managed-mode -1))))
   3650           buffers)
   3651     (lsp-diagnostics--workspace-cleanup lsp--cur-workspace)))
   3652 
   3653 (defun lsp--client-capabilities (&optional custom-capabilities)
   3654   "Return the client capabilities appending CUSTOM-CAPABILITIES."
   3655   (append
   3656    `((general . ((positionEncodings . ["utf-32", "utf-16"])))
   3657      (workspace . ((workspaceEdit . ((documentChanges . t)
   3658                                      (resourceOperations . ["create" "rename" "delete"])))
   3659                    (applyEdit . t)
   3660                    (symbol . ((symbolKind . ((valueSet . ,(apply 'vector (number-sequence 1 26)))))))
   3661                    (executeCommand . ((dynamicRegistration . :json-false)))
   3662                    ,@(when lsp-enable-file-watchers '((didChangeWatchedFiles . ((dynamicRegistration . t)))))
   3663                    (workspaceFolders . t)
   3664                    (configuration . t)
   3665                    ,@(when lsp-semantic-tokens-enable
   3666                        `((semanticTokens . ((refreshSupport . ,(or (and (boundp 'lsp-semantic-tokens-honor-refresh-requests)
   3667                                                                         lsp-semantic-tokens-honor-refresh-requests)
   3668                                                                    :json-false))))))
   3669                    ,@(when lsp-lens-enable '((codeLens . ((refreshSupport . t)))))
   3670                    ,@(when lsp-inlay-hint-enable '((inlayHint . ((refreshSupport . :json-false)))))
   3671                    (fileOperations . ((didCreate . :json-false)
   3672                                       (willCreate . :json-false)
   3673                                       (didRename . t)
   3674                                       (willRename . t)
   3675                                       (didDelete . :json-false)
   3676                                       (willDelete . :json-false)))))
   3677      (textDocument . ((declaration . ((dynamicRegistration . t)
   3678                                       (linkSupport . t)))
   3679                       (definition . ((dynamicRegistration . t)
   3680                                      (linkSupport . t)))
   3681                       (references . ((dynamicRegistration . t)))
   3682                       (implementation . ((dynamicRegistration . t)
   3683                                          (linkSupport . t)))
   3684                       (typeDefinition . ((dynamicRegistration . t)
   3685                                          (linkSupport . t)))
   3686                       (synchronization . ((willSave . t) (didSave . t) (willSaveWaitUntil . t)))
   3687                       (documentSymbol . ((symbolKind . ((valueSet . ,(apply 'vector (number-sequence 1 26)))))
   3688                                          (hierarchicalDocumentSymbolSupport . t)))
   3689                       (formatting . ((dynamicRegistration . t)))
   3690                       (rangeFormatting . ((dynamicRegistration . t)))
   3691                       (onTypeFormatting . ((dynamicRegistration . t)))
   3692                       ,@(when (and lsp-semantic-tokens-enable
   3693                                    (functionp 'lsp--semantic-tokens-capabilities))
   3694                           (lsp--semantic-tokens-capabilities))
   3695                       (rename . ((dynamicRegistration . t) (prepareSupport . t)))
   3696                       (codeAction . ((dynamicRegistration . t)
   3697                                      (isPreferredSupport . t)
   3698                                      (codeActionLiteralSupport . ((codeActionKind . ((valueSet . [""
   3699                                                                                                   "quickfix"
   3700                                                                                                   "refactor"
   3701                                                                                                   "refactor.extract"
   3702                                                                                                   "refactor.inline"
   3703                                                                                                   "refactor.rewrite"
   3704                                                                                                   "source"
   3705                                                                                                   "source.organizeImports"])))))
   3706                                      (resolveSupport . ((properties . ["edit" "command"])))
   3707                                      (dataSupport . t)))
   3708                       (completion . ((completionItem . ((snippetSupport . ,(cond
   3709                                                                             ((and lsp-enable-snippet (not (fboundp 'yas-minor-mode)))
   3710                                                                              (lsp--warn (concat
   3711                                                                                          "Yasnippet is not installed, but `lsp-enable-snippet' is set to `t'. "
   3712                                                                                          "You must either install yasnippet, or disable snippet support."))
   3713                                                                              :json-false)
   3714                                                                             (lsp-enable-snippet t)
   3715                                                                             (t :json-false)))
   3716                                                         (documentationFormat . ["markdown" "plaintext"])
   3717                                                         ;; Remove this after jdtls support resolveSupport
   3718                                                         (resolveAdditionalTextEditsSupport . t)
   3719                                                         (insertReplaceSupport . t)
   3720                                                         (deprecatedSupport . t)
   3721                                                         (resolveSupport
   3722                                                          . ((properties . ["documentation"
   3723                                                                            "detail"
   3724                                                                            "additionalTextEdits"
   3725                                                                            "command"])))
   3726                                                         (insertTextModeSupport . ((valueSet . [1 2])))))
   3727                                      (contextSupport . t)
   3728                                      (dynamicRegistration . t)))
   3729                       (signatureHelp . ((signatureInformation . ((parameterInformation . ((labelOffsetSupport . t)))))
   3730                                         (dynamicRegistration . t)))
   3731                       (documentLink . ((dynamicRegistration . t)
   3732                                        (tooltipSupport . t)))
   3733                       (hover . ((contentFormat . ["markdown" "plaintext"])
   3734                                 (dynamicRegistration . t)))
   3735                       ,@(when lsp-enable-folding
   3736                           `((foldingRange . ((dynamicRegistration . t)
   3737                                              ,@(when lsp-folding-range-limit
   3738                                                  `((rangeLimit . ,lsp-folding-range-limit)))
   3739                                              ,@(when lsp-folding-line-folding-only
   3740                                                  `((lineFoldingOnly . t)))))))
   3741                       (selectionRange . ((dynamicRegistration . t)))
   3742                       (callHierarchy . ((dynamicRegistration . :json-false)))
   3743                       (typeHierarchy . ((dynamicRegistration . t)))
   3744                       (publishDiagnostics . ((relatedInformation . t)
   3745                                              (tagSupport . ((valueSet . [1 2])))
   3746                                              (versionSupport . t)))
   3747                       (linkedEditingRange . ((dynamicRegistration . t)))))
   3748      (window . ((workDoneProgress . t)
   3749                 (showDocument . ((support . t))))))
   3750    custom-capabilities))
   3751 
   3752 (defun lsp-find-roots-for-workspace (workspace session)
   3753   "Get all roots for the WORKSPACE."
   3754   (-filter #'identity (ht-map (lambda (folder workspaces)
   3755                                 (when (-contains? workspaces workspace)
   3756                                   folder))
   3757                               (lsp-session-folder->servers session))))
   3758 
   3759 (defun lsp-session-watches (&optional session)
   3760   "Get watches created for SESSION."
   3761   (or (gethash "__watches" (lsp-session-metadata (or session (lsp-session))))
   3762       (-let [res (make-hash-table :test 'equal)]
   3763         (puthash "__watches" res (lsp-session-metadata (or session (lsp-session))))
   3764         res)))
   3765 
   3766 (defun lsp--file-process-event (session root-folder event)
   3767   "Process file event."
   3768   (let* ((changed-file (cl-third event))
   3769          (rel-changed-file (f-relative changed-file root-folder))
   3770          (event-numeric-kind (alist-get (cl-second event) lsp--file-change-type))
   3771          (bit-position (1- event-numeric-kind))
   3772          (watch-bit (ash 1 bit-position)))
   3773     (->>
   3774      session
   3775      lsp-session-folder->servers
   3776      (gethash root-folder)
   3777      (seq-do (lambda (workspace)
   3778                (when (->>
   3779                       workspace
   3780                       lsp--workspace-registered-server-capabilities
   3781                       (-any?
   3782                        (lambda (capability)
   3783                          (and
   3784                           (equal (lsp--registered-capability-method capability)
   3785                                  "workspace/didChangeWatchedFiles")
   3786                           (->>
   3787                            capability
   3788                            lsp--registered-capability-options
   3789                            (lsp:did-change-watched-files-registration-options-watchers)
   3790                            (seq-find
   3791                             (-lambda ((fs-watcher &as &FileSystemWatcher :glob-pattern :kind? :_cachedRegexp cached-regexp))
   3792                               (when (or (null kind?)
   3793                                         (> (logand kind? watch-bit) 0))
   3794                                 (-let [regexes (or cached-regexp
   3795                                                    (let ((regexp (lsp-glob-to-regexps glob-pattern)))
   3796                                                      (lsp-put fs-watcher :_cachedRegexp regexp)
   3797                                                      regexp))]
   3798                                   (-any? (lambda (re)
   3799                                            (or (string-match re changed-file)
   3800                                                (string-match re rel-changed-file)))
   3801                                          regexes))))))))))
   3802                  (with-lsp-workspace workspace
   3803                    (lsp-notify
   3804                     "workspace/didChangeWatchedFiles"
   3805                     `((changes . [((type . ,event-numeric-kind)
   3806                                    (uri . ,(lsp--path-to-uri changed-file)))]))))))))))
   3807 
   3808 (lsp-defun lsp--server-register-capability ((&Registration :method :id :register-options?))
   3809   "Register capability REG."
   3810   (when (and lsp-enable-file-watchers
   3811              (equal method "workspace/didChangeWatchedFiles"))
   3812     (-let* ((created-watches (lsp-session-watches (lsp-session)))
   3813             (root-folders (cl-set-difference
   3814                            (lsp-find-roots-for-workspace lsp--cur-workspace (lsp-session))
   3815                            (ht-keys created-watches))))
   3816       ;; create watch for each root folder without such
   3817       (dolist (folder root-folders)
   3818         (let* ((watch (make-lsp-watch :root-directory folder))
   3819                (ignored-things (lsp--get-ignored-regexes-for-workspace-root folder))
   3820                (ignored-files-regex-list (car ignored-things))
   3821                (ignored-directories-regex-list (cadr ignored-things)))
   3822           (puthash folder watch created-watches)
   3823           (lsp-watch-root-folder (file-truename folder)
   3824                                  (-partial #'lsp--file-process-event (lsp-session) folder)
   3825                                  ignored-files-regex-list
   3826                                  ignored-directories-regex-list
   3827                                  watch
   3828                                  t)))))
   3829 
   3830   (push
   3831    (make-lsp--registered-capability :id id :method method :options register-options?)
   3832    (lsp--workspace-registered-server-capabilities lsp--cur-workspace)))
   3833 
   3834 (defmacro lsp--with-workspace-temp-buffer (workspace-root &rest body)
   3835   "With a temp-buffer under `WORKSPACE-ROOT' and evaluate `BODY', useful to
   3836 access dir-local variables."
   3837   (declare (indent 1) (debug t))
   3838   `(with-temp-buffer
   3839      ;; Set the buffer's name to something under the root so that we can hack the local variables
   3840      ;; This file doesn't need to exist and will not be created due to this.
   3841      (setq-local buffer-file-name (expand-file-name "lsp-mode-temp" (expand-file-name ,workspace-root)))
   3842      (hack-local-variables)
   3843      (prog1 ,@body
   3844        (setq-local buffer-file-name nil))))
   3845 
   3846 (defun lsp--get-ignored-regexes-for-workspace-root (workspace-root)
   3847   "Return a list of the form
   3848 (lsp-file-watch-ignored-files lsp-file-watch-ignored-directories) for the given
   3849 WORKSPACE-ROOT."
   3850   ;; The intent of this function is to provide per-root workspace-level customization of the
   3851   ;; lsp-file-watch-ignored-directories and lsp-file-watch-ignored-files variables.
   3852   (lsp--with-workspace-temp-buffer workspace-root
   3853     (list lsp-file-watch-ignored-files (lsp-file-watch-ignored-directories))))
   3854 
   3855 
   3856 (defun lsp--cleanup-hanging-watches ()
   3857   "Cleanup watches in case there are no more workspaces that are interested
   3858 in that particular folder."
   3859   (let* ((session (lsp-session))
   3860          (watches (lsp-session-watches session)))
   3861     (dolist (watched-folder (ht-keys watches))
   3862       (when (-none? (lambda (workspace)
   3863                       (with-lsp-workspace workspace
   3864                         (lsp--registered-capability "workspace/didChangeWatchedFiles")))
   3865                     (gethash watched-folder (lsp-session-folder->servers (lsp-session))))
   3866         (lsp-log "Cleaning up watches for folder %s. There is no workspace watching this folder..." watched-folder)
   3867         (lsp-kill-watch (gethash watched-folder watches))
   3868         (remhash watched-folder watches)))))
   3869 
   3870 (lsp-defun lsp--server-unregister-capability ((&Unregistration :id :method))
   3871   "Unregister capability UNREG."
   3872   (setf (lsp--workspace-registered-server-capabilities lsp--cur-workspace)
   3873         (seq-remove (lambda (e) (equal (lsp--registered-capability-id e) id))
   3874                     (lsp--workspace-registered-server-capabilities lsp--cur-workspace)))
   3875   (when (equal method "workspace/didChangeWatchedFiles")
   3876     (lsp--cleanup-hanging-watches)))
   3877 
   3878 (defun lsp--server-capabilities ()
   3879   "Return the capabilities of the language server associated with the buffer."
   3880   (->> (lsp-workspaces)
   3881        (-keep #'lsp--workspace-server-capabilities)
   3882        (apply #'lsp-merge)))
   3883 
   3884 (defun lsp--send-open-close-p ()
   3885   "Return whether open and close notifications should be sent to the server."
   3886   (let ((sync (lsp:server-capabilities-text-document-sync? (lsp--server-capabilities))))
   3887     (or (memq sync '(1 2))
   3888         (lsp:text-document-sync-options-open-close? sync))))
   3889 
   3890 (defun lsp--send-will-save-p ()
   3891   "Return whether willSave notifications should be sent to the server."
   3892   (-> (lsp--server-capabilities)
   3893       (lsp:server-capabilities-text-document-sync?)
   3894       (lsp:text-document-sync-options-will-save?)))
   3895 
   3896 (defun lsp--send-will-save-wait-until-p ()
   3897   "Return whether willSaveWaitUntil notifications should be sent to the server."
   3898   (-> (lsp--server-capabilities)
   3899       (lsp:server-capabilities-text-document-sync?)
   3900       (lsp:text-document-sync-options-will-save-wait-until?)))
   3901 
   3902 (defun lsp--send-did-save-p ()
   3903   "Return whether didSave notifications should be sent to the server."
   3904   (let ((sync (lsp:server-capabilities-text-document-sync? (lsp--server-capabilities))))
   3905     (or (memq sync '(1 2))
   3906         (lsp:text-document-sync-options-save? sync))))
   3907 
   3908 (defun lsp--save-include-text-p ()
   3909   "Return whether save notifications should include the text document's contents."
   3910   (->> (lsp--server-capabilities)
   3911        (lsp:server-capabilities-text-document-sync?)
   3912        (lsp:text-document-sync-options-save?)
   3913        (lsp:text-document-save-registration-options-include-text?)))
   3914 
   3915 (defun lsp--send-will-rename-files-p (path)
   3916   "Return whether willRenameFiles request should be sent to the server.
   3917 If any filters, checks if it applies for PATH."
   3918   (let* ((will-rename (-> (lsp--server-capabilities)
   3919                           (lsp:server-capabilities-workspace?)
   3920                           (lsp:workspace-server-capabilities-file-operations?)
   3921                           (lsp:workspace-file-operations-will-rename?)))
   3922          (filters (seq-into (lsp:file-operation-registration-options-filters will-rename) 'list)))
   3923     (and will-rename
   3924          (or (seq-empty-p filters)
   3925              (-any? (-lambda ((&FileOperationFilter :scheme? :pattern (&FileOperationPattern :glob)))
   3926                       (-let [regexes (lsp-glob-to-regexps glob)]
   3927                         (and (or (not scheme?)
   3928                                  (string-prefix-p scheme? (lsp--path-to-uri path)))
   3929                              (-any? (lambda (re)
   3930                                       (string-match re path))
   3931                                     regexes))))
   3932                     filters)))))
   3933 
   3934 (defun lsp--send-did-rename-files-p ()
   3935   "Return whether didRenameFiles notification should be sent to the server."
   3936   (-> (lsp--server-capabilities)
   3937       (lsp:server-capabilities-workspace?)
   3938       (lsp:workspace-server-capabilities-file-operations?)
   3939       (lsp:workspace-file-operations-did-rename?)))
   3940 
   3941 (declare-function project-roots "ext:project" (project) t)
   3942 (declare-function project-root "ext:project" (project) t)
   3943 
   3944 (defun lsp--suggest-project-root ()
   3945   "Get project root."
   3946   (or
   3947    (when (fboundp 'projectile-project-root)
   3948      (condition-case nil
   3949          (projectile-project-root)
   3950        (error nil)))
   3951    (when (fboundp 'project-current)
   3952      (when-let ((project (project-current)))
   3953        (if (fboundp 'project-root)
   3954            (project-root project)
   3955          (car (with-no-warnings
   3956                 (project-roots project))))))
   3957    default-directory))
   3958 
   3959 (defun lsp--read-from-file (file)
   3960   "Read FILE content."
   3961   (when (file-exists-p file)
   3962     (cl-first (read-from-string (f-read-text file 'utf-8)))))
   3963 
   3964 (defun lsp--persist (file-name to-persist)
   3965   "Persist TO-PERSIST in FILE-NAME.
   3966 
   3967 This function creates the parent directories if they don't exist
   3968 yet."
   3969   (let ((print-length nil)
   3970         (print-level nil))
   3971     ;; Create all parent directories:
   3972     (make-directory (f-parent file-name) t)
   3973     (f-write-text (prin1-to-string to-persist) 'utf-8 file-name)))
   3974 
   3975 (defun lsp-workspace-folders-add (project-root)
   3976   "Add PROJECT-ROOT to the list of workspace folders."
   3977   (interactive
   3978    (list (read-directory-name "Select folder to add: "
   3979                               (or (lsp--suggest-project-root) default-directory) nil t)))
   3980   (cl-pushnew (lsp-f-canonical project-root)
   3981               (lsp-session-folders (lsp-session)) :test 'equal)
   3982   (lsp--persist-session (lsp-session))
   3983 
   3984   (run-hook-with-args 'lsp-workspace-folders-changed-functions (list project-root) nil))
   3985 
   3986 (defun lsp-workspace-folders-remove (project-root)
   3987   "Remove PROJECT-ROOT from the list of workspace folders."
   3988   (interactive (list (completing-read "Select folder to remove: "
   3989                                       (lsp-session-folders (lsp-session))
   3990                                       nil t nil nil
   3991                                       (lsp-find-session-folder (lsp-session) default-directory))))
   3992 
   3993   (setq project-root (lsp-f-canonical project-root))
   3994 
   3995   ;; send remove folder to each multiroot workspace associated with the folder
   3996   (dolist (wks (->> (lsp-session)
   3997                     (lsp-session-folder->servers)
   3998                     (gethash project-root)
   3999                     (--filter (lsp--client-multi-root (lsp--workspace-client it)))))
   4000     (with-lsp-workspace wks
   4001       (lsp-notify "workspace/didChangeWorkspaceFolders"
   4002                   (lsp-make-did-change-workspace-folders-params
   4003                    :event (lsp-make-workspace-folders-change-event
   4004                            :removed (vector (lsp-make-workspace-folder
   4005                                              :uri (lsp--path-to-uri project-root)
   4006                                              :name (f-filename project-root)))
   4007                            :added [])))))
   4008 
   4009   ;; turn off servers in the removed directory
   4010   (let* ((session (lsp-session))
   4011          (folder->servers (lsp-session-folder->servers session))
   4012          (server-id->folders (lsp-session-server-id->folders session))
   4013          (workspaces (gethash project-root folder->servers)))
   4014 
   4015     (remhash project-root folder->servers)
   4016 
   4017     ;; turn off the servers without root folders
   4018     (dolist (workspace workspaces)
   4019       (when (--none? (-contains? it workspace) (ht-values folder->servers))
   4020         (lsp--info "Shutdown %s since folder %s is removed..."
   4021                    (lsp--workspace-print workspace) project-root)
   4022         (with-lsp-workspace workspace (lsp--shutdown-workspace))))
   4023 
   4024     (setf (lsp-session-folders session)
   4025           (-remove-item project-root (lsp-session-folders session)))
   4026 
   4027     (ht-aeach (puthash key
   4028                        (-remove-item project-root value)
   4029                        server-id->folders)
   4030               server-id->folders)
   4031     (lsp--persist-session (lsp-session)))
   4032 
   4033   (run-hook-with-args 'lsp-workspace-folders-changed-functions nil (list project-root)))
   4034 
   4035 (defun lsp-workspace-blocklist-remove (project-root)
   4036   "Remove PROJECT-ROOT from the workspace blocklist."
   4037   (interactive (list (completing-read "Select folder to remove:"
   4038                                       (lsp-session-folders-blocklist (lsp-session))
   4039                                       nil t)))
   4040   (setf (lsp-session-folders-blocklist (lsp-session))
   4041         (delete project-root
   4042                 (lsp-session-folders-blocklist (lsp-session))))
   4043   (lsp--persist-session (lsp-session)))
   4044 
   4045 (define-obsolete-function-alias 'lsp-workspace-folders-switch
   4046   'lsp-workspace-folders-open "lsp-mode 6.1")
   4047 
   4048 (defun lsp-workspace-folders-open (project-root)
   4049   "Open the directory located at PROJECT-ROOT"
   4050   (interactive (list (completing-read "Open folder: "
   4051                                       (lsp-session-folders (lsp-session))
   4052                                       nil t)))
   4053   (find-file project-root))
   4054 
   4055 (defun lsp--maybe-enable-signature-help (trigger-characters)
   4056   (let ((ch last-command-event))
   4057     (when (cl-find ch trigger-characters :key #'string-to-char)
   4058       (lsp-signature-activate))))
   4059 
   4060 (defun lsp--on-type-formatting-handler-create ()
   4061   (when-let ((provider (lsp--capability-for-method "textDocument/onTypeFormatting" )))
   4062     (-let [(&DocumentOnTypeFormattingOptions :more-trigger-character?
   4063                                              :first-trigger-character) provider]
   4064       (lambda ()
   4065         (lsp--on-type-formatting first-trigger-character
   4066                                  more-trigger-character?)))))
   4067 
   4068 (defun lsp--update-on-type-formatting-hook (&optional cleanup?)
   4069   (let ((on-type-formatting-handler (lsp--on-type-formatting-handler-create)))
   4070     (cond
   4071      ((and lsp-enable-on-type-formatting on-type-formatting-handler (not cleanup?))
   4072       (add-hook 'post-self-insert-hook on-type-formatting-handler nil t))
   4073      ((or cleanup?
   4074           (not lsp-enable-on-type-formatting))
   4075       (remove-hook 'post-self-insert-hook on-type-formatting-handler t)))))
   4076 
   4077 (defun lsp--signature-help-handler-create ()
   4078   (-when-let ((&SignatureHelpOptions? :trigger-characters?)
   4079               (lsp--capability-for-method "textDocument/signatureHelp"))
   4080     (lambda ()
   4081       (lsp--maybe-enable-signature-help trigger-characters?))))
   4082 
   4083 (defun lsp--update-signature-help-hook (&optional cleanup?)
   4084   (let ((signature-help-handler (lsp--signature-help-handler-create)))
   4085     (cond
   4086      ((and (or (equal lsp-signature-auto-activate t)
   4087                (memq :on-trigger-char lsp-signature-auto-activate))
   4088            signature-help-handler)
   4089       (add-hook 'post-self-insert-hook signature-help-handler nil t))
   4090 
   4091      ((or cleanup?
   4092           (not (or (equal lsp-signature-auto-activate t)
   4093                    (memq :on-trigger-char lsp-signature-auto-activate))))
   4094       (remove-hook 'post-self-insert-hook signature-help-handler t)))))
   4095 
   4096 (defun lsp--after-set-visited-file-name ()
   4097   (lsp-disconnect)
   4098   (lsp))
   4099 
   4100 ;; TODO remove those eldoc workarounds when dropping support for Emacs 27
   4101 ;; https://github.com/emacs-lsp/lsp-mode/issues/3295#issuecomment-1308994099
   4102 (defvar eldoc-documentation-default) ; CI
   4103 (when (< emacs-major-version 28)
   4104   (unless (boundp 'eldoc-documentation-functions)
   4105     (load "eldoc" nil 'nomessage))
   4106   (when (memq (default-value 'eldoc-documentation-function) '(nil ignore))
   4107     ;; actually `eldoc-documentation-strategy', but CI was failing
   4108     (setq-default eldoc-documentation-function 'eldoc-documentation-default)))
   4109 
   4110 (define-minor-mode lsp-managed-mode
   4111   "Mode for source buffers managed by lsp-mode."
   4112   :lighter nil
   4113   (cond
   4114    (lsp-managed-mode
   4115     (when (lsp-feature? "textDocument/hover")
   4116       (add-hook 'eldoc-documentation-functions #'lsp-eldoc-function nil t)
   4117       (eldoc-mode 1))
   4118 
   4119     (add-hook 'after-change-functions #'lsp-on-change nil t)
   4120     (add-hook 'after-revert-hook #'lsp-on-revert nil t)
   4121     (add-hook 'after-save-hook #'lsp-on-save nil t)
   4122     (add-hook 'auto-save-hook #'lsp--on-auto-save nil t)
   4123     (add-hook 'before-change-functions #'lsp-before-change nil t)
   4124     (add-hook 'before-save-hook #'lsp--before-save nil t)
   4125     (add-hook 'kill-buffer-hook #'lsp--text-document-did-close nil t)
   4126     (add-hook 'post-command-hook #'lsp--post-command nil t)
   4127 
   4128     (lsp--update-on-type-formatting-hook)
   4129     (lsp--update-signature-help-hook)
   4130 
   4131     (when lsp-enable-xref
   4132       (add-hook 'xref-backend-functions #'lsp--xref-backend nil t))
   4133 
   4134     (lsp-configure-buffer)
   4135 
   4136     ;; make sure we turn off lsp-mode in case major mode changes, because major
   4137     ;; mode change will wipe the buffer locals.
   4138     (add-hook 'change-major-mode-hook #'lsp-disconnect nil t)
   4139     (add-hook 'after-set-visited-file-name-hook #'lsp--after-set-visited-file-name nil t)
   4140 
   4141     (let ((buffer (lsp-current-buffer)))
   4142       (run-with-idle-timer
   4143        0.0 nil
   4144        (lambda ()
   4145          (when (lsp-buffer-live-p buffer)
   4146            (lsp-with-current-buffer buffer
   4147              (lsp--on-change-debounce buffer)
   4148              (lsp--on-idle buffer)))))))
   4149    (t
   4150     (lsp-unconfig-buffer)
   4151 
   4152     (remove-hook 'eldoc-documentation-functions #'lsp-eldoc-function t)
   4153     (remove-hook 'post-command-hook #'lsp--post-command t)
   4154     (remove-hook 'after-change-functions #'lsp-on-change t)
   4155     (remove-hook 'after-revert-hook #'lsp-on-revert t)
   4156     (remove-hook 'after-save-hook #'lsp-on-save t)
   4157     (remove-hook 'auto-save-hook #'lsp--on-auto-save t)
   4158     (remove-hook 'before-change-functions #'lsp-before-change t)
   4159     (remove-hook 'before-save-hook #'lsp--before-save t)
   4160     (remove-hook 'kill-buffer-hook #'lsp--text-document-did-close t)
   4161 
   4162     (lsp--update-on-type-formatting-hook :cleanup)
   4163     (lsp--update-signature-help-hook :cleanup)
   4164 
   4165     (when lsp--on-idle-timer
   4166       (cancel-timer lsp--on-idle-timer)
   4167       (setq lsp--on-idle-timer nil))
   4168 
   4169     (remove-hook 'lsp-on-idle-hook #'lsp--document-links t)
   4170     (remove-hook 'lsp-on-idle-hook #'lsp--document-highlight t)
   4171 
   4172     (lsp--remove-overlays 'lsp-highlight)
   4173     (lsp--remove-overlays 'lsp-links)
   4174 
   4175     (remove-hook 'xref-backend-functions #'lsp--xref-backend t)
   4176     (remove-hook 'change-major-mode-hook #'lsp-disconnect t)
   4177     (remove-hook 'after-set-visited-file-name-hook #'lsp--after-set-visited-file-name t)
   4178     (setq-local lsp-buffer-uri nil))))
   4179 
   4180 (defun lsp-configure-buffer ()
   4181   "Configure LSP features for current buffer."
   4182   ;; make sure the core is running in the context of all available workspaces
   4183   ;; to avoid misconfiguration in case we are running in `with-lsp-workspace' context
   4184   (let ((lsp--buffer-workspaces (cond
   4185                                  (lsp--buffer-workspaces)
   4186                                  (lsp--cur-workspace (list lsp--cur-workspace))))
   4187         lsp--cur-workspace)
   4188     (when lsp-auto-configure
   4189       (lsp--auto-configure)
   4190 
   4191       (when (and lsp-enable-text-document-color
   4192                  (lsp-feature? "textDocument/documentColor"))
   4193         (add-hook 'lsp-on-change-hook #'lsp--document-color nil t))
   4194 
   4195       (when (and lsp-enable-imenu
   4196                  (lsp-feature? "textDocument/documentSymbol"))
   4197         (lsp-enable-imenu))
   4198 
   4199       (when (and lsp-enable-indentation
   4200                  (lsp-feature? "textDocument/rangeFormatting"))
   4201         (add-function :override (local 'indent-region-function) #'lsp-format-region))
   4202 
   4203       (when (and lsp-enable-symbol-highlighting
   4204                  (lsp-feature? "textDocument/documentHighlight"))
   4205         (add-hook 'lsp-on-idle-hook #'lsp--document-highlight nil t))
   4206 
   4207       (when (and lsp-enable-links
   4208                  (lsp-feature? "textDocument/documentLink"))
   4209         (add-hook 'lsp-on-idle-hook #'lsp--document-links nil t))
   4210 
   4211       (when (and lsp-inlay-hint-enable
   4212                  (lsp-feature? "textDocument/inlayHint"))
   4213         (lsp-inlay-hints-mode))
   4214 
   4215       (when (and lsp-enable-dap-auto-configure
   4216                  (functionp 'dap-mode))
   4217         (dap-auto-configure-mode 1)))
   4218     (run-hooks 'lsp-configure-hook)))
   4219 
   4220 (defun lsp-unconfig-buffer ()
   4221   "Unconfigure LSP features for buffer."
   4222   (lsp--remove-overlays 'lsp-color)
   4223 
   4224   (when (advice-function-member-p 'lsp--imenu-create-index imenu-create-index-function)
   4225     (remove-function (local 'imenu-create-index-function) #'lsp--imenu-create-index)
   4226     (setq-local imenu-menubar-modified-tick 0)
   4227     (setq-local imenu--index-alist nil)
   4228     (imenu--cleanup))
   4229 
   4230   (remove-function (local 'indent-region-function) #'lsp-format-region)
   4231 
   4232   (remove-hook 'lsp-on-change-hook #'lsp--document-color t)
   4233   (remove-hook 'lsp-on-idle-hook #'lsp--document-highlight t)
   4234   (remove-hook 'lsp-on-idle-hook #'lsp--document-links t)
   4235 
   4236   (when (and lsp-enable-dap-auto-configure
   4237              (functionp 'dap-mode))
   4238     (dap-auto-configure-mode -1))
   4239 
   4240   (run-hooks 'lsp-unconfigure-hook))
   4241 
   4242 (defun lsp--buffer-content ()
   4243   (lsp-save-restriction-and-excursion
   4244     (or (lsp-virtual-buffer-call :buffer-string)
   4245         (buffer-substring-no-properties (point-min)
   4246                                         (point-max)))))
   4247 
   4248 (defun lsp--text-document-did-open ()
   4249   "`document/didOpen' event."
   4250   (run-hooks 'lsp-before-open-hook)
   4251   (when (and lsp-auto-touch-files
   4252              (not (f-exists? (lsp--uri-to-path (lsp--buffer-uri)))))
   4253     (lsp--info "Saving file '%s' because it is not present on the disk." (lsp--buffer-uri))
   4254     (save-buffer))
   4255 
   4256   (setq lsp--cur-version (or lsp--cur-version 0))
   4257   (cl-pushnew (lsp-current-buffer) (lsp--workspace-buffers lsp--cur-workspace))
   4258   (lsp-notify
   4259    "textDocument/didOpen"
   4260    (list :textDocument
   4261          (list :uri (lsp--buffer-uri)
   4262                :languageId (lsp-buffer-language)
   4263                :version lsp--cur-version
   4264                :text (lsp--buffer-content))))
   4265 
   4266   (lsp-managed-mode 1)
   4267 
   4268   (run-hooks 'lsp-after-open-hook)
   4269   (when-let ((client (-some-> lsp--cur-workspace (lsp--workspace-client))))
   4270     (-some-> (lsp--client-after-open-fn client)
   4271       (funcall))
   4272     (-some-> (format "lsp-%s-after-open-hook" (lsp--client-server-id client))
   4273       (intern-soft)
   4274       (run-hooks))))
   4275 
   4276 (defun lsp--text-document-identifier ()
   4277   "Make TextDocumentIdentifier."
   4278   (list :uri (lsp--buffer-uri)))
   4279 
   4280 (defun lsp--versioned-text-document-identifier ()
   4281   "Make VersionedTextDocumentIdentifier."
   4282   (plist-put (lsp--text-document-identifier) :version lsp--cur-version))
   4283 
   4284 (defun lsp--cur-line (&optional point)
   4285   (1- (line-number-at-pos point)))
   4286 
   4287 (defun lsp--cur-position ()
   4288   "Make a Position object for the current point."
   4289   (or (lsp-virtual-buffer-call :cur-position)
   4290       (lsp-save-restriction-and-excursion
   4291         (list :line (lsp--cur-line)
   4292               :character (- (point) (line-beginning-position))))))
   4293 
   4294 (defun lsp--point-to-position (point)
   4295   "Convert POINT to Position."
   4296   (lsp-save-restriction-and-excursion
   4297     (goto-char point)
   4298     (lsp--cur-position)))
   4299 
   4300 (defun lsp--range (start end)
   4301   "Make Range body from START and END."
   4302   ;; make sure start and end are Position objects
   4303   (list :start start :end end))
   4304 
   4305 (defun lsp--region-to-range (start end)
   4306   "Make Range object for the current region."
   4307   (lsp--range (lsp--point-to-position start)
   4308               (lsp--point-to-position end)))
   4309 
   4310 (defun lsp--region-or-line ()
   4311   "The active region or the current line."
   4312   (if (use-region-p)
   4313       (lsp--region-to-range (region-beginning) (region-end))
   4314     (lsp--region-to-range (line-beginning-position) (line-end-position))))
   4315 
   4316 (defun lsp--check-document-changes-version (document-changes)
   4317   "Verify that DOCUMENT-CHANGES have the proper version."
   4318   (unless (seq-every-p
   4319            (-lambda ((&TextDocumentEdit :text-document))
   4320              (or
   4321               (not text-document)
   4322               (let* ((filename (-> text-document
   4323                                    lsp:versioned-text-document-identifier-uri
   4324                                    lsp--uri-to-path))
   4325                      (version (lsp:versioned-text-document-identifier-version? text-document)))
   4326                 (with-current-buffer (find-file-noselect filename)
   4327                   (or (null version) (zerop version) (= -1 version)
   4328                       (equal version lsp--cur-version))))))
   4329            document-changes)
   4330     (error "Document changes cannot be applied due to different document version")))
   4331 
   4332 (defun lsp--apply-workspace-edit (workspace-edit &optional operation)
   4333   "Apply the WorkspaceEdit object WORKSPACE-EDIT.
   4334 OPERATION is symbol representing the source of this text edit."
   4335   (-let (((&WorkspaceEdit :document-changes? :changes?) workspace-edit))
   4336     (if-let ((document-changes (seq-reverse document-changes?)))
   4337         (progn
   4338           (lsp--check-document-changes-version document-changes)
   4339           (->> document-changes
   4340                (seq-filter (-lambda ((&CreateFile :kind)) (equal kind "create")))
   4341                (seq-do (lambda (change) (lsp--apply-text-document-edit change operation))))
   4342           (->> document-changes
   4343                (seq-filter (-lambda ((&CreateFile :kind))
   4344                              (and (or (not kind) (equal kind "edit"))
   4345                                   (not (equal kind "create")))))
   4346                (seq-do (lambda (change) (lsp--apply-text-document-edit change operation))))
   4347           (->> document-changes
   4348                (seq-filter (-lambda ((&CreateFile :kind))
   4349                              (and (not (or (not kind) (equal kind "edit")))
   4350                                   (not (equal kind "create")))))
   4351                (seq-do (lambda (change) (lsp--apply-text-document-edit change operation)))))
   4352       (lsp-map
   4353        (lambda (uri text-edits)
   4354          (with-current-buffer (-> uri lsp--uri-to-path find-file-noselect)
   4355            (lsp--apply-text-edits text-edits operation)))
   4356        changes?))))
   4357 
   4358 (defmacro lsp-with-filename (file &rest body)
   4359   "Execute BODY with FILE as a context.
   4360 Need to handle the case when FILE indicates virtual buffer."
   4361   (declare (indent 1) (debug t))
   4362   `(if-let ((lsp--virtual-buffer (get-text-property 0 'lsp-virtual-buffer ,file)))
   4363        (lsp-with-current-buffer lsp--virtual-buffer
   4364          ,@body)
   4365      ,@body))
   4366 
   4367 (defun lsp--apply-text-document-edit (edit &optional operation)
   4368   "Apply the TextDocumentEdit object EDIT.
   4369 OPERATION is symbol representing the source of this text edit.
   4370 If the file is not being visited by any buffer, it is opened with
   4371 `find-file-noselect'.
   4372 Because lsp-mode does not store previous document versions, the edit is only
   4373 applied if the version of the textDocument matches the version of the
   4374 corresponding file.
   4375 
   4376 interface TextDocumentEdit {
   4377   textDocument: VersionedTextDocumentIdentifier;
   4378   edits: TextEdit[];
   4379 }"
   4380   (pcase (lsp:edit-kind edit)
   4381     ("create" (-let* (((&CreateFile :uri :options?) edit)
   4382                       (file-name (lsp--uri-to-path uri)))
   4383                 (mkdir (f-dirname file-name) t)
   4384                 (f-touch file-name)
   4385                 (when (lsp:create-file-options-overwrite? options?)
   4386                   (f-write-text "" nil file-name))
   4387                 (find-file-noselect file-name)))
   4388     ("delete" (-let (((&DeleteFile :uri :options? (&DeleteFileOptions? :recursive?)) edit))
   4389                 (f-delete (lsp--uri-to-path uri) recursive?)))
   4390     ("rename" (-let* (((&RenameFile :old-uri :new-uri :options? (&RenameFileOptions? :overwrite?)) edit)
   4391                       (old-file-name (lsp--uri-to-path old-uri))
   4392                       (new-file-name (lsp--uri-to-path new-uri))
   4393                       (buf (find-buffer-visiting old-file-name)))
   4394                 (when buf
   4395                   (lsp-with-current-buffer buf
   4396                     (save-buffer)
   4397                     (lsp--text-document-did-close)))
   4398                 (mkdir (f-dirname new-file-name) t)
   4399                 (rename-file old-file-name new-file-name overwrite?)
   4400                 (when buf
   4401                   (lsp-with-current-buffer buf
   4402                     (set-buffer-modified-p nil)
   4403                     (setq lsp-buffer-uri nil)
   4404                     (set-visited-file-name new-file-name)
   4405                     (lsp)))))
   4406     (_ (let ((file-name (->> edit
   4407                              (lsp:text-document-edit-text-document)
   4408                              (lsp:versioned-text-document-identifier-uri)
   4409                              (lsp--uri-to-path))))
   4410          (lsp-with-current-buffer (find-buffer-visiting file-name)
   4411            (lsp-with-filename file-name
   4412              (lsp--apply-text-edits (lsp:text-document-edit-edits edit) operation)))))))
   4413 
   4414 (lsp-defun lsp--position-compare ((&Position :line left-line
   4415                                              :character left-character)
   4416                                   (&Position :line right-line
   4417                                              :character right-character))
   4418   "Return t if position LEFT is greater than RIGHT."
   4419   (if (= left-line right-line)
   4420       (> left-character right-character)
   4421     (> left-line right-line)))
   4422 
   4423 (lsp-defun lsp-point-in-range? (position (&Range :start :end))
   4424   "Returns if POINT is in RANGE."
   4425   (not (or (lsp--position-compare start position)
   4426            (lsp--position-compare position end))))
   4427 
   4428 (lsp-defun lsp--position-equal ((&Position :line left-line
   4429                                            :character left-character)
   4430                                 (&Position :line right-line
   4431                                            :character right-character))
   4432   "Return whether LEFT and RIGHT positions are equal."
   4433   (and (= left-line right-line)
   4434        (= left-character right-character)))
   4435 
   4436 (lsp-defun lsp--text-edit-sort-predicate ((&TextEdit :range (&Range :start left-start :end left-end))
   4437                                           (&TextEdit :range (&Range :start right-start :end right-end)))
   4438   (if (lsp--position-equal left-start right-start)
   4439       (lsp--position-compare left-end right-end)
   4440     (lsp--position-compare left-start right-start)))
   4441 
   4442 (lsp-defun lsp--apply-text-edit ((edit &as &TextEdit :range (&RangeToPoint :start :end) :new-text))
   4443   "Apply the edits described in the TextEdit object in TEXT-EDIT."
   4444   (setq new-text (s-replace "\r" "" (or new-text "")))
   4445   (lsp:set-text-edit-new-text edit new-text)
   4446   (goto-char start)
   4447   (delete-region start end)
   4448   (insert new-text))
   4449 
   4450 ;; WORKAROUND: typescript-language might send -1 when applying code actions.
   4451 ;; see https://github.com/emacs-lsp/lsp-mode/issues/1582
   4452 (lsp-defun lsp--fix-point ((point &as &Position :character :line))
   4453   (-doto point
   4454     (lsp:set-position-line (max 0 line))
   4455     (lsp:set-position-character (max 0 character))))
   4456 
   4457 (lsp-defun lsp--apply-text-edit-replace-buffer-contents ((edit &as
   4458                                                                &TextEdit
   4459                                                                :range (&Range :start :end)
   4460                                                                :new-text))
   4461   "Apply the edits described in the TextEdit object in TEXT-EDIT.
   4462 The method uses `replace-buffer-contents'."
   4463   (setq new-text (s-replace "\r" "" (or new-text "")))
   4464   (lsp:set-text-edit-new-text edit new-text)
   4465   (-let* ((source (current-buffer))
   4466           ((beg . end) (lsp--range-to-region (lsp-make-range :start (lsp--fix-point start)
   4467                                                              :end (lsp--fix-point end)))))
   4468     (with-temp-buffer
   4469       (insert new-text)
   4470       (let ((temp (current-buffer)))
   4471         (with-current-buffer source
   4472           (save-excursion
   4473             (save-restriction
   4474               (narrow-to-region beg end)
   4475 
   4476               ;; On emacs versions < 26.2,
   4477               ;; `replace-buffer-contents' is buggy - it calls
   4478               ;; change functions with invalid arguments - so we
   4479               ;; manually call the change functions here.
   4480               ;;
   4481               ;; See emacs bugs #32237, #32278:
   4482               ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32237
   4483               ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32278
   4484               (let ((inhibit-modification-hooks t)
   4485                     (length (- end beg)))
   4486                 (run-hook-with-args 'before-change-functions
   4487                                     beg end)
   4488                 (replace-buffer-contents temp)
   4489                 (run-hook-with-args 'after-change-functions
   4490                                     beg (+ beg (length new-text))
   4491                                     length)))))))))
   4492 
   4493 (defun lsp--to-yasnippet-snippet (snippet)
   4494   "Convert LSP SNIPPET to yasnippet snippet."
   4495   ;; LSP snippet doesn't escape "{" and "`", but yasnippet requires escaping it.
   4496   (replace-regexp-in-string (rx (or bos (not (any "$" "\\"))) (group (or "{" "`")))
   4497                             (rx "\\" (backref 1))
   4498                             snippet
   4499                             nil nil 1))
   4500 
   4501 (defvar-local lsp-enable-relative-indentation nil
   4502   "Enable relative indentation when insert texts, snippets ...
   4503 from language server.")
   4504 
   4505 (defun lsp--expand-snippet (snippet &optional start end expand-env)
   4506   "Wrapper of `yas-expand-snippet' with all of it arguments.
   4507 The snippet will be convert to LSP style and indent according to
   4508 LSP server result."
   4509   (require 'yasnippet nil t)
   4510   (let* ((inhibit-field-text-motion t)
   4511          (yas-wrap-around-region nil)
   4512          (yas-indent-line 'none)
   4513          (yas-also-auto-indent-first-line nil))
   4514     (yas-expand-snippet
   4515      (lsp--to-yasnippet-snippet snippet)
   4516      start end expand-env)))
   4517 
   4518 (defun lsp--indent-lines (start end &optional insert-text-mode?)
   4519   "Indent from START to END based on INSERT-TEXT-MODE? value.
   4520 - When INSERT-TEXT-MODE? is provided
   4521   - if it's `lsp/insert-text-mode-as-it', do no editor indentation.
   4522   - if it's `lsp/insert-text-mode-adjust-indentation', adjust leading
   4523     whitespaces to match the line where text is inserted.
   4524 - When it's not provided, using `indent-line-function' for each line."
   4525   (save-excursion
   4526     (goto-char end)
   4527     (let* ((end-line (line-number-at-pos))
   4528            (offset (save-excursion
   4529                      (goto-char start)
   4530                      (current-indentation)))
   4531            (indent-line-function
   4532             (cond ((equal insert-text-mode? lsp/insert-text-mode-as-it)
   4533                    #'ignore)
   4534                   ((or (equal insert-text-mode? lsp/insert-text-mode-adjust-indentation)
   4535                        lsp-enable-relative-indentation
   4536                        ;; Indenting snippets is extremely slow in `org-mode' buffers
   4537                        ;; since it has to calculate indentation based on SRC block
   4538                        ;; position.  Thus we use relative indentation as default.
   4539                        (derived-mode-p 'org-mode))
   4540                    (lambda () (save-excursion
   4541                                 (beginning-of-line)
   4542                                 (indent-to-column offset))))
   4543                   (t indent-line-function))))
   4544       (goto-char start)
   4545       (forward-line)
   4546       (while (and (not (eobp))
   4547                   (<= (line-number-at-pos) end-line))
   4548         (funcall indent-line-function)
   4549         (forward-line)))))
   4550 
   4551 (defun lsp--apply-text-edits (edits &optional operation)
   4552   "Apply the EDITS described in the TextEdit[] object.
   4553 OPERATION is symbol representing the source of this text edit."
   4554   (unless (seq-empty-p edits)
   4555     (atomic-change-group
   4556       (run-hooks 'lsp-before-apply-edits-hook)
   4557       (let* ((change-group (prepare-change-group))
   4558              (howmany (length edits))
   4559              (message (format "Applying %s edits to `%s' ..." howmany (current-buffer)))
   4560              (_ (lsp--info message))
   4561              (reporter (make-progress-reporter message 0 howmany))
   4562              (done 0)
   4563              (apply-edit (if (not lsp--virtual-buffer)
   4564                              #'lsp--apply-text-edit-replace-buffer-contents
   4565                            #'lsp--apply-text-edit)))
   4566         (unwind-protect
   4567             (->> edits
   4568                  ;; We sort text edits so as to apply edits that modify latter
   4569                  ;; parts of the document first. Furthermore, because the LSP
   4570                  ;; spec dictates that: "If multiple inserts have the same
   4571                  ;; position, the order in the array defines which edit to
   4572                  ;; apply first."  We reverse the initial list and sort stably
   4573                  ;; to make sure the order among edits with the same position
   4574                  ;; is preserved.
   4575                  (nreverse)
   4576                  (seq-sort #'lsp--text-edit-sort-predicate)
   4577                  (mapc (lambda (edit)
   4578                          (progress-reporter-update reporter (cl-incf done))
   4579                          (funcall apply-edit edit)
   4580                          (when (lsp:snippet-text-edit-insert-text-format? edit)
   4581                            (-when-let ((&SnippetTextEdit :range (&RangeToPoint :start)
   4582                                                          :insert-text-format? :new-text) edit)
   4583                              (when (eq insert-text-format? lsp/insert-text-format-snippet)
   4584                                ;; No `save-excursion' needed since expand snippet will change point anyway
   4585                                (goto-char (+ start (length new-text)))
   4586                                (lsp--indent-lines start (point))
   4587                                (lsp--expand-snippet new-text start (point)))))
   4588                          (run-hook-with-args 'lsp-after-apply-edits-hook operation))))
   4589           (undo-amalgamate-change-group change-group)
   4590           (progress-reporter-done reporter))))))
   4591 
   4592 (defun lsp--create-apply-text-edits-handlers ()
   4593   "Create (handler cleanup-fn) for applying text edits in async request.
   4594 Only works when mode is `tick or `alive."
   4595   (let* (first-edited
   4596          (func (lambda (start &rest _)
   4597                  (setq first-edited (if first-edited
   4598                                         (min start first-edited)
   4599                                       start)))))
   4600     (add-hook 'before-change-functions func nil t)
   4601     (list
   4602      (lambda (edits)
   4603        (if (and first-edited
   4604                 (seq-find (-lambda ((&TextEdit :range (&RangeToPoint :end)))
   4605                             ;; Text edit region is overlapped
   4606                             (> end first-edited))
   4607                           edits))
   4608            (lsp--warn "TextEdits will not be applied since document has been modified before of them.")
   4609          (lsp--apply-text-edits edits 'completion-cleanup)))
   4610      (lambda ()
   4611        (remove-hook 'before-change-functions func t)))))
   4612 
   4613 (defun lsp--capability (cap &optional capabilities)
   4614   "Get the value of capability CAP.  If CAPABILITIES is non-nil, use them instead."
   4615   (when (stringp cap)
   4616     (setq cap (intern (concat ":" cap))))
   4617 
   4618   (lsp-get (or capabilities
   4619                (lsp--server-capabilities))
   4620            cap))
   4621 
   4622 (defun lsp--registered-capability (method)
   4623   "Check whether there is workspace providing METHOD."
   4624   (->> (lsp-workspaces)
   4625        (--keep (seq-find (lambda (reg)
   4626                            (equal (lsp--registered-capability-method reg) method))
   4627                          (lsp--workspace-registered-server-capabilities it)))
   4628        cl-first))
   4629 
   4630 (defun lsp--capability-for-method (method)
   4631   "Get the value of capability for METHOD."
   4632   (-let* ((reqs (cdr (assoc method lsp-method-requirements)))
   4633           ((&plist :capability) reqs))
   4634     (or (and capability (lsp--capability capability))
   4635         (-some-> (lsp--registered-capability method)
   4636           (lsp--registered-capability-options)))))
   4637 
   4638 (defvar-local lsp--before-change-vals nil
   4639   "Store the positions from the `lsp-before-change' function call, for
   4640 validation and use in the `lsp-on-change' function.")
   4641 
   4642 (defun lsp--text-document-content-change-event (start end length)
   4643   "Make a TextDocumentContentChangeEvent body for START to END, of length LENGTH."
   4644   ;; So (47 54 0) means add    7 chars starting at pos 47
   4645   ;; must become
   4646   ;;   {"range":{"start":{"line":5,"character":6}
   4647   ;;             ,"end" :{"line":5,"character":6}}
   4648   ;;             ,"rangeLength":0
   4649   ;;             ,"text":"\nbb = 5"}
   4650   ;;
   4651   ;; And (47 47 7) means delete 7 chars starting at pos 47
   4652   ;; must become
   4653   ;;   {"range":{"start":{"line":6,"character":0}
   4654   ;;            ,"end"  :{"line":7,"character":0}}
   4655   ;;            ,"rangeLength":7
   4656   ;;            ,"text":""}
   4657   ;;
   4658   ;; (208 221 3) means delete 3 chars starting at pos 208, and replace them with
   4659   ;; 13 chars. So it must become
   4660   ;;   {"range":{"start":{"line":5,"character":8}
   4661   ;;             ,"end" :{"line":5,"character":11}}
   4662   ;;             ,"rangeLength":3
   4663   ;;             ,"text":"new-chars-xxx"}
   4664   ;;
   4665 
   4666   ;; Adding text:
   4667   ;;   lsp-before-change:(start,end)=(33,33)
   4668   ;;   lsp-on-change:(start,end,length)=(33,34,0)
   4669   ;;
   4670   ;; Changing text:
   4671   ;;   lsp-before-change:(start,end)=(208,211)
   4672   ;;   lsp-on-change:(start,end,length)=(208,221,3)
   4673   ;;
   4674   ;; Deleting text:
   4675   ;;   lsp-before-change:(start,end)=(19,27)
   4676   ;;   lsp-on-change:(start,end,length)=(19,19,8)
   4677   (if (zerop length)
   4678       ;; Adding something only, work from start only
   4679       `( :range ,(lsp--range
   4680                   (lsp--point-to-position start)
   4681                   (lsp--point-to-position start))
   4682          :rangeLength 0
   4683          :text ,(buffer-substring-no-properties start end))
   4684 
   4685     (if (eq start end)
   4686         ;; Deleting something only
   4687         (if (lsp--bracketed-change-p start length)
   4688             ;; The before-change value is bracketed, use it
   4689             `( :range ,(lsp--range
   4690                         (lsp--point-to-position start)
   4691                         (plist-get lsp--before-change-vals :end-pos))
   4692                :rangeLength ,length
   4693                :text "")
   4694           ;; If the change is not bracketed, send a full change event instead.
   4695           (lsp--full-change-event))
   4696 
   4697       ;; Deleting some things, adding others
   4698       (if (lsp--bracketed-change-p start length)
   4699           ;; The before-change value is valid, use it
   4700           `( :range ,(lsp--range
   4701                       (lsp--point-to-position start)
   4702                       (plist-get lsp--before-change-vals :end-pos))
   4703              :rangeLength ,length
   4704              :text ,(buffer-substring-no-properties start end))
   4705         (lsp--full-change-event)))))
   4706 
   4707 (defun lsp--bracketed-change-p (start length)
   4708   "If the before and after positions are the same, and the length
   4709 is the size of the start range, we are probably good."
   4710   (-let [(&plist :end before-end :start before-start) lsp--before-change-vals]
   4711     (and (eq start before-start)
   4712          (eq length (- before-end before-start)))))
   4713 
   4714 (defun lsp--full-change-event ()
   4715   `(:text ,(lsp--buffer-content)))
   4716 
   4717 (defun lsp-before-change (start end)
   4718   "Executed before a file is changed.
   4719 Added to `before-change-functions'."
   4720   ;; Note:
   4721   ;;
   4722   ;; This variable holds a list of functions to call when Emacs is about to
   4723   ;; modify a buffer. Each function gets two arguments, the beginning and end of
   4724   ;; the region that is about to change, represented as integers. The buffer
   4725   ;; that is about to change is always the current buffer when the function is
   4726   ;; called.
   4727   ;;
   4728   ;; WARNING:
   4729   ;;
   4730   ;; Do not expect the before-change hooks and the after-change hooks be called
   4731   ;; in balanced pairs around each buffer change. Also don't expect the
   4732   ;; before-change hooks to be called for every chunk of text Emacs is about to
   4733   ;; delete. These hooks are provided on the assumption that Lisp programs will
   4734   ;; use either before- or the after-change hooks, but not both, and the
   4735   ;; boundaries of the region where the changes happen might include more than
   4736   ;; just the actual changed text, or even lump together several changes done
   4737   ;; piecemeal.
   4738   (save-match-data
   4739     (lsp-save-restriction-and-excursion
   4740       (setq lsp--before-change-vals
   4741             (list :start start
   4742                   :end end
   4743                   :end-pos (lsp--point-to-position end))))))
   4744 
   4745 (defun lsp--flush-delayed-changes ()
   4746   (let ((inhibit-quit t))
   4747     (when lsp--delay-timer
   4748       (cancel-timer lsp--delay-timer))
   4749     (mapc (-lambda ((workspace buffer document change))
   4750             (with-current-buffer buffer
   4751               (with-lsp-workspace workspace
   4752                 (lsp-notify "textDocument/didChange"
   4753                             (list :textDocument document
   4754                                   :contentChanges (vector change))))))
   4755           (prog1 (nreverse lsp--delayed-requests)
   4756             (setq lsp--delayed-requests nil)))))
   4757 
   4758 (defun lsp--workspace-sync-method (workspace)
   4759   (let ((sync (-> workspace
   4760                   (lsp--workspace-server-capabilities)
   4761                   (lsp:server-capabilities-text-document-sync?))))
   4762     (if (lsp-text-document-sync-options? sync)
   4763         (lsp:text-document-sync-options-change? sync)
   4764       sync)))
   4765 
   4766 (defun lsp-on-change (start end length &optional content-change-event-fn)
   4767   "Executed when a file is changed.
   4768 Added to `after-change-functions'."
   4769   ;; Note:
   4770   ;;
   4771   ;; Each function receives three arguments: the beginning and end of the region
   4772   ;; just changed, and the length of the text that existed before the change.
   4773   ;; All three arguments are integers. The buffer that has been changed is
   4774   ;; always the current buffer when the function is called.
   4775   ;;
   4776   ;; The length of the old text is the difference between the buffer positions
   4777   ;; before and after that text as it was before the change. As for the
   4778   ;; changed text, its length is simply the difference between the first two
   4779   ;; arguments.
   4780   ;;
   4781   ;; So (47 54 0) means add    7 chars starting at pos 47
   4782   ;; So (47 47 7) means delete 7 chars starting at pos 47
   4783   (save-match-data
   4784     (let ((inhibit-quit t)
   4785           ;; make sure that `lsp-on-change' is called in multi-workspace context
   4786           ;; see #2901
   4787           lsp--cur-workspace)
   4788       ;; A (revert-buffer) call with the 'preserve-modes parameter (eg, as done
   4789       ;; by auto-revert-mode) will cause this handler to get called with a nil
   4790       ;; buffer-file-name. We need the buffer-file-name to send notifications;
   4791       ;; so we skip handling revert-buffer-caused changes and instead handle
   4792       ;; reverts separately in lsp-on-revert
   4793       (when (not revert-buffer-in-progress-p)
   4794         (cl-incf lsp--cur-version)
   4795         (mapc
   4796          (lambda (workspace)
   4797            (pcase (or lsp-document-sync-method
   4798                       (lsp--workspace-sync-method workspace))
   4799              (1
   4800               (if lsp-debounce-full-sync-notifications
   4801                   (setq lsp--delayed-requests
   4802                         (->> lsp--delayed-requests
   4803                              (-remove (-lambda ((_ buffer))
   4804                                         (equal (current-buffer) buffer)))
   4805                              (cons (list workspace
   4806                                          (current-buffer)
   4807                                          (lsp--versioned-text-document-identifier)
   4808                                          (lsp--full-change-event)))))
   4809                 (with-lsp-workspace workspace
   4810                   (lsp-notify "textDocument/didChange"
   4811                               (list :contentChanges (vector (lsp--full-change-event))
   4812                                     :textDocument (lsp--versioned-text-document-identifier))))))
   4813              (2
   4814               (with-lsp-workspace workspace
   4815                 (lsp-notify
   4816                  "textDocument/didChange"
   4817                  (list :textDocument (lsp--versioned-text-document-identifier)
   4818                        :contentChanges (vector
   4819                                         (if content-change-event-fn
   4820                                             (funcall content-change-event-fn start end length)
   4821                                           (lsp--text-document-content-change-event
   4822                                            start end length)))))))))
   4823          (lsp-workspaces))
   4824         (when lsp--delay-timer (cancel-timer lsp--delay-timer))
   4825         (setq lsp--delay-timer (run-with-idle-timer
   4826                                 lsp-debounce-full-sync-notifications-interval
   4827                                 nil
   4828                                 #'lsp--flush-delayed-changes))
   4829         ;; force cleanup overlays after each change
   4830         (lsp--remove-overlays 'lsp-highlight)
   4831         (lsp--after-change (current-buffer))
   4832         (setq lsp--signature-last-index nil
   4833               lsp--signature-last nil)
   4834         ;; cleanup diagnostics
   4835         (when lsp-diagnostic-clean-after-change
   4836           (lsp-foreach-workspace
   4837            (-let [diagnostics (lsp--workspace-diagnostics lsp--cur-workspace)]
   4838              (remhash (lsp--fix-path-casing (buffer-file-name)) diagnostics))))))))
   4839 
   4840 
   4841 
   4842 ;; facilities for on change hooks. We do not want to make lsp calls on each
   4843 ;; change event so we add debounce to avoid flooding the server with events.
   4844 ;; Additionally, we want to have a mechanism for stopping the server calls in
   4845 ;; particular cases like, e. g. when performing completion.
   4846 
   4847 (defvar lsp-inhibit-lsp-hooks nil
   4848   "Flag to control.")
   4849 
   4850 (defcustom lsp-on-change-hook nil
   4851   "Hooks to run when buffer has changed."
   4852   :type 'hook
   4853   :group 'lsp-mode)
   4854 
   4855 (defcustom lsp-idle-delay 0.500
   4856   "Debounce interval for `after-change-functions'."
   4857   :type 'number
   4858   :group 'lsp-mode)
   4859 
   4860 (defcustom lsp-on-idle-hook nil
   4861   "Hooks to run after `lsp-idle-delay'."
   4862   :type 'hook
   4863   :group 'lsp-mode)
   4864 
   4865 (defun lsp--idle-reschedule (buffer)
   4866   (when lsp--on-idle-timer
   4867     (cancel-timer lsp--on-idle-timer))
   4868 
   4869   (setq lsp--on-idle-timer (run-with-idle-timer
   4870                             lsp-idle-delay
   4871                             nil
   4872                             #'lsp--on-idle
   4873                             buffer)))
   4874 
   4875 (defun lsp--post-command ()
   4876   (lsp--cleanup-highlights-if-needed)
   4877   (lsp--idle-reschedule (current-buffer)))
   4878 
   4879 (defun lsp--on-idle (buffer)
   4880   "Start post command loop."
   4881   (when (and (buffer-live-p buffer)
   4882              (equal buffer (current-buffer))
   4883              (not lsp-inhibit-lsp-hooks)
   4884              lsp-managed-mode)
   4885     (run-hooks 'lsp-on-idle-hook)))
   4886 
   4887 (defun lsp--on-change-debounce (buffer)
   4888   (when (and (buffer-live-p buffer)
   4889              (equal buffer (current-buffer))
   4890              (not lsp-inhibit-lsp-hooks)
   4891              lsp-managed-mode)
   4892     (run-hooks 'lsp-on-change-hook)))
   4893 
   4894 (defun lsp--after-change (buffer)
   4895   (when (fboundp 'lsp--semantic-tokens-refresh-if-enabled)
   4896     (lsp--semantic-tokens-refresh-if-enabled buffer))
   4897   (when lsp--on-change-timer
   4898     (cancel-timer lsp--on-change-timer))
   4899   (setq lsp--on-change-timer (run-with-idle-timer
   4900                               lsp-idle-delay
   4901                               nil
   4902                               #'lsp--on-change-debounce
   4903                               buffer))
   4904   (lsp--idle-reschedule buffer))
   4905 
   4906 
   4907 (defcustom lsp-trim-trailing-whitespace t
   4908   "Trim trailing whitespace on a line."
   4909   :group 'lsp-mode
   4910   :type 'boolean)
   4911 
   4912 (defcustom lsp-insert-final-newline t
   4913   "Insert a newline character at the end of the file if one does not exist."
   4914   :group 'lsp-mode
   4915   :type 'boolean)
   4916 
   4917 (defcustom lsp-trim-final-newlines t
   4918   "Trim all newlines after the final newline at the end of the file."
   4919   :group 'lsp-mode
   4920   :type 'boolean)
   4921 
   4922 
   4923 (defun lsp--on-type-formatting (first-trigger-characters more-trigger-characters)
   4924   "Self insert handling.
   4925 Applies on type formatting."
   4926   (let ((ch last-command-event))
   4927     (when (or (eq (string-to-char first-trigger-characters) ch)
   4928               (cl-find ch more-trigger-characters :key #'string-to-char))
   4929       (lsp-request-async "textDocument/onTypeFormatting"
   4930                          (lsp-make-document-on-type-formatting-params
   4931                           :text-document (lsp--text-document-identifier)
   4932                           :options (lsp-make-formatting-options
   4933                                     :tab-size (symbol-value (lsp--get-indent-width major-mode))
   4934                                     :insert-spaces (lsp-json-bool (not indent-tabs-mode))
   4935                                     :trim-trailing-whitespace? (lsp-json-bool lsp-trim-trailing-whitespace)
   4936                                     :insert-final-newline? (lsp-json-bool lsp-insert-final-newline)
   4937                                     :trim-final-newlines? (lsp-json-bool lsp-trim-final-newlines))
   4938                           :ch (char-to-string ch)
   4939                           :position (lsp--cur-position))
   4940                          (lambda (data) (lsp--apply-text-edits data 'format))
   4941                          :mode 'tick))))
   4942 
   4943 
   4944 ;; links
   4945 (defun lsp--document-links ()
   4946   (when (lsp-feature? "textDocument/documentLink")
   4947     (lsp-request-async
   4948      "textDocument/documentLink"
   4949      `(:textDocument ,(lsp--text-document-identifier))
   4950      (lambda (links)
   4951        (lsp--remove-overlays 'lsp-link)
   4952        (seq-do
   4953         (-lambda ((link &as &DocumentLink :range (&Range :start :end)))
   4954           (-doto (make-button (lsp--position-to-point start)
   4955                               (lsp--position-to-point end)
   4956                               'action (lsp--document-link-keymap link)
   4957                               'keymap (let ((map (make-sparse-keymap)))
   4958                                         (define-key map [M-return] 'push-button)
   4959                                         (define-key map [mouse-2] 'push-button)
   4960                                         map)
   4961                               'help-echo "mouse-2, M-RET: Visit this link")
   4962             (overlay-put 'lsp-link t)))
   4963         links))
   4964      :mode 'unchanged)))
   4965 
   4966 (defun lsp--document-link-handle-target (url)
   4967   (let* ((parsed-url (url-generic-parse-url (url-unhex-string url)))
   4968          (type (url-type parsed-url)))
   4969     (pcase type
   4970       ("file"
   4971        (xref-push-marker-stack)
   4972        (find-file (lsp--uri-to-path url))
   4973        (-when-let ((_ line column) (s-match (rx "#" (group (1+ num)) (or "," "#") (group (1+ num))) url))
   4974          (goto-char (lsp--position-to-point
   4975                      (lsp-make-position :character (1- (string-to-number column))
   4976                                         :line (1- (string-to-number line)))))))
   4977       ((or "http" "https") (browse-url url))
   4978       (type (if-let ((handler (lsp--get-uri-handler type)))
   4979                 (funcall handler url)
   4980               (signal 'lsp-file-scheme-not-supported (list url)))))))
   4981 
   4982 (lsp-defun lsp--document-link-keymap ((link &as &DocumentLink :target?))
   4983   (if target?
   4984       (lambda (_)
   4985         (interactive)
   4986         (lsp--document-link-handle-target target?))
   4987     (lambda (_)
   4988       (interactive)
   4989       (when (lsp:document-link-registration-options-resolve-provider?
   4990              (lsp--capability-for-method "textDocument/documentLink"))
   4991         (lsp-request-async
   4992          "documentLink/resolve"
   4993          link
   4994          (-lambda ((&DocumentLink :target?))
   4995            (lsp--document-link-handle-target target?)))))))
   4996 
   4997 
   4998 
   4999 (defcustom lsp-warn-no-matched-clients t
   5000   "Whether to show messages when there are no supported clients."
   5001   :group 'lsp-mode
   5002   :type 'boolean)
   5003 
   5004 (defun lsp-buffer-language--configured-id ()
   5005   "Return nil when not registered."
   5006   (->> lsp-language-id-configuration
   5007        (-first
   5008         (-lambda ((mode-or-pattern . language))
   5009           (cond
   5010            ((and (stringp mode-or-pattern)
   5011                  (s-matches? mode-or-pattern (buffer-file-name)))
   5012             language)
   5013            ((eq mode-or-pattern major-mode) language))))
   5014        cl-rest))
   5015 
   5016 (defvar-local lsp--buffer-language nil
   5017   "Locally cached returned value of `lsp-buffer-language'.")
   5018 
   5019 (defun lsp-buffer-language ()
   5020   "Get language corresponding current buffer."
   5021   (or lsp--buffer-language
   5022       (let* ((configured-language (lsp-buffer-language--configured-id)))
   5023         (setq lsp--buffer-language
   5024               (or configured-language
   5025                   ;; ensure non-nil
   5026                   (string-remove-suffix "-mode" (symbol-name major-mode))))
   5027         (when (and lsp-warn-no-matched-clients
   5028                    (null configured-language))
   5029           (lsp-warn "Unable to calculate the languageId for buffer `%s'. \
   5030 Take a look at `lsp-language-id-configuration'. The `major-mode' is %s"
   5031                     (buffer-name)
   5032                     major-mode))
   5033         lsp--buffer-language)))
   5034 
   5035 (defun lsp-activate-on (&rest languages)
   5036   "Returns language activation function.
   5037 The function will return t when the `lsp-buffer-language' returns
   5038 one of the LANGUAGES."
   5039   (lambda (_file-name _mode)
   5040     (-contains? languages (lsp-buffer-language))))
   5041 
   5042 (defun lsp-workspace-root (&optional path)
   5043   "Find the workspace root for the current file or PATH."
   5044   (-when-let* ((file-name (or path (buffer-file-name)))
   5045                (file-name (lsp-f-canonical file-name)))
   5046     (->> (lsp-session)
   5047          (lsp-session-folders)
   5048          (--filter (and (lsp--files-same-host it file-name)
   5049                         (or (lsp-f-ancestor-of? it file-name)
   5050                             (equal it file-name))))
   5051          (--max-by (> (length it) (length other))))))
   5052 
   5053 (defun lsp-on-revert ()
   5054   "Executed when a file is reverted.
   5055 Added to `after-revert-hook'."
   5056   (let ((n (buffer-size))
   5057         (revert-buffer-in-progress-p nil))
   5058     (lsp-on-change 0 n n)))
   5059 
   5060 (defun lsp--text-document-did-close (&optional keep-workspace-alive)
   5061   "Executed when the file is closed, added to `kill-buffer-hook'.
   5062 
   5063 If KEEP-WORKSPACE-ALIVE is non-nil, do not shutdown the workspace
   5064 if it's closing the last buffer in the workspace."
   5065   (lsp-foreach-workspace
   5066    (cl-callf2 delq (lsp-current-buffer) (lsp--workspace-buffers lsp--cur-workspace))
   5067    (with-demoted-errors "Error sending didClose notification in ‘lsp--text-document-did-close’: %S"
   5068      (lsp-notify "textDocument/didClose"
   5069                  `(:textDocument ,(lsp--text-document-identifier))))
   5070    (when (and (not lsp-keep-workspace-alive)
   5071               (not keep-workspace-alive)
   5072               (not (lsp--workspace-buffers lsp--cur-workspace)))
   5073      (lsp--shutdown-workspace))))
   5074 
   5075 (defun lsp--will-save-text-document-params (reason)
   5076   (list :textDocument (lsp--text-document-identifier)
   5077         :reason reason))
   5078 
   5079 (defun lsp--before-save ()
   5080   "Before save handler."
   5081   (with-demoted-errors "Error in ‘lsp--before-save’: %S"
   5082     (let ((params (lsp--will-save-text-document-params 1)))
   5083       (when (lsp--send-will-save-p)
   5084         (lsp-notify "textDocument/willSave" params))
   5085       (when (and (lsp--send-will-save-wait-until-p) lsp-before-save-edits)
   5086         (let ((lsp-response-timeout 0.1))
   5087           (condition-case nil
   5088               (lsp--apply-text-edits
   5089                (lsp-request "textDocument/willSaveWaitUntil"
   5090                             params)
   5091                'before-save)
   5092             (error)))))))
   5093 
   5094 (defun lsp--on-auto-save ()
   5095   "Handler for auto-save."
   5096   (when (lsp--send-will-save-p)
   5097     (with-demoted-errors "Error in ‘lsp--on-auto-save’: %S"
   5098       (lsp-notify "textDocument/willSave" (lsp--will-save-text-document-params 2)))))
   5099 
   5100 (defun lsp--text-document-did-save ()
   5101   "Executed when the file is closed, added to `after-save-hook''."
   5102   (when (lsp--send-did-save-p)
   5103     (with-demoted-errors "Error on ‘lsp--text-document-did-save: %S’"
   5104       (lsp-notify "textDocument/didSave"
   5105                   `( :textDocument ,(lsp--versioned-text-document-identifier)
   5106                      ,@(when (lsp--save-include-text-p)
   5107                          (list :text (lsp--buffer-content))))))))
   5108 
   5109 (defun lsp--text-document-position-params (&optional identifier position)
   5110   "Make TextDocumentPositionParams for the current point in the current document.
   5111 If IDENTIFIER and POSITION are non-nil, they will be used as the document
   5112 identifier and the position respectively."
   5113   (list :textDocument (or identifier (lsp--text-document-identifier))
   5114         :position (or position (lsp--cur-position))))
   5115 
   5116 (defun lsp--get-buffer-diagnostics ()
   5117   "Return buffer diagnostics."
   5118   (gethash (or
   5119             (plist-get lsp--virtual-buffer :buffer-file-name)
   5120             (lsp--fix-path-casing (buffer-file-name)))
   5121            (lsp-diagnostics t)))
   5122 
   5123 (defun lsp-cur-line-diagnostics ()
   5124   "Return any diagnostics that apply to the current line."
   5125   (-let [(&plist :start (&plist :line start) :end (&plist :line end)) (lsp--region-or-line)]
   5126     (cl-coerce (-filter
   5127                 (-lambda ((&Diagnostic :range (&Range :start (&Position :line))))
   5128                   (and (>= line start) (<= line end)))
   5129                 (lsp--get-buffer-diagnostics))
   5130                'vector)))
   5131 
   5132 (lsp-defun lsp-range-overlapping?((left &as &Range :start left-start :end left-end)
   5133                                   (right &as &Range :start right-start :end right-end))
   5134   (or (lsp-point-in-range? right-start left)
   5135       (lsp-point-in-range? right-end left)
   5136       (lsp-point-in-range? left-start right)
   5137       (lsp-point-in-range? left-end right)))
   5138 
   5139 (defun lsp-make-position-1 (position)
   5140   (lsp-make-position :line (plist-get position :line)
   5141                      :character (plist-get position :character)))
   5142 
   5143 (defun lsp-cur-possition-diagnostics ()
   5144   "Return any diagnostics that apply to the current line."
   5145   (-let* ((start (if (use-region-p) (region-beginning) (point)))
   5146           (end (if (use-region-p) (region-end) (point)))
   5147           (current-range (lsp-make-range :start (lsp-make-position-1 (lsp-point-to-position start))
   5148                                          :end (lsp-make-position-1 (lsp-point-to-position end)))))
   5149     (->> (lsp--get-buffer-diagnostics)
   5150          (-filter
   5151           (-lambda ((&Diagnostic :range))
   5152             (lsp-range-overlapping? range current-range)))
   5153          (apply 'vector))))
   5154 
   5155 (defalias 'lsp--cur-line-diagnotics 'lsp-cur-line-diagnostics)
   5156 
   5157 (defun lsp--extract-line-from-buffer (pos)
   5158   "Return the line pointed to by POS (a Position object) in the current buffer."
   5159   (let* ((point (lsp--position-to-point pos))
   5160          (inhibit-field-text-motion t))
   5161     (save-excursion
   5162       (goto-char point)
   5163       (buffer-substring (line-beginning-position) (line-end-position)))))
   5164 
   5165 (lsp-defun lsp--xref-make-item (filename (&Range :start (start &as &Position :character start-char :line start-line)
   5166                                                  :end (end &as &Position :character end-char)))
   5167   "Return a xref-item from a RANGE in FILENAME."
   5168   (let* ((line (lsp--extract-line-from-buffer start))
   5169          (len (length line)))
   5170     (add-face-text-property (max (min start-char len) 0)
   5171                             (max (min end-char len) 0)
   5172                             'xref-match t line)
   5173     ;; LINE is nil when FILENAME is not being current visited by any buffer.
   5174     (xref-make-match (or line filename)
   5175                      (xref-make-file-location
   5176                       filename
   5177                       (lsp-translate-line (1+ start-line))
   5178                       (lsp-translate-column start-char))
   5179                      (- end-char start-char))))
   5180 
   5181 (defun lsp--location-uri (loc)
   5182   (if (lsp-location? loc)
   5183       (lsp:location-uri loc)
   5184     (lsp:location-link-target-uri loc)))
   5185 
   5186 (lsp-defun lsp-goto-location ((loc &as &Location :uri :range (&Range :start)))
   5187   "Go to location."
   5188   (let ((path (lsp--uri-to-path uri)))
   5189     (if (f-exists? path)
   5190         (with-current-buffer (find-file path)
   5191           (goto-char (lsp--position-to-point start)))
   5192       (error "There is no file %s" path))))
   5193 
   5194 (defun lsp--location-range (loc)
   5195   (if (lsp-location? loc)
   5196       (lsp:location-range loc)
   5197     (lsp:location-link-target-selection-range loc)))
   5198 
   5199 (defun lsp--locations-to-xref-items (locations)
   5200   "Return a list of `xref-item' given LOCATIONS, which can be of
   5201 type Location, LocationLink, Location[] or LocationLink[]."
   5202   (setq locations
   5203         (pcase locations
   5204           ((seq (or (Location)
   5205                     (LocationLink)))
   5206            (append locations nil))
   5207           ((or (Location)
   5208                (LocationLink))
   5209            (list locations))))
   5210 
   5211   (cl-labels ((get-xrefs-in-file
   5212                (file-locs)
   5213                (-let [(filename . matches) file-locs]
   5214                  (condition-case err
   5215                      (let ((visiting (find-buffer-visiting filename))
   5216                            (fn (lambda (loc)
   5217                                  (lsp-with-filename filename
   5218                                    (lsp--xref-make-item filename
   5219                                                         (lsp--location-range loc))))))
   5220                        (if visiting
   5221                            (with-current-buffer visiting
   5222                              (seq-map fn matches))
   5223                          (when (file-readable-p filename)
   5224                            (with-temp-buffer
   5225                              (insert-file-contents-literally filename)
   5226                              (seq-map fn matches)))))
   5227                    (error (lsp-warn "Failed to process xref entry for filename '%s': %s"
   5228                                     filename (error-message-string err)))
   5229                    (file-error (lsp-warn "Failed to process xref entry, file-error, '%s': %s"
   5230                                          filename (error-message-string err)))))))
   5231 
   5232     (->> locations
   5233          (seq-sort #'lsp--location-before-p)
   5234          (seq-group-by (-compose #'lsp--uri-to-path #'lsp--location-uri))
   5235          (seq-map #'get-xrefs-in-file)
   5236          (apply #'nconc))))
   5237 
   5238 (defun lsp--location-before-p (left right)
   5239   "Sort first by file, then by line, then by column."
   5240   (let ((left-uri (lsp--location-uri left))
   5241         (right-uri (lsp--location-uri right)))
   5242     (if (not (string= left-uri right-uri))
   5243         (string< left-uri right-uri)
   5244       (-let (((&Range :start left-start) (lsp--location-range left))
   5245              ((&Range :start right-start) (lsp--location-range right)))
   5246         (lsp--position-compare right-start left-start)))))
   5247 
   5248 (defun lsp--make-reference-params (&optional td-position exclude-declaration)
   5249   "Make a ReferenceParam object.
   5250 If TD-POSITION is non-nil, use it as TextDocumentPositionParams object instead.
   5251 If EXCLUDE-DECLARATION is non-nil, request the server to include declarations."
   5252   (let ((json-false :json-false))
   5253     (plist-put (or td-position (lsp--text-document-position-params))
   5254                :context `(:includeDeclaration ,(lsp-json-bool (not exclude-declaration))))))
   5255 
   5256 (defun lsp--cancel-request (id)
   5257   "Cancel request with ID in all workspaces."
   5258   (lsp-foreach-workspace
   5259    (->> lsp--cur-workspace lsp--workspace-client lsp--client-response-handlers (remhash id))
   5260    (lsp-notify "$/cancelRequest" `(:id ,id))))
   5261 
   5262 (defvar-local lsp--hover-saved-bounds nil)
   5263 
   5264 (defun lsp-eldoc-function (cb &rest _ignored)
   5265   "`lsp-mode' eldoc function to display hover info (based on `textDocument/hover')."
   5266   (if (and lsp--hover-saved-bounds
   5267            (lsp--point-in-bounds-p lsp--hover-saved-bounds))
   5268       lsp--eldoc-saved-message
   5269     (setq lsp--hover-saved-bounds nil
   5270           lsp--eldoc-saved-message nil)
   5271     (if (looking-at-p "[[:space:]\n]")
   5272         (setq lsp--eldoc-saved-message nil) ; And returns nil.
   5273       (when (and lsp-eldoc-enable-hover (lsp-feature? "textDocument/hover"))
   5274         (lsp-request-async
   5275          "textDocument/hover"
   5276          (lsp--text-document-position-params)
   5277          (-lambda ((hover &as &Hover? :range? :contents))
   5278            (setq lsp--hover-saved-bounds (when range?
   5279                                            (lsp--range-to-region range?)))
   5280            (funcall cb (setq lsp--eldoc-saved-message
   5281                              (when contents
   5282                                (lsp--render-on-hover-content
   5283                                 contents
   5284                                 lsp-eldoc-render-all)))))
   5285          :error-handler #'ignore
   5286          :mode 'tick
   5287          :cancel-token :eldoc-hover)))))
   5288 
   5289 (defun lsp--point-on-highlight? ()
   5290   (-some? (lambda (overlay)
   5291             (overlay-get overlay 'lsp-highlight))
   5292           (overlays-at (point))))
   5293 
   5294 (defun lsp--cleanup-highlights-if-needed ()
   5295   (when (and lsp-enable-symbol-highlighting
   5296              lsp--have-document-highlights
   5297              (not (lsp--point-on-highlight?)))
   5298     (lsp--remove-overlays 'lsp-highlight)
   5299     (setq lsp--have-document-highlights nil)
   5300     (lsp-cancel-request-by-token :highlights)))
   5301 
   5302 (defvar-local lsp--symbol-bounds-of-last-highlight-invocation nil
   5303   "The bounds of the symbol from which `lsp--document-highlight'
   5304   most recently requested highlights.")
   5305 
   5306 (defun lsp--document-highlight ()
   5307   (when (lsp-feature? "textDocument/documentHighlight")
   5308     (let ((curr-sym-bounds (bounds-of-thing-at-point 'symbol)))
   5309       (unless (or (looking-at-p "[[:space:]\n]")
   5310                   (not lsp-enable-symbol-highlighting)
   5311                   (and lsp--have-document-highlights
   5312                        curr-sym-bounds
   5313                        (equal curr-sym-bounds
   5314                               lsp--symbol-bounds-of-last-highlight-invocation)))
   5315         (setq lsp--symbol-bounds-of-last-highlight-invocation
   5316               curr-sym-bounds)
   5317         (lsp-request-async "textDocument/documentHighlight"
   5318                            (lsp--text-document-position-params)
   5319                            #'lsp--document-highlight-callback
   5320                            :mode 'tick
   5321                            :cancel-token :highlights)))))
   5322 
   5323 (defun lsp--help-open-link (&rest _)
   5324   "Open markdown link at point via mouse or keyboard."
   5325   (interactive "P")
   5326   (let ((buffer-list-update-hook nil))
   5327     (-let [(buffer point) (if-let* ((valid (and (listp last-input-event)
   5328                                                 (eq (car last-input-event) 'mouse-2)))
   5329                                     (event (cadr last-input-event))
   5330                                     (win (posn-window event))
   5331                                     (buffer (window-buffer win)))
   5332                               `(,buffer ,(posn-point event))
   5333                             `(,(current-buffer) ,(point)))]
   5334       (with-current-buffer buffer
   5335         (when-let* ((face (get-text-property point 'face))
   5336                     (url (or (and (eq face 'markdown-link-face)
   5337                                   (get-text-property point 'help-echo))
   5338                              (and (memq face '(markdown-url-face markdown-plain-url-face))
   5339                                   (nth 3 (markdown-link-at-pos point))))))
   5340           (lsp--document-link-handle-target url))))))
   5341 
   5342 (defvar lsp-help-mode-map
   5343   (-doto (make-sparse-keymap)
   5344     (define-key [remap markdown-follow-link-at-point] #'lsp--help-open-link))
   5345   "Keymap for `lsp-help-mode'.")
   5346 
   5347 (define-derived-mode lsp-help-mode help-mode "LspHelp"
   5348   "Major mode for displaying lsp help.")
   5349 
   5350 (defun lsp-describe-thing-at-point ()
   5351   "Display the type signature and documentation of the thing at point."
   5352   (interactive)
   5353   (let ((contents (-some->> (lsp--text-document-position-params)
   5354                     (lsp--make-request "textDocument/hover")
   5355                     (lsp--send-request)
   5356                     (lsp:hover-contents))))
   5357     (if (and contents (not (equal contents "")))
   5358         (let ((lsp-help-buf-name "*lsp-help*"))
   5359           (with-current-buffer (get-buffer-create lsp-help-buf-name)
   5360             (delay-mode-hooks
   5361               (lsp-help-mode)
   5362               (with-help-window lsp-help-buf-name
   5363                 (insert (string-trim-right (lsp--render-on-hover-content contents t)))))
   5364             (run-mode-hooks)))
   5365       (lsp--info "No content at point."))))
   5366 
   5367 (defun lsp--point-in-bounds-p (bounds)
   5368   "Return whether the current point is within BOUNDS."
   5369   (and (<= (car bounds) (point)) (< (point) (cdr bounds))))
   5370 
   5371 (defun lsp-get-renderer (language)
   5372   "Get renderer for LANGUAGE."
   5373   (lambda (str)
   5374     (lsp--render-string str language)))
   5375 
   5376 (defun lsp--setup-markdown (mode)
   5377   "Setup the ‘markdown-mode’ in the frame.
   5378 MODE is the mode used in the parent frame."
   5379   (make-local-variable 'markdown-code-lang-modes)
   5380   (dolist (mark (alist-get mode lsp-custom-markup-modes))
   5381     (add-to-list 'markdown-code-lang-modes (cons mark mode)))
   5382   (setq-local markdown-fontify-code-blocks-natively t)
   5383   (setq-local markdown-fontify-code-block-default-mode mode)
   5384   (setq-local markdown-hide-markup t)
   5385 
   5386   ;; Render some common HTML entities.
   5387   ;; This should really happen in markdown-mode instead,
   5388   ;; but it doesn't, so we do it here for now.
   5389   (setq prettify-symbols-alist
   5390         (cl-loop for i from 0 to 255
   5391                  collect (cons (format "&#x%02X;" i) i)))
   5392   (push '("&lt;" . ?<) prettify-symbols-alist)
   5393   (push '("&gt;" . ?>) prettify-symbols-alist)
   5394   (push '("&amp;" . ?&) prettify-symbols-alist)
   5395   (push '("&nbsp;" . ? ) prettify-symbols-alist)
   5396   (setq prettify-symbols-compose-predicate
   5397         (lambda (_start _end _match) t))
   5398   (prettify-symbols-mode 1))
   5399 
   5400 (defvar lsp-help-link-keymap
   5401   (let ((map (make-sparse-keymap)))
   5402     (define-key map [mouse-2] #'lsp--help-open-link)
   5403     (define-key map "\r" #'lsp--help-open-link)
   5404     map)
   5405   "Keymap active on links in *lsp-help* mode.")
   5406 
   5407 (defun lsp--fix-markdown-links ()
   5408   (let ((inhibit-read-only t)
   5409         (inhibit-modification-hooks t)
   5410         (prop))
   5411     (save-restriction
   5412       (goto-char (point-min))
   5413       (while (setq prop (markdown-find-next-prop 'face))
   5414         (let ((end (or (next-single-property-change (car prop) 'face)
   5415                        (point-max))))
   5416           (when (memq (get-text-property (car prop) 'face)
   5417                       '(markdown-link-face
   5418                         markdown-url-face
   5419                         markdown-plain-url-face))
   5420             (add-text-properties (car prop) end
   5421                                  (list 'button t
   5422                                        'category 'lsp-help-link
   5423                                        'follow-link t
   5424                                        'keymap lsp-help-link-keymap)))
   5425           (goto-char end))))))
   5426 
   5427 (defun lsp--buffer-string-visible ()
   5428   "Return visible buffer string.
   5429 Stolen from `org-copy-visible'."
   5430   (let ((temp (generate-new-buffer " *temp*"))
   5431         (beg (point-min))
   5432         (end (point-max)))
   5433     (while (/= beg end)
   5434       (when (get-char-property beg 'invisible)
   5435         (setq beg (next-single-char-property-change beg 'invisible nil end)))
   5436       (let* ((next (next-single-char-property-change beg 'invisible nil end))
   5437              (substring (buffer-substring beg next)))
   5438         (with-current-buffer temp (insert substring))
   5439         ;; (setq result (concat result substring))
   5440         (setq beg next)))
   5441     (setq deactivate-mark t)
   5442     (prog1 (with-current-buffer temp
   5443              (s-chop-suffix "\n" (buffer-string)))
   5444       (kill-buffer temp))))
   5445 
   5446 (defvar lsp-buffer-major-mode nil
   5447   "Holds the major mode when fontification function is running.
   5448 See #2588")
   5449 
   5450 (defvar view-inhibit-help-message)
   5451 
   5452 (defun lsp--render-markdown ()
   5453   "Render markdown."
   5454 
   5455   (let ((markdown-enable-math nil))
   5456     (goto-char (point-min))
   5457     (while (re-search-forward
   5458             (rx (and "\\" (group (or "\\" "`" "*" "_" ":" "/"
   5459                                      "{" "}" "[" "]" "(" ")"
   5460                                      "#" "+" "-" "." "!" "|"))))
   5461             nil t)
   5462       (replace-match (rx (backref 1))))
   5463 
   5464     ;; markdown-mode v2.3 does not yet provide gfm-view-mode
   5465     (if (fboundp 'gfm-view-mode)
   5466         (let ((view-inhibit-help-message t))
   5467           (gfm-view-mode))
   5468       (gfm-mode))
   5469 
   5470     (lsp--setup-markdown lsp-buffer-major-mode)))
   5471 
   5472 (defvar lsp--display-inline-image-alist
   5473   '((lsp--render-markdown
   5474      (:regexp
   5475       "!\\[.*?\\](data:image/[a-zA-Z]+;base64,\\([A-Za-z0-9+/\n]+?=*?\\)\\(|[^)]+\\)?)"
   5476       :sexp
   5477       (create-image
   5478        (base64-decode-string
   5479         (buffer-substring-no-properties (match-beginning 1) (match-end 1)))
   5480        nil t))))
   5481   "Replaced string regexp and function returning image.
   5482 Each element should have the form (MODE . (PROPERTY-LIST...)).
   5483 MODE (car) is function which is defined in `lsp-language-id-configuration'.
   5484 Cdr should be list of PROPERTY-LIST.
   5485 
   5486 Each PROPERTY-LIST should have properties:
   5487 :regexp  Regexp which determines what string is relpaced to image.
   5488          You should also get information of image, by parenthesis constructs.
   5489          By default, all matched string is replaced to image, but you can
   5490          change index of replaced string by keyword :replaced-index.
   5491 
   5492 :sexp    Return image when evaluated. You can use information of regexp
   5493          by using (match-beggining N), (match-end N) or (match-substring N).
   5494 
   5495 In addition, each can have property:
   5496 :replaced-index  Determine index which is used to replace regexp to image.
   5497                  The value means first argument of `match-beginning' and
   5498                  `match-end'. If omitted, interpreted as index 0.")
   5499 
   5500 (defcustom lsp-display-inline-image t
   5501   "Showing inline image or not."
   5502   :group 'lsp-mode
   5503   :type 'boolean)
   5504 
   5505 (defcustom lsp-enable-suggest-server-download t
   5506   "When non-nil enable server downloading suggestions."
   5507   :group 'lsp-mode
   5508   :type 'boolean
   5509   :package-version '(lsp-mode . "9.0.0"))
   5510 
   5511 (defcustom lsp-auto-register-remote-clients t
   5512   "When non-nil register remote when registering the local one."
   5513   :group 'lsp-mode
   5514   :type 'boolean
   5515   :package-version '(lsp-mode . "9.0.0"))
   5516 
   5517 (defun lsp--display-inline-image (mode)
   5518   "Add image property if available."
   5519   (let ((plist-list (cdr (assq mode lsp--display-inline-image-alist))))
   5520     (when (and (display-images-p) lsp-display-inline-image)
   5521       (cl-loop
   5522        for plist in plist-list
   5523        with regexp with replaced-index
   5524        do
   5525        (setq regexp (plist-get plist :regexp))
   5526        (setq replaced-index (or (plist-get plist :replaced-index) 0))
   5527 
   5528        (font-lock-remove-keywords nil (list regexp replaced-index))
   5529        (let ((inhibit-read-only t))
   5530          (save-excursion
   5531            (goto-char (point-min))
   5532            (while (re-search-forward regexp nil t)
   5533              (set-text-properties
   5534               (match-beginning replaced-index) (match-end replaced-index)
   5535               nil)
   5536              (add-text-properties
   5537               (match-beginning replaced-index) (match-end replaced-index)
   5538               `(display ,(eval (plist-get plist :sexp)))))))))))
   5539 
   5540 (defun lsp--fontlock-with-mode (str mode)
   5541   "Fontlock STR with MODE."
   5542   (let ((lsp-buffer-major-mode major-mode))
   5543     (with-temp-buffer
   5544       (with-demoted-errors "Error during doc rendering: %s"
   5545         (insert str)
   5546         (delay-mode-hooks (funcall mode))
   5547         (cl-flet ((window-body-width () lsp-window-body-width))
   5548           ;; This can go wrong in some cases, and the fontification would
   5549           ;; not work as expected.
   5550           ;;
   5551           ;; See #2984
   5552           (ignore-errors (font-lock-ensure))
   5553           (lsp--display-inline-image mode)
   5554           (when (eq mode 'lsp--render-markdown)
   5555             (lsp--fix-markdown-links))))
   5556       (lsp--buffer-string-visible))))
   5557 
   5558 (defun lsp--render-string (str language)
   5559   "Render STR using `major-mode' corresponding to LANGUAGE.
   5560 When language is nil render as markup if `markdown-mode' is loaded."
   5561   (setq str (s-replace "\r" "" (or str "")))
   5562   (if-let* ((modes (-keep (-lambda ((mode . lang))
   5563                             (when (and (equal lang language) (functionp mode))
   5564                               mode))
   5565                           lsp-language-id-configuration))
   5566             (mode (car (or (member major-mode modes) modes))))
   5567       (lsp--fontlock-with-mode str mode)
   5568     str))
   5569 
   5570 (defun lsp--render-element (content)
   5571   "Render CONTENT element."
   5572   (let ((inhibit-message t))
   5573     (or
   5574      (pcase content
   5575        ((MarkedString :value :language)
   5576         (lsp--render-string value language))
   5577        ((MarkupContent :value :kind)
   5578         (lsp--render-string value kind))
   5579        ;; plain string
   5580        ((pred stringp) (lsp--render-string content "markdown"))
   5581        ((pred null) "")
   5582        (_ (error "Failed to handle %s" content)))
   5583      "")))
   5584 
   5585 (defun lsp--create-unique-string-fn ()
   5586   (let (elements)
   5587     (lambda (element)
   5588       (let ((count (cl-count element elements :test #'string=)))
   5589         (prog1 (if (zerop count)
   5590                    element
   5591                  (format "%s (%s)" element count))
   5592           (push element elements))))))
   5593 
   5594 (defun lsp--select-action (actions)
   5595   "Select an action to execute from ACTIONS."
   5596   (cond
   5597    ((seq-empty-p actions) (signal 'lsp-no-code-actions nil))
   5598    ((and (eq (seq-length actions) 1) lsp-auto-execute-action)
   5599     (lsp-seq-first actions))
   5600    (t (let ((completion-ignore-case t))
   5601         (lsp--completing-read "Select code action: "
   5602                               (seq-into actions 'list)
   5603                               (-compose (lsp--create-unique-string-fn)
   5604                                         #'lsp:code-action-title)
   5605                               nil t)))))
   5606 
   5607 (defun lsp--workspace-server-id (workspace)
   5608   "Return the server ID of WORKSPACE."
   5609   (-> workspace lsp--workspace-client lsp--client-server-id))
   5610 
   5611 (defun lsp--handle-rendered-for-echo-area (contents)
   5612   "Return a single line from RENDERED, appropriate for display in the echo area."
   5613   (pcase (lsp-workspaces)
   5614     (`(,workspace)
   5615      (lsp-clients-extract-signature-on-hover contents (lsp--workspace-server-id workspace)))
   5616     ;; For projects with multiple active workspaces we also default to
   5617     ;; render the first line.
   5618     (_ (lsp-clients-extract-signature-on-hover contents nil))))
   5619 
   5620 (cl-defmethod lsp-clients-extract-signature-on-hover (contents _server-id)
   5621   "Extract a representative line from CONTENTS, to show in the echo area."
   5622   (car (s-lines (s-trim (lsp--render-element contents)))))
   5623 
   5624 (defun lsp--render-on-hover-content (contents render-all)
   5625   "Render the content received from `document/onHover' request.
   5626 CONTENTS  - MarkedString | MarkedString[] | MarkupContent
   5627 RENDER-ALL - nil if only the signature should be rendered."
   5628   (cond
   5629    ((lsp-markup-content? contents)
   5630     ;; MarkupContent.
   5631     ;; It tends to be long and is not suitable to display fully in the echo area.
   5632     ;; Just display the first line which is typically the signature.
   5633     (if render-all
   5634         (lsp--render-element contents)
   5635       (lsp--handle-rendered-for-echo-area contents)))
   5636    ((and (stringp contents) (not (string-match-p "\n" contents)))
   5637     ;; If the contents is a single string containing a single line,
   5638     ;; render it always.
   5639     (lsp--render-element contents))
   5640    (t
   5641     ;; MarkedString -> MarkedString[]
   5642     (when (or (lsp-marked-string? contents) (stringp contents))
   5643       (setq contents (list contents)))
   5644     ;; Consider the signature consisting of the elements who have a renderable
   5645     ;; "language" property. When render-all is nil, ignore other elements.
   5646     (string-join
   5647      (seq-map
   5648       #'lsp--render-element
   5649       (if render-all
   5650           contents
   5651         ;; Only render contents that have an available renderer.
   5652         (seq-take
   5653          (seq-filter
   5654           (-andfn #'lsp-marked-string?
   5655                   (-compose #'lsp-get-renderer #'lsp:marked-string-language))
   5656           contents)
   5657          1)))
   5658      (if (bound-and-true-p page-break-lines-mode)
   5659          "\n\n"
   5660        "\n")))))
   5661 
   5662 
   5663 
   5664 (defvar lsp-signature-mode-map
   5665   (-doto (make-sparse-keymap)
   5666     (define-key (kbd "M-n") #'lsp-signature-next)
   5667     (define-key (kbd "M-p") #'lsp-signature-previous)
   5668     (define-key (kbd "M-a") #'lsp-signature-toggle-full-docs)
   5669     (define-key (kbd "C-c C-k") #'lsp-signature-stop)
   5670     (define-key (kbd "C-g") #'lsp-signature-stop))
   5671   "Keymap for `lsp-signature-mode'.")
   5672 
   5673 (define-minor-mode lsp-signature-mode
   5674   "Mode used to show signature popup."
   5675   :keymap lsp-signature-mode-map
   5676   :lighter ""
   5677   :group 'lsp-mode)
   5678 
   5679 (defun lsp-signature-stop ()
   5680   "Stop showing current signature help."
   5681   (interactive)
   5682   (lsp-cancel-request-by-token :signature)
   5683   (remove-hook 'post-command-hook #'lsp-signature)
   5684   (funcall lsp-signature-function nil)
   5685   (lsp-signature-mode -1))
   5686 
   5687 (declare-function page-break-lines--update-display-tables "ext:page-break-lines")
   5688 
   5689 (defun lsp--setup-page-break-mode-if-present ()
   5690   "Enable `page-break-lines-mode' in current buffer."
   5691   (when (fboundp 'page-break-lines-mode)
   5692     (page-break-lines-mode)
   5693     ;; force page-break-lines-mode to update the display tables.
   5694     (page-break-lines--update-display-tables)))
   5695 
   5696 (defun lsp-lv-message (message)
   5697   (add-hook 'lv-window-hook #'lsp--setup-page-break-mode-if-present)
   5698   (if message
   5699       (progn
   5700         (setq lsp--signature-last-buffer (current-buffer))
   5701         (let ((lv-force-update t))
   5702           (lv-message "%s" message)))
   5703     (lv-delete-window)
   5704     (remove-hook 'lv-window-hook #'lsp--setup-page-break-mode-if-present)))
   5705 
   5706 (declare-function posframe-show "ext:posframe")
   5707 (declare-function posframe-hide "ext:posframe")
   5708 (declare-function posframe-poshandler-point-bottom-left-corner-upward "ext:posframe")
   5709 
   5710 (defface lsp-signature-posframe
   5711   '((t :inherit tooltip))
   5712   "Background and foreground for `lsp-signature-posframe'."
   5713   :group 'lsp-mode)
   5714 
   5715 (defvar lsp-signature-posframe-params
   5716   (list :poshandler #'posframe-poshandler-point-bottom-left-corner-upward
   5717         :height 10
   5718         :width 60
   5719         :border-width 1
   5720         :min-width 60)
   5721   "Params for signature and `posframe-show'.")
   5722 
   5723 (defun lsp-signature-posframe (str)
   5724   "Use posframe to show the STR signatureHelp string."
   5725   (if str
   5726       (apply #'posframe-show
   5727              (with-current-buffer (get-buffer-create " *lsp-signature*")
   5728                (erase-buffer)
   5729                (insert str)
   5730                (visual-line-mode 1)
   5731                (lsp--setup-page-break-mode-if-present)
   5732                (current-buffer))
   5733              (append
   5734               lsp-signature-posframe-params
   5735               (list :position (point)
   5736                     :background-color (face-attribute 'lsp-signature-posframe :background nil t)
   5737                     :foreground-color (face-attribute 'lsp-signature-posframe :foreground nil t)
   5738                     :border-color (face-attribute 'font-lock-comment-face :foreground nil t))))
   5739     (posframe-hide " *lsp-signature*")))
   5740 
   5741 (defun lsp--handle-signature-update (signature)
   5742   (let ((message
   5743          (if (lsp-signature-help? signature)
   5744              (lsp--signature->message signature)
   5745            (mapconcat #'lsp--signature->message signature "\n"))))
   5746     (if (s-present? message)
   5747         (funcall lsp-signature-function message)
   5748       (lsp-signature-stop))))
   5749 
   5750 (defun lsp-signature-activate ()
   5751   "Activate signature help.
   5752 It will show up only if current point has signature help."
   5753   (interactive)
   5754   (setq lsp--signature-last nil
   5755         lsp--signature-last-index nil
   5756         lsp--signature-last-buffer (current-buffer))
   5757   (add-hook 'post-command-hook #'lsp-signature)
   5758   (lsp-signature-mode t))
   5759 
   5760 (defcustom lsp-signature-cycle t
   5761   "Whether `lsp-signature-next' and prev should cycle."
   5762   :type 'boolean
   5763   :group 'lsp-mode)
   5764 
   5765 (defun lsp-signature-next ()
   5766   "Show next signature."
   5767   (interactive)
   5768   (let ((nsigs (length (lsp:signature-help-signatures lsp--signature-last))))
   5769     (when (and lsp--signature-last-index
   5770                lsp--signature-last
   5771                (or lsp-signature-cycle (< (1+ lsp--signature-last-index) nsigs)))
   5772       (setq lsp--signature-last-index (% (1+ lsp--signature-last-index) nsigs))
   5773       (funcall lsp-signature-function (lsp--signature->message lsp--signature-last)))))
   5774 
   5775 (defun lsp-signature-previous ()
   5776   "Next signature."
   5777   (interactive)
   5778   (when (and lsp--signature-last-index
   5779              lsp--signature-last
   5780              (or lsp-signature-cycle (not (zerop lsp--signature-last-index))))
   5781     (setq lsp--signature-last-index (1- (if (zerop lsp--signature-last-index)
   5782                                             (length (lsp:signature-help-signatures lsp--signature-last))
   5783                                           lsp--signature-last-index)))
   5784     (funcall lsp-signature-function (lsp--signature->message lsp--signature-last))))
   5785 
   5786 (defun lsp-signature-toggle-full-docs ()
   5787   "Toggle full/partial signature documentation."
   5788   (interactive)
   5789   (let ((all? (not (numberp lsp-signature-doc-lines))))
   5790     (setq lsp-signature-doc-lines (if all?
   5791                                       (or (car-safe lsp-signature-doc-lines)
   5792                                           20)
   5793                                     (list lsp-signature-doc-lines))))
   5794   (lsp-signature-activate))
   5795 
   5796 (defun lsp--signature->message (signature-help)
   5797   "Generate eldoc message from SIGNATURE-HELP response."
   5798   (setq lsp--signature-last signature-help)
   5799 
   5800   (when (and signature-help (not (seq-empty-p (lsp:signature-help-signatures signature-help))))
   5801     (-let* (((&SignatureHelp :active-signature?
   5802                              :active-parameter?
   5803                              :signatures) signature-help)
   5804             (active-signature? (or lsp--signature-last-index active-signature? 0))
   5805             (_ (setq lsp--signature-last-index active-signature?))
   5806             ((signature &as &SignatureInformation? :label :parameters?) (seq-elt signatures active-signature?))
   5807             (prefix (if (= (length signatures) 1)
   5808                         ""
   5809                       (concat (propertize (format " %s/%s"
   5810                                                   (1+ active-signature?)
   5811                                                   (length signatures))
   5812                                           'face 'success)
   5813                               " ")))
   5814             (method-docs (when
   5815                              (and lsp-signature-render-documentation
   5816                                   (or (not (numberp lsp-signature-doc-lines)) (< 0 lsp-signature-doc-lines)))
   5817                            (let ((docs (lsp--render-element
   5818                                         (lsp:parameter-information-documentation? signature))))
   5819                              (when (s-present? docs)
   5820                                (concat
   5821                                 "\n"
   5822                                 (if (fboundp 'page-break-lines-mode)
   5823                                     "\n"
   5824                                   "")
   5825                                 (if (and (numberp lsp-signature-doc-lines)
   5826                                          (> (length (s-lines docs)) lsp-signature-doc-lines))
   5827                                     (concat (s-join "\n" (-take lsp-signature-doc-lines (s-lines docs)))
   5828                                             (propertize "\nTruncated..." 'face 'highlight))
   5829                                   docs)))))))
   5830       (when (and active-parameter? (not (seq-empty-p parameters?)))
   5831         (-when-let* ((param (when (and (< -1 active-parameter? (length parameters?)))
   5832                               (seq-elt parameters? active-parameter?)))
   5833                      (selected-param-label (let ((label (lsp:parameter-information-label param)))
   5834                                              (if (stringp label) label (append label nil))))
   5835                      (start (if (stringp selected-param-label)
   5836                                 (s-index-of selected-param-label label)
   5837                               (cl-first selected-param-label)))
   5838                      (end (if (stringp selected-param-label)
   5839                               (+ start (length selected-param-label))
   5840                             (cl-second selected-param-label))))
   5841           (add-face-text-property start end 'eldoc-highlight-function-argument nil label)))
   5842       (concat prefix label method-docs))))
   5843 
   5844 (defun lsp-signature ()
   5845   "Display signature info (based on `textDocument/signatureHelp')"
   5846   (if (and lsp--signature-last-buffer
   5847            (not (equal (current-buffer) lsp--signature-last-buffer)))
   5848       (lsp-signature-stop)
   5849     (lsp-request-async "textDocument/signatureHelp"
   5850                        (lsp--text-document-position-params)
   5851                        #'lsp--handle-signature-update
   5852                        :cancel-token :signature)))
   5853 
   5854 
   5855 (defcustom lsp-overlay-document-color-char "■"
   5856   "Display the char represent the document color in overlay"
   5857   :type 'string
   5858   :group 'lsp-mode)
   5859 
   5860 ;; color presentation
   5861 (defun lsp--color-create-interactive-command (color range)
   5862   (lambda ()
   5863     (interactive)
   5864     (-let [(&ColorPresentation? :text-edit?
   5865                                 :additional-text-edits?)
   5866            (lsp--completing-read
   5867             "Select color presentation: "
   5868             (lsp-request
   5869              "textDocument/colorPresentation"
   5870              `( :textDocument ,(lsp--text-document-identifier)
   5871                 :color ,color
   5872                 :range ,range))
   5873             #'lsp:color-presentation-label
   5874             nil
   5875             t)]
   5876       (when text-edit?
   5877         (lsp--apply-text-edit text-edit?))
   5878       (when additional-text-edits?
   5879         (lsp--apply-text-edits additional-text-edits? 'color-presentation)))))
   5880 
   5881 (defun lsp--number->color (number)
   5882   (let ((result (format "%x"
   5883                         (round (* (or number 0) 255.0)))))
   5884     (if (= 1 (length result))
   5885         (concat "0" result)
   5886       result)))
   5887 
   5888 (defun lsp--document-color ()
   5889   "Document color handler."
   5890   (when (lsp-feature? "textDocument/documentColor")
   5891     (lsp-request-async
   5892      "textDocument/documentColor"
   5893      `(:textDocument ,(lsp--text-document-identifier))
   5894      (lambda (result)
   5895        (lsp--remove-overlays 'lsp-color)
   5896        (seq-do
   5897         (-lambda ((&ColorInformation :color (color &as &Color :red :green :blue)
   5898                                      :range))
   5899           (-let* (((beg . end) (lsp--range-to-region range))
   5900                   (overlay (make-overlay beg end))
   5901                   (command (lsp--color-create-interactive-command color range)))
   5902             (overlay-put overlay 'lsp-color t)
   5903             (overlay-put overlay 'evaporate t)
   5904             (overlay-put overlay
   5905                          'before-string
   5906                          (propertize
   5907                           lsp-overlay-document-color-char
   5908                           'face `((:foreground ,(format
   5909                                                  "#%s%s%s"
   5910                                                  (lsp--number->color red)
   5911                                                  (lsp--number->color green)
   5912                                                  (lsp--number->color blue))))
   5913                           'action command
   5914                           'mouse-face 'lsp-lens-mouse-face
   5915                           'local-map (-doto (make-sparse-keymap)
   5916                                        (define-key [mouse-1] command))))))
   5917         result))
   5918      :mode 'unchanged
   5919      :cancel-token :document-color-token)))
   5920 
   5921 
   5922 
   5923 (defun lsp--action-trigger-parameter-hints (_command)
   5924   "Handler for editor.action.triggerParameterHints."
   5925   (when (member :on-server-request lsp-signature-auto-activate)
   5926     (lsp-signature-activate)))
   5927 
   5928 (defun lsp--action-trigger-suggest (_command)
   5929   "Handler for editor.action.triggerSuggest."
   5930   (cond
   5931    ((and (bound-and-true-p company-mode)
   5932          (fboundp 'company-auto-begin)
   5933          (fboundp 'company-post-command))
   5934     (run-at-time 0 nil
   5935                  (lambda ()
   5936                    (let ((this-command 'company-idle-begin)
   5937                          (company-minimum-prefix-length 0))
   5938                      (company-auto-begin)
   5939                      (company-post-command)))))
   5940    (t
   5941     (completion-at-point))))
   5942 
   5943 (defconst lsp--default-action-handlers
   5944   (ht ("editor.action.triggerParameterHints" #'lsp--action-trigger-parameter-hints)
   5945       ("editor.action.triggerSuggest" #'lsp--action-trigger-suggest))
   5946   "Default action handlers.")
   5947 
   5948 (defun lsp--find-action-handler (command)
   5949   "Find action handler for particular COMMAND."
   5950   (or
   5951    (--some (-some->> it
   5952              (lsp--workspace-client)
   5953              (lsp--client-action-handlers)
   5954              (gethash command))
   5955            (lsp-workspaces))
   5956    (gethash command lsp--default-action-handlers)))
   5957 
   5958 (defun lsp--text-document-code-action-params (&optional kind)
   5959   "Code action params."
   5960   (list :textDocument (lsp--text-document-identifier)
   5961         :range (if (use-region-p)
   5962                    (lsp--region-to-range (region-beginning) (region-end))
   5963                  (lsp--region-to-range (point) (point)))
   5964         :context `( :diagnostics ,(lsp-cur-possition-diagnostics)
   5965                     ,@(when kind (list :only (vector kind))))))
   5966 
   5967 (defun lsp-code-actions-at-point (&optional kind)
   5968   "Retrieve the code actions for the active region or the current line.
   5969 It will filter by KIND if non nil."
   5970   (lsp-request "textDocument/codeAction" (lsp--text-document-code-action-params kind)))
   5971 
   5972 (defun lsp-execute-code-action-by-kind (command-kind)
   5973   "Execute code action by COMMAND-KIND."
   5974   (if-let ((action (->> (lsp-get-or-calculate-code-actions command-kind)
   5975                         (-filter (-lambda ((&CodeAction :kind?))
   5976                                    (and kind? (s-prefix? command-kind kind?))))
   5977                         lsp--select-action)))
   5978       (lsp-execute-code-action action)
   5979     (signal 'lsp-no-code-actions '(command-kind))))
   5980 
   5981 (defalias 'lsp-get-or-calculate-code-actions 'lsp-code-actions-at-point)
   5982 
   5983 (lsp-defun lsp--execute-command ((action &as &Command :command :arguments?))
   5984   "Parse and execute a code ACTION represented as a Command LSP type."
   5985   (let ((server-id (->> (lsp-workspaces)
   5986                         (cl-first)
   5987                         (or lsp--cur-workspace)
   5988                         (lsp--workspace-client)
   5989                         (lsp--client-server-id))))
   5990     (condition-case nil
   5991         (with-no-warnings
   5992           (lsp-execute-command server-id (intern command) arguments?))
   5993       (cl-no-applicable-method
   5994        (if-let ((action-handler (lsp--find-action-handler command)))
   5995            (funcall action-handler action)
   5996          (lsp-send-execute-command command arguments?))))))
   5997 
   5998 (lsp-defun lsp-execute-code-action ((action &as &CodeAction :command? :edit?))
   5999   "Execute code action ACTION. For example, when text under the
   6000 caret has a suggestion to apply a fix from an lsp-server, calling
   6001 this function will do so.
   6002 If ACTION is not set it will be selected from `lsp-code-actions-at-point'.
   6003 Request codeAction/resolve for more info if server supports."
   6004   (interactive (list (lsp--select-action (lsp-code-actions-at-point))))
   6005   (if (and (lsp-feature? "codeAction/resolve")
   6006            (not command?)
   6007            (not edit?))
   6008       (lsp--execute-code-action (lsp-request "codeAction/resolve" action))
   6009     (lsp--execute-code-action action)))
   6010 
   6011 (lsp-defun lsp--execute-code-action ((action &as &CodeAction :command? :edit?))
   6012   "Execute code action ACTION."
   6013   (when edit?
   6014     (lsp--apply-workspace-edit edit? 'code-action))
   6015 
   6016   (cond
   6017    ((stringp command?) (lsp--execute-command action))
   6018    ((lsp-command? command?) (progn
   6019                               (when-let ((action-filter (->> (lsp-workspaces)
   6020                                                              (cl-first)
   6021                                                              (or lsp--cur-workspace)
   6022                                                              (lsp--workspace-client)
   6023                                                              (lsp--client-action-filter))))
   6024                                 (funcall action-filter command?))
   6025                               (lsp--execute-command command?)))))
   6026 
   6027 (lsp-defun lsp-fix-code-action-booleans ((&Command :arguments?) boolean-action-arguments)
   6028   "Patch incorrect boolean argument values in the provided `CodeAction' command
   6029 in place, based on the BOOLEAN-ACTION-ARGUMENTS list. The values
   6030 in this list can be either symbols or lists of symbols that
   6031 represent paths to boolean arguments in code actions:
   6032 
   6033 > (lsp-fix-code-action-booleans command `(:foo :bar (:some :nested :boolean)))
   6034 
   6035 When there are available code actions, the server sends
   6036 `lsp-mode' a list of possible command names and arguments as
   6037 JSON. `lsp-mode' parses all boolean false values as `nil'. As a
   6038 result code action arguments containing falsy values don't
   6039 roundtrip correctly because `lsp-mode' will end up sending null
   6040 values back to the client. This list makes it possible to
   6041 selectively transform `nil' values back into `:json-false'."
   6042   (seq-doseq (path boolean-action-arguments)
   6043     (seq-doseq (args arguments?)
   6044       (lsp--fix-nested-boolean args (if (listp path) path (list path))))))
   6045 
   6046 (defun lsp--fix-nested-boolean (structure path)
   6047   "Traverse STRUCTURE using the paths from the PATH list, changing the value to
   6048 `:json-false' if it was `nil'. PATH should be a list containing
   6049 one or more symbols, and STRUCTURE should be compatible with
   6050 `lsp-member?', `lsp-get', and `lsp-put'."
   6051   (let ((key (car path))
   6052         (rest (cdr path)))
   6053     (if (null rest)
   6054         ;; `lsp-put' returns `nil' both when the key doesn't exist and when the
   6055         ;; value is `nil', so we need to explicitly check its presence here
   6056         (when (and (lsp-member? structure key) (not (lsp-get structure key)))
   6057           (lsp-put structure key :json-false))
   6058       ;; If `key' does not exist, then we'll silently ignore it
   6059       (when-let ((child (lsp-get structure key)))
   6060         (lsp--fix-nested-boolean child rest)))))
   6061 
   6062 (defvar lsp--formatting-indent-alist
   6063   ;; Taken from `dtrt-indent-mode'
   6064   '(
   6065     (ada-mode                   . ada-indent)                       ; Ada
   6066     (ada-ts-mode                . ada-ts-mode-indent-offset)
   6067     (c++-mode                   . c-basic-offset)                   ; C++
   6068     (c++-ts-mode                . c-ts-mode-indent-offset)
   6069     (c-mode                     . c-basic-offset)                   ; C
   6070     (c-ts-mode                  . c-ts-mode-indent-offset)
   6071     (cperl-mode                 . cperl-indent-level)               ; Perl
   6072     (crystal-mode               . crystal-indent-level)             ; Crystal (Ruby)
   6073     (csharp-mode                . c-basic-offset)                   ; C#
   6074     (csharp-tree-sitter-mode    . csharp-tree-sitter-indent-offset) ; C#
   6075     (csharp-ts-mode             . csharp-ts-mode-indent-offset)     ; C# (tree-sitter, Emacs29)
   6076     (css-mode                   . css-indent-offset)                ; CSS
   6077     (d-mode                     . c-basic-offset)                   ; D
   6078     (enh-ruby-mode              . enh-ruby-indent-level)            ; Ruby
   6079     (erlang-mode                . erlang-indent-level)              ; Erlang
   6080     (ess-mode                   . ess-indent-offset)                ; ESS (R)
   6081     (go-ts-mode                 . go-ts-mode-indent-offset)
   6082     (gpr-mode                   . gpr-indent-offset)                ; GNAT Project
   6083     (gpr-ts-mode                . gpr-ts-mode-indent-offset)
   6084     (hack-mode                  . hack-indent-offset)               ; Hack
   6085     (java-mode                  . c-basic-offset)                   ; Java
   6086     (java-ts-mode               . java-ts-mode-indent-offset)
   6087     (jde-mode                   . c-basic-offset)                   ; Java (JDE)
   6088     (js-mode                    . js-indent-level)                  ; JavaScript
   6089     (js-ts-mode                 . js-indent-level)
   6090     (js2-mode                   . js2-basic-offset)                 ; JavaScript-IDE
   6091     (js3-mode                   . js3-indent-level)                 ; JavaScript-IDE
   6092     (json-mode                  . js-indent-level)                  ; JSON
   6093     (json-ts-mode               . json-ts-mode-indent-offset)
   6094     (lua-mode                   . lua-indent-level)                 ; Lua
   6095     (lua-ts-mode                . lua-ts-indent-offset)
   6096     (nxml-mode                  . nxml-child-indent)                ; XML
   6097     (objc-mode                  . c-basic-offset)                   ; Objective C
   6098     (pascal-mode                . pascal-indent-level)              ; Pascal
   6099     (perl-mode                  . perl-indent-level)                ; Perl
   6100     (php-mode                   . c-basic-offset)                   ; PHP
   6101     (php-ts-mode                . php-ts-mode-indent-offset)        ; PHP
   6102     (powershell-mode            . powershell-indent)                ; PowerShell
   6103     (powershell-ts-mode         . powershell-ts-mode-indent-offset) ; PowerShell
   6104     (raku-mode                  . raku-indent-offset)               ; Perl6/Raku
   6105     (ruby-mode                  . ruby-indent-level)                ; Ruby
   6106     (rust-mode                  . rust-indent-offset)               ; Rust
   6107     (rust-ts-mode               . rust-ts-mode-indent-offset)
   6108     (rustic-mode                . rustic-indent-offset)             ; Rust
   6109     (scala-mode                 . scala-indent:step)                ; Scala
   6110     (sgml-mode                  . sgml-basic-offset)                ; SGML
   6111     (sh-mode                    . sh-basic-offset)                  ; Shell Script
   6112     (toml-ts-mode               . toml-ts-mode-indent-offset)
   6113     (typescript-mode            . typescript-indent-level)          ; Typescript
   6114     (typescript-ts-mode         . typescript-ts-mode-indent-offset) ; Typescript (tree-sitter, Emacs29)
   6115     (yaml-mode                  . yaml-indent-offset)               ; YAML
   6116     (yang-mode                  . c-basic-offset)                   ; YANG (yang-mode)
   6117 
   6118     (default                    . standard-indent))                 ; default fallback
   6119   "A mapping from `major-mode' to its indent variable.")
   6120 
   6121 (defun lsp--get-indent-width (mode)
   6122   "Get indentation offset for MODE."
   6123   (or (alist-get mode lsp--formatting-indent-alist)
   6124       (lsp--get-indent-width (or (get mode 'derived-mode-parent) 'default))))
   6125 
   6126 (defun lsp--make-document-formatting-params ()
   6127   "Create document formatting params."
   6128   (lsp-make-document-formatting-params
   6129    :text-document (lsp--text-document-identifier)
   6130    :options (lsp-make-formatting-options
   6131              :tab-size (symbol-value (lsp--get-indent-width major-mode))
   6132              :insert-spaces (lsp-json-bool (not indent-tabs-mode))
   6133              :trim-trailing-whitespace? (lsp-json-bool lsp-trim-trailing-whitespace)
   6134              :insert-final-newline? (lsp-json-bool lsp-insert-final-newline)
   6135              :trim-final-newlines? (lsp-json-bool lsp-trim-final-newlines))))
   6136 
   6137 (defun lsp-format-buffer ()
   6138   "Ask the server to format this document."
   6139   (interactive "*")
   6140   (cond ((lsp-feature? "textDocument/formatting")
   6141          (let ((edits (lsp-request "textDocument/formatting"
   6142                                    (lsp--make-document-formatting-params))))
   6143            (if (seq-empty-p edits)
   6144                (lsp--info "No formatting changes provided")
   6145              (lsp--apply-text-edits edits 'format))))
   6146         ((lsp-feature? "textDocument/rangeFormatting")
   6147          (save-restriction
   6148            (widen)
   6149            (lsp-format-region (point-min) (point-max))))
   6150         (t (signal 'lsp-capability-not-supported (list "documentFormattingProvider")))))
   6151 
   6152 (defun lsp-format-region (s e)
   6153   "Ask the server to format the region, or if none is selected, the current line."
   6154   (interactive "r")
   6155   (let ((edits (lsp-request
   6156                 "textDocument/rangeFormatting"
   6157                 (lsp--make-document-range-formatting-params s e))))
   6158     (if (seq-empty-p edits)
   6159         (lsp--info "No formatting changes provided")
   6160       (lsp--apply-text-edits edits 'format))))
   6161 
   6162 (defmacro lsp-make-interactive-code-action (func-name code-action-kind)
   6163   "Define an interactive function FUNC-NAME that attempts to
   6164 execute a CODE-ACTION-KIND action."
   6165   `(defun ,(intern (concat "lsp-" (symbol-name func-name))) ()
   6166      ,(format "Perform the %s code action, if available." code-action-kind)
   6167      (interactive)
   6168      ;; Even when `lsp-auto-execute-action' is nil, it still makes sense to
   6169      ;; auto-execute here: the user has specified exactly what they want.
   6170      (let ((lsp-auto-execute-action t))
   6171        (condition-case nil
   6172            (lsp-execute-code-action-by-kind ,code-action-kind)
   6173          (lsp-no-code-actions
   6174           (when (called-interactively-p 'any)
   6175             (lsp--info ,(format "%s action not available" code-action-kind))))))))
   6176 
   6177 (lsp-make-interactive-code-action organize-imports "source.organizeImports")
   6178 
   6179 (defun lsp--make-document-range-formatting-params (start end)
   6180   "Make DocumentRangeFormattingParams for selected region."
   6181   (lsp:set-document-range-formatting-params-range (lsp--make-document-formatting-params)
   6182                                                   (lsp--region-to-range start end)))
   6183 
   6184 (defconst lsp--highlight-kind-face
   6185   '((1 . lsp-face-highlight-textual)
   6186     (2 . lsp-face-highlight-read)
   6187     (3 . lsp-face-highlight-write)))
   6188 
   6189 (defun lsp--remove-overlays (name)
   6190   (save-restriction
   6191     (widen)
   6192     (remove-overlays (point-min) (point-max) name t)))
   6193 
   6194 (defun lsp-document-highlight ()
   6195   "Highlight all relevant references to the symbol under point."
   6196   (interactive)
   6197   (lsp--remove-overlays 'lsp-highlight) ;; clear any previous highlights
   6198   (setq lsp--have-document-highlights nil
   6199         lsp--symbol-bounds-of-last-highlight-invocation nil)
   6200   (let ((lsp-enable-symbol-highlighting t))
   6201     (lsp--document-highlight)))
   6202 
   6203 (defun lsp--document-highlight-callback (highlights)
   6204   "Create a callback to process the reply of a
   6205 `textDocument/documentHighlight' message for the buffer BUF.
   6206 A reference is highlighted only if it is visible in a window."
   6207   (lsp--remove-overlays 'lsp-highlight)
   6208 
   6209   (let* ((wins-visible-pos (-map (lambda (win)
   6210                                    (cons (1- (line-number-at-pos (window-start win) t))
   6211                                          (1+ (line-number-at-pos (window-end win) t))))
   6212                                  (get-buffer-window-list nil nil 'visible))))
   6213     (setq lsp--have-document-highlights t)
   6214     (-map
   6215      (-lambda ((&DocumentHighlight :range (&Range :start (start &as &Position :line start-line)
   6216                                                   :end (end &as &Position :line end-line))
   6217                                    :kind?))
   6218        (-map
   6219         (-lambda ((start-window . end-window))
   6220           ;; Make the overlay only if the reference is visible
   6221           (let ((start-point (lsp--position-to-point start))
   6222                 (end-point (lsp--position-to-point end)))
   6223             (when (and (> (1+ start-line) start-window)
   6224                        (< (1+ end-line) end-window)
   6225                        (not (and lsp-symbol-highlighting-skip-current
   6226                                  (<= start-point (point) end-point))))
   6227               (-doto (make-overlay start-point end-point)
   6228                 (overlay-put 'face (cdr (assq (or kind? 1) lsp--highlight-kind-face)))
   6229                 (overlay-put 'lsp-highlight t)))))
   6230         wins-visible-pos))
   6231      highlights)))
   6232 
   6233 (defcustom lsp-symbol-kinds
   6234   '((1 . "File")
   6235     (2 . "Module")
   6236     (3 . "Namespace")
   6237     (4 . "Package")
   6238     (5 . "Class")
   6239     (6 . "Method")
   6240     (7 . "Property")
   6241     (8 . "Field")
   6242     (9 . "Constructor")
   6243     (10 . "Enum")
   6244     (11 . "Interface")
   6245     (12 . "Function")
   6246     (13 . "Variable")
   6247     (14 . "Constant")
   6248     (15 . "String")
   6249     (16 . "Number")
   6250     (17 . "Boolean")
   6251     (18 . "Array")
   6252     (19 . "Object")
   6253     (20 . "Key")
   6254     (21 . "Null")
   6255     (22 . "Enum Member")
   6256     (23 . "Struct")
   6257     (24 . "Event")
   6258     (25 . "Operator")
   6259     (26 . "Type Parameter"))
   6260   "Alist mapping SymbolKinds to human-readable strings.
   6261 Various Symbol objects in the LSP protocol have an integral type,
   6262 specifying what they are. This alist maps such type integrals to
   6263 readable representations of them. See
   6264 `https://microsoft.github.io/language-server-protocol/specifications/specification-current/',
   6265 namespace SymbolKind."
   6266   :group 'lsp-mode
   6267   :type '(alist :key-type integer :value-type string))
   6268 (defalias 'lsp--symbol-kind 'lsp-symbol-kinds)
   6269 
   6270 (lsp-defun lsp--symbol-information-to-xref
   6271   ((&SymbolInformation :kind :name
   6272                        :location (&Location :uri :range (&Range :start
   6273                                                                 (&Position :line :character)))))
   6274   "Return a `xref-item' from SYMBOL information."
   6275   (xref-make (format "[%s] %s" (alist-get kind lsp-symbol-kinds) name)
   6276              (xref-make-file-location (lsp--uri-to-path uri)
   6277                                       line
   6278                                       character)))
   6279 
   6280 (defun lsp--get-document-symbols ()
   6281   "Get document symbols.
   6282 
   6283 If the buffer has not been modified since symbols were last
   6284 retrieved, simply return the latest result.
   6285 
   6286 Else, if the request was initiated by Imenu updating its menu-bar
   6287 entry, perform it asynchronously; i.e., give Imenu the latest
   6288 result and then force a refresh when a new one is available.
   6289 
   6290 Else (e.g., due to interactive use of `imenu' or `xref'),
   6291 perform the request synchronously."
   6292   (if (= (buffer-chars-modified-tick) lsp--document-symbols-tick)
   6293       lsp--document-symbols
   6294     (let ((method "textDocument/documentSymbol")
   6295           (params `(:textDocument ,(lsp--text-document-identifier)))
   6296           (tick (buffer-chars-modified-tick)))
   6297       (if (not lsp--document-symbols-request-async)
   6298           (prog1
   6299               (setq lsp--document-symbols (lsp-request method params))
   6300             (setq lsp--document-symbols-tick tick))
   6301         (lsp-request-async method params
   6302                            (lambda (document-symbols)
   6303                              (setq lsp--document-symbols document-symbols
   6304                                    lsp--document-symbols-tick tick)
   6305                              (lsp--imenu-refresh))
   6306                            :mode 'alive
   6307                            :cancel-token :document-symbols)
   6308         lsp--document-symbols))))
   6309 
   6310 (advice-add 'imenu-update-menubar :around
   6311             (lambda (oldfun &rest r)
   6312               (let ((lsp--document-symbols-request-async t))
   6313                 (apply oldfun r))))
   6314 
   6315 (defun lsp--document-symbols->document-symbols-hierarchy (document-symbols current-position)
   6316   "Convert DOCUMENT-SYMBOLS to symbols hierarchy on CURRENT-POSITION."
   6317   (-let (((symbol &as &DocumentSymbol? :children?)
   6318           (seq-find (-lambda ((&DocumentSymbol :range))
   6319                       (lsp-point-in-range? current-position range))
   6320                     document-symbols)))
   6321     (if children?
   6322         (cons symbol (lsp--document-symbols->document-symbols-hierarchy children? current-position))
   6323       (when symbol
   6324         (list symbol)))))
   6325 
   6326 (lsp-defun lsp--symbol-information->document-symbol ((&SymbolInformation :name :kind :location :container-name? :deprecated?))
   6327   "Convert a SymbolInformation to a DocumentInformation"
   6328   (lsp-make-document-symbol :name name
   6329                             :kind kind
   6330                             :range (lsp:location-range location)
   6331                             :children? nil
   6332                             :deprecated? deprecated?
   6333                             :selection-range (lsp:location-range location)
   6334                             :detail? container-name?))
   6335 
   6336 (defun lsp--symbols-informations->document-symbols-hierarchy (symbols-informations current-position)
   6337   "Convert SYMBOLS-INFORMATIONS to symbols hierarchy on CURRENT-POSITION."
   6338   (--> symbols-informations
   6339     (-keep (-lambda ((symbol &as &SymbolInformation :location (&Location :range)))
   6340              (when (lsp-point-in-range? current-position range)
   6341                (lsp--symbol-information->document-symbol symbol)))
   6342            it)
   6343     (sort it (-lambda ((&DocumentSymbol :range (&Range :start a-start-position :end a-end-position))
   6344                        (&DocumentSymbol :range (&Range :start b-start-position :end b-end-position)))
   6345                (and (lsp--position-compare b-start-position a-start-position)
   6346                     (lsp--position-compare a-end-position b-end-position))))))
   6347 
   6348 (defun lsp--symbols->document-symbols-hierarchy (symbols)
   6349   "Convert SYMBOLS to symbols-hierarchy."
   6350   (when-let ((first-symbol (lsp-seq-first symbols)))
   6351     (let ((cur-position (lsp-make-position :line (plist-get (lsp--cur-position) :line)
   6352                                            :character (plist-get (lsp--cur-position) :character))))
   6353       (if (lsp-symbol-information? first-symbol)
   6354           (lsp--symbols-informations->document-symbols-hierarchy symbols cur-position)
   6355         (lsp--document-symbols->document-symbols-hierarchy symbols cur-position)))))
   6356 
   6357 (defun lsp--xref-backend () 'xref-lsp)
   6358 
   6359 (cl-defmethod xref-backend-identifier-at-point ((_backend (eql xref-lsp)))
   6360   (propertize (or (thing-at-point 'symbol) "")
   6361               'identifier-at-point t))
   6362 
   6363 (defun lsp--xref-elements-index (symbols path)
   6364   (-mapcat
   6365    (-lambda (sym)
   6366      (pcase-exhaustive sym
   6367        ((DocumentSymbol :name :children? :selection-range (Range :start))
   6368         (cons (cons (concat path name)
   6369                     (lsp--position-to-point start))
   6370               (lsp--xref-elements-index children? (concat path name " / "))))
   6371        ((SymbolInformation :name :location (Location :range (Range :start)))
   6372         (list (cons (concat path name)
   6373                     (lsp--position-to-point start))))))
   6374    symbols))
   6375 
   6376 (defvar-local lsp--symbols-cache nil)
   6377 
   6378 (cl-defmethod xref-backend-identifier-completion-table ((_backend (eql xref-lsp)))
   6379   (if (lsp--find-workspaces-for "textDocument/documentSymbol")
   6380       (progn
   6381         (setq lsp--symbols-cache (lsp--xref-elements-index
   6382                                   (lsp--get-document-symbols) nil))
   6383         lsp--symbols-cache)
   6384     (list (propertize (or (thing-at-point 'symbol) "")
   6385                       'identifier-at-point t))))
   6386 
   6387 (cl-defmethod xref-backend-definitions ((_backend (eql xref-lsp)) identifier)
   6388   (save-excursion
   6389     (unless (get-text-property 0 'identifier-at-point identifier)
   6390       (goto-char (cl-rest (or (assoc identifier lsp--symbols-cache)
   6391                               (user-error "Unable to find symbol %s in current document" identifier)))))
   6392     (lsp--locations-to-xref-items (lsp-request "textDocument/definition"
   6393                                                (lsp--text-document-position-params)))))
   6394 
   6395 (cl-defmethod xref-backend-references ((_backend (eql xref-lsp)) identifier)
   6396   (save-excursion
   6397     (unless (get-text-property 0 'identifier-at-point identifier)
   6398       (goto-char (cl-rest (or (assoc identifier lsp--symbols-cache)
   6399                               (user-error "Unable to find symbol %s" identifier)))))
   6400     (lsp--locations-to-xref-items (lsp-request "textDocument/references"
   6401                                                (lsp--make-reference-params nil lsp-references-exclude-definition)))))
   6402 
   6403 (cl-defmethod xref-backend-apropos ((_backend (eql xref-lsp)) pattern)
   6404   (seq-map #'lsp--symbol-information-to-xref
   6405            (lsp-request "workspace/symbol" `(:query ,pattern))))
   6406 
   6407 (defcustom lsp-rename-use-prepare t
   6408   "Whether `lsp-rename' should do a prepareRename first.
   6409 For some language servers, textDocument/prepareRename might be
   6410 too slow, in which case this variable may be set to nil.
   6411 `lsp-rename' will then use `thing-at-point' `symbol' to determine
   6412 the symbol to rename at point."
   6413   :group 'lsp-mode
   6414   :type 'boolean)
   6415 
   6416 (defun lsp--get-symbol-to-rename ()
   6417   "Get a symbol to rename and placeholder at point.
   6418 Returns a cons ((START . END) . PLACEHOLDER?), and nil if
   6419 renaming is generally supported but cannot be done at point.
   6420 START and END are the bounds of the identifiers being renamed,
   6421 while PLACEHOLDER?, is either nil or a string suggested by the
   6422 language server as the initial input of a new-name prompt."
   6423   (unless (lsp-feature? "textDocument/rename")
   6424     (error "The connected server(s) doesn't support renaming"))
   6425   (if (and lsp-rename-use-prepare (lsp-feature? "textDocument/prepareRename"))
   6426       (when-let ((response
   6427                   (lsp-request "textDocument/prepareRename"
   6428                                (lsp--text-document-position-params))))
   6429         (let* ((bounds (lsp--range-to-region
   6430                         (if (lsp-range? response)
   6431                             response
   6432                           (lsp:prepare-rename-result-range response))))
   6433                (placeholder
   6434                 (and (not (lsp-range? response))
   6435                      (lsp:prepare-rename-result-placeholder response))))
   6436           (cons bounds placeholder)))
   6437     (when-let ((bounds (bounds-of-thing-at-point 'symbol)))
   6438       (cons bounds nil))))
   6439 
   6440 (defface lsp-face-rename '((t :underline t))
   6441   "Face used to highlight the identifier being renamed.
   6442 Renaming can be done using `lsp-rename'."
   6443   :group 'lsp-mode)
   6444 
   6445 (defface lsp-rename-placeholder-face '((t :inherit font-lock-variable-name-face))
   6446   "Face used to display the rename placeholder in.
   6447 When calling `lsp-rename' interactively, this will be the face of
   6448 the new name."
   6449   :group 'lsp-mode)
   6450 
   6451 (defvar lsp-rename-history '()
   6452   "History for `lsp--read-rename'.")
   6453 
   6454 (defun lsp--read-rename (at-point)
   6455   "Read a new name for a `lsp-rename' at `point' from the user.
   6456 AT-POINT shall be a structure as returned by
   6457 `lsp--get-symbol-to-rename'.
   6458 
   6459 Returns a string, which should be the new name for the identifier
   6460 at point. If renaming cannot be done at point (as determined from
   6461 AT-POINT), throw a `user-error'.
   6462 
   6463 This function is for use in `lsp-rename' only, and shall not be
   6464 relied upon."
   6465   (unless at-point
   6466     (user-error "`lsp-rename' is invalid here"))
   6467   (-let* ((((start . end) . placeholder?) at-point)
   6468           ;; Do the `buffer-substring' first to not include `lsp-face-rename'
   6469           (rename-me (buffer-substring start end))
   6470           (placeholder (or placeholder? rename-me))
   6471           (placeholder (propertize placeholder 'face 'lsp-rename-placeholder-face))
   6472 
   6473           overlay)
   6474     ;; We need unwind protect, as the user might cancel here, causing the
   6475     ;; overlay to linger.
   6476     (unwind-protect
   6477         (progn
   6478           (setq overlay (make-overlay start end))
   6479           (overlay-put overlay 'face 'lsp-face-rename)
   6480 
   6481           (read-string (format "Rename %s to: " rename-me) placeholder
   6482                        'lsp-rename-history))
   6483       (and overlay (delete-overlay overlay)))))
   6484 
   6485 (defun lsp-rename (newname)
   6486   "Rename the symbol (and all references to it) under point to NEWNAME."
   6487   (interactive (list (lsp--read-rename (lsp--get-symbol-to-rename))))
   6488   (when-let ((edits (lsp-request "textDocument/rename"
   6489                                  `( :textDocument ,(lsp--text-document-identifier)
   6490                                     :position ,(lsp--cur-position)
   6491                                     :newName ,newname))))
   6492     (lsp--apply-workspace-edit edits 'rename)))
   6493 
   6494 (defun lsp--on-rename-file (old-func old-name new-name &optional ok-if-already-exists?)
   6495   "Advice around function `rename-file'.
   6496 Applies OLD-FUNC with OLD-NAME, NEW-NAME and OK-IF-ALREADY-EXISTS?.
   6497 
   6498 This advice sends workspace/willRenameFiles before renaming file
   6499 to check if server wants to apply any workspaceEdits after renamed."
   6500   (if (and lsp-apply-edits-after-file-operations
   6501            (lsp--send-will-rename-files-p old-name))
   6502       (let ((params (lsp-make-rename-files-params
   6503                      :files (vector (lsp-make-file-rename
   6504                                      :oldUri (lsp--path-to-uri old-name)
   6505                                      :newUri (lsp--path-to-uri new-name))))))
   6506         (when-let ((edits (lsp-request "workspace/willRenameFiles" params)))
   6507           (lsp--apply-workspace-edit edits 'rename-file)
   6508           (funcall old-func old-name new-name ok-if-already-exists?)
   6509           (when (lsp--send-did-rename-files-p)
   6510             (lsp-notify "workspace/didRenameFiles" params))))
   6511     (funcall old-func old-name new-name ok-if-already-exists?)))
   6512 
   6513 (advice-add 'rename-file :around #'lsp--on-rename-file)
   6514 
   6515 (defcustom lsp-xref-force-references nil
   6516   "If non-nil threat everything as references(e. g. jump if only one item.)"
   6517   :group 'lsp-mode
   6518   :type 'boolean)
   6519 
   6520 (defun lsp-show-xrefs (xrefs display-action references?)
   6521   (unless (region-active-p) (push-mark nil t))
   6522   (if (boundp 'xref-show-definitions-function)
   6523       (with-no-warnings
   6524         (xref-push-marker-stack)
   6525         (funcall (if (and references? (not lsp-xref-force-references))
   6526                      xref-show-xrefs-function
   6527                    xref-show-definitions-function)
   6528                  (-const xrefs)
   6529                  `((window . ,(selected-window))
   6530                    (display-action . ,display-action)
   6531                    ,(if (and references? (not lsp-xref-force-references))
   6532                         `(auto-jump . ,xref-auto-jump-to-first-xref)
   6533                       `(auto-jump . ,xref-auto-jump-to-first-definition)))))
   6534     (xref--show-xrefs xrefs display-action)))
   6535 
   6536 (cl-defmethod seq-empty-p ((ht hash-table))
   6537   "Function `seq-empty-p' for hash-table."
   6538   (hash-table-empty-p ht))
   6539 
   6540 (cl-defun lsp-find-locations (method &optional extra &key display-action references?)
   6541   "Send request named METHOD and get cross references of the symbol under point.
   6542 EXTRA is a plist of extra parameters.
   6543 REFERENCES? t when METHOD returns references."
   6544   (let ((loc (lsp-request method
   6545                           (append (lsp--text-document-position-params) extra))))
   6546     (if (seq-empty-p loc)
   6547         (lsp--error "Not found for: %s" (or (thing-at-point 'symbol t) ""))
   6548       (lsp-show-xrefs (lsp--locations-to-xref-items loc) display-action references?))))
   6549 
   6550 (cl-defun lsp-find-declaration (&key display-action)
   6551   "Find declarations of the symbol under point."
   6552   (interactive)
   6553   (lsp-find-locations "textDocument/declaration" nil :display-action display-action))
   6554 
   6555 (cl-defun lsp-find-definition (&key display-action)
   6556   "Find definitions of the symbol under point."
   6557   (interactive)
   6558   (lsp-find-locations "textDocument/definition" nil :display-action display-action))
   6559 
   6560 (defun lsp-find-definition-mouse (click)
   6561   "Click to start `lsp-find-definition' at clicked point."
   6562   (interactive "e")
   6563   (let* ((ec (event-start click))
   6564          (p1 (posn-point ec))
   6565          (w1 (posn-window ec)))
   6566     (select-window w1)
   6567     (goto-char p1)
   6568     (lsp-find-definition)))
   6569 
   6570 (cl-defun lsp-find-implementation (&key display-action)
   6571   "Find implementations of the symbol under point."
   6572   (interactive)
   6573   (lsp-find-locations "textDocument/implementation"
   6574                       nil
   6575                       :display-action display-action
   6576                       :references? t))
   6577 
   6578 (cl-defun lsp-find-references (&optional exclude-declaration &key display-action)
   6579   "Find references of the symbol under point."
   6580   (interactive "P")
   6581   (lsp-find-locations "textDocument/references"
   6582                       (list :context `(:includeDeclaration ,(lsp-json-bool (not (or exclude-declaration lsp-references-exclude-definition)))))
   6583                       :display-action display-action
   6584                       :references? t))
   6585 
   6586 (cl-defun lsp-find-type-definition (&key display-action)
   6587   "Find type definitions of the symbol under point."
   6588   (interactive)
   6589   (lsp-find-locations "textDocument/typeDefinition" nil :display-action display-action))
   6590 
   6591 (defalias 'lsp-find-custom #'lsp-find-locations)
   6592 (defalias 'lsp-goto-implementation #'lsp-find-implementation)
   6593 (defalias 'lsp-goto-type-definition #'lsp-find-type-definition)
   6594 
   6595 (with-eval-after-load 'evil
   6596   (evil-set-command-property 'lsp-find-definition :jump t)
   6597   (evil-set-command-property 'lsp-find-implementation :jump t)
   6598   (evil-set-command-property 'lsp-find-references :jump t)
   6599   (evil-set-command-property 'lsp-find-type-definition :jump t))
   6600 
   6601 (defun lsp--workspace-method-supported? (check-command method capability workspace)
   6602   (with-lsp-workspace workspace
   6603     (if check-command
   6604         (funcall check-command workspace)
   6605       (or
   6606        (when capability (lsp--capability capability))
   6607        (lsp--registered-capability method)
   6608        (and (not capability) (not check-command))))))
   6609 
   6610 (defun lsp-disable-method-for-server (method server-id)
   6611   "Disable METHOD for SERVER-ID."
   6612   (cl-callf
   6613       (lambda (reqs)
   6614         (-let (((&plist :check-command :capability) reqs))
   6615           (list :check-command
   6616                 (lambda (workspace)
   6617                   (unless (-> workspace
   6618                               lsp--workspace-client
   6619                               lsp--client-server-id
   6620                               (eq server-id))
   6621                     (lsp--workspace-method-supported? check-command
   6622                                                       method
   6623                                                       capability
   6624                                                       workspace))))))
   6625       (alist-get method lsp-method-requirements nil nil 'string=)))
   6626 
   6627 (defun lsp--find-workspaces-for (msg-or-method)
   6628   "Find all workspaces in the current project that can handle MSG."
   6629   (let ((method (if (stringp msg-or-method)
   6630                     msg-or-method
   6631                   (plist-get msg-or-method :method))))
   6632     (-if-let (reqs (cdr (assoc method lsp-method-requirements)))
   6633         (-let (((&plist :capability :check-command) reqs))
   6634           (-filter
   6635            (-partial #'lsp--workspace-method-supported?
   6636                      check-command method capability)
   6637            (lsp-workspaces)))
   6638       (lsp-workspaces))))
   6639 
   6640 (defun lsp-can-execute-command? (command-name)
   6641   "Returns non-nil if current language server(s) can execute COMMAND-NAME.
   6642 The command is executed via `workspace/executeCommand'"
   6643   (cl-position
   6644    command-name
   6645    (lsp:execute-command-options-commands
   6646     (lsp:server-capabilities-execute-command-provider?
   6647      (lsp--server-capabilities)))
   6648    :test #'equal))
   6649 
   6650 (defalias 'lsp-feature? 'lsp--find-workspaces-for)
   6651 
   6652 (cl-defmethod lsp-execute-command (_server _command _arguments)
   6653   "Dispatch COMMAND execution."
   6654   (signal 'cl-no-applicable-method nil))
   6655 
   6656 (defun lsp-workspace-command-execute (command &optional args)
   6657   "Execute workspace COMMAND with ARGS."
   6658   (condition-case-unless-debug err
   6659       (let ((params (if args
   6660                         (list :command command :arguments args)
   6661                       (list :command command))))
   6662         (lsp-request "workspace/executeCommand" params))
   6663     (error
   6664      (error "`workspace/executeCommand' with `%s' failed.\n\n%S"
   6665             command err))))
   6666 
   6667 (defun lsp-send-execute-command (command &optional args)
   6668   "Create and send a `workspace/executeCommand' message having command COMMAND
   6669 and optional ARGS."
   6670   (lsp-workspace-command-execute command args))
   6671 
   6672 (defalias 'lsp-point-to-position #'lsp--point-to-position)
   6673 (defalias 'lsp-text-document-identifier #'lsp--text-document-identifier)
   6674 (defalias 'lsp--send-execute-command #'lsp-send-execute-command)
   6675 (defalias 'lsp-on-open #'lsp--text-document-did-open)
   6676 (defalias 'lsp-on-save #'lsp--text-document-did-save)
   6677 
   6678 (defun lsp--set-configuration (settings)
   6679   "Set the SETTINGS for the lsp server."
   6680   (lsp-notify "workspace/didChangeConfiguration" `(:settings ,settings)))
   6681 
   6682 (defun lsp-current-buffer ()
   6683   (or lsp--virtual-buffer
   6684       (current-buffer)))
   6685 
   6686 (defun lsp-buffer-live-p (buffer-id)
   6687   (if-let ((buffer-live (plist-get buffer-id :buffer-live?)))
   6688       (funcall buffer-live buffer-id)
   6689     (buffer-live-p buffer-id)))
   6690 
   6691 (defun lsp--on-set-visited-file-name (old-func &rest args)
   6692   "Advice around function `set-visited-file-name'.
   6693 
   6694 This advice sends textDocument/didClose for the old file and
   6695 textDocument/didOpen for the new file."
   6696   (when lsp--cur-workspace
   6697     (lsp--text-document-did-close t))
   6698   (prog1 (apply old-func args)
   6699     (when lsp--cur-workspace
   6700       (lsp--text-document-did-open))))
   6701 
   6702 (advice-add 'set-visited-file-name :around #'lsp--on-set-visited-file-name)
   6703 
   6704 (defvar lsp--flushing-delayed-changes nil)
   6705 
   6706 (defun lsp--send-no-wait (message proc)
   6707   "Send MESSAGE to PROC without waiting for further output."
   6708 
   6709   (unless lsp--flushing-delayed-changes
   6710     (let ((lsp--flushing-delayed-changes t))
   6711       (lsp--flush-delayed-changes)))
   6712   (lsp-process-send proc message))
   6713 
   6714 (define-error 'lsp-parse-error
   6715   "Error parsing message from language server" 'lsp-error)
   6716 (define-error 'lsp-unknown-message-type
   6717   "Unknown message type" '(lsp-error lsp-parse-error))
   6718 (define-error 'lsp-unknown-json-rpc-version
   6719   "Unknown JSON-RPC protocol version" '(lsp-error lsp-parse-error))
   6720 (define-error 'lsp-no-content-length
   6721   "Content-Length header missing in message" '(lsp-error lsp-parse-error))
   6722 (define-error 'lsp-invalid-header-name
   6723   "Invalid header name" '(lsp-error lsp-parse-error))
   6724 
   6725 ;;  id  method
   6726 ;;   x    x     request
   6727 ;;   x    .     response
   6728 ;;   .    x     notification
   6729 (defun lsp--get-message-type (json-data)
   6730   "Get the message type from JSON-DATA."
   6731   (if (lsp:json-message-id? json-data)
   6732       (if (lsp:json-message-error? json-data)
   6733           'response-error
   6734         (if (lsp:json-message-method? json-data)
   6735             'request
   6736           'response))
   6737     'notification))
   6738 
   6739 (defconst lsp--default-notification-handlers
   6740   (ht ("window/showMessage" #'lsp--window-show-message)
   6741       ("window/logMessage" #'lsp--window-log-message)
   6742       ("window/showInputBox" #'lsp--window-show-input-box)
   6743       ("window/showQuickPick" #'lsp--window-show-quick-pick)
   6744       ("textDocument/publishDiagnostics" #'lsp--on-diagnostics)
   6745       ("textDocument/diagnosticsEnd" #'ignore)
   6746       ("textDocument/diagnosticsBegin" #'ignore)
   6747       ("telemetry/event" #'ignore)
   6748       ("$/progress" (lambda (workspace params)
   6749                       (funcall lsp-progress-function workspace params)))))
   6750 
   6751 (lsp-defun lsp--on-notification (workspace (&JSONNotification :params :method))
   6752   "Call the appropriate handler for NOTIFICATION."
   6753   (-let ((client (lsp--workspace-client workspace)))
   6754     (when (lsp--log-io-p method)
   6755       (lsp--log-entry-new (lsp--make-log-entry method nil params 'incoming-notif)
   6756                           lsp--cur-workspace))
   6757     (if-let ((handler (or (gethash method (lsp--client-notification-handlers client))
   6758                           (gethash method lsp--default-notification-handlers))))
   6759         (funcall handler workspace params)
   6760       (when (and method (not (string-prefix-p "$" method)))
   6761         (lsp-warn "Unknown notification: %s" method)))))
   6762 
   6763 (lsp-defun lsp--build-workspace-configuration-response ((&ConfigurationParams :items))
   6764   "Get section configuration.
   6765 PARAMS are the `workspace/configuration' request params"
   6766   (->> items
   6767        (-map (-lambda ((&ConfigurationItem :section?))
   6768                (-let* ((path-parts (split-string section? "\\."))
   6769                        (path-without-last (s-join "." (-slice path-parts 0 -1)))
   6770                        (path-parts-len (length path-parts)))
   6771                  (cond
   6772                   ((<= path-parts-len 1)
   6773                    (ht-get (lsp-configuration-section section?)
   6774                            (car-safe path-parts)
   6775                            (ht-create)))
   6776                   ((> path-parts-len 1)
   6777                    (when-let ((section (lsp-configuration-section path-without-last))
   6778                               (keys path-parts))
   6779                      (while (and keys section)
   6780                        (setf section (ht-get section (pop keys))))
   6781                      section))))))
   6782        (apply #'vector)))
   6783 
   6784 (defun lsp--ms-since (timestamp)
   6785   "Integer number of milliseconds since TIMESTAMP.  Fractions discarded."
   6786   (floor (* 1000 (float-time (time-since timestamp)))))
   6787 
   6788 (defun lsp--send-request-response (workspace recv-time request response)
   6789   "Send the RESPONSE for REQUEST in WORKSPACE and log if needed."
   6790   (-let* (((&JSONResponse :params :method :id) request)
   6791           (process (lsp--workspace-proc workspace))
   6792           (response (lsp--make-response id response))
   6793           (req-entry (and lsp-log-io
   6794                           (lsp--make-log-entry method id params 'incoming-req)))
   6795           (resp-entry (and lsp-log-io
   6796                            (lsp--make-log-entry method id response 'outgoing-resp
   6797                                                 (lsp--ms-since recv-time)))))
   6798     ;; Send response to the server.
   6799     (when (lsp--log-io-p method)
   6800       (lsp--log-entry-new req-entry workspace)
   6801       (lsp--log-entry-new resp-entry workspace))
   6802     (lsp--send-no-wait response process)))
   6803 
   6804 (lsp-defun lsp--on-request (workspace (request &as &JSONRequest :params :method))
   6805   "Call the appropriate handler for REQUEST, and send the return value to the
   6806 server. WORKSPACE is the active workspace."
   6807   (-let* ((recv-time (current-time))
   6808           (client (lsp--workspace-client workspace))
   6809           (buffers (lsp--workspace-buffers workspace))
   6810           handler
   6811           (response (cond
   6812                      ((setq handler (gethash method (lsp--client-request-handlers client) nil))
   6813                       (funcall handler workspace params))
   6814                      ((setq handler (gethash method (lsp--client-async-request-handlers client) nil))
   6815                       (funcall handler workspace params
   6816                                (-partial #'lsp--send-request-response
   6817                                          workspace recv-time request))
   6818                       'delay-response)
   6819                      ((equal method "client/registerCapability")
   6820                       (mapc #'lsp--server-register-capability
   6821                             (lsp:registration-params-registrations params))
   6822                       (mapc (lambda (buf)
   6823                               (when (lsp-buffer-live-p buf)
   6824                                 (lsp-with-current-buffer buf
   6825                                   (lsp-unconfig-buffer)
   6826                                   (lsp-configure-buffer))))
   6827                             buffers)
   6828                       nil)
   6829                      ((equal method "window/showMessageRequest")
   6830                       (let ((choice (lsp--window-log-message-request params)))
   6831                         `(:title ,choice)))
   6832                      ((equal method "window/showDocument")
   6833                       (let ((success? (lsp--window-show-document params)))
   6834                         (lsp-make-show-document-result :success (or success?
   6835                                                                     :json-false))))
   6836                      ((equal method "client/unregisterCapability")
   6837                       (mapc #'lsp--server-unregister-capability
   6838                             (lsp:unregistration-params-unregisterations params))
   6839                       (mapc (lambda (buf)
   6840                               (when (lsp-buffer-live-p buf)
   6841                                 (lsp-with-current-buffer buf
   6842                                   (lsp-unconfig-buffer)
   6843                                   (lsp-configure-buffer))))
   6844                             buffers)
   6845                       nil)
   6846                      ((equal method "workspace/applyEdit")
   6847                       (list :applied (condition-case err
   6848                                          (prog1 t
   6849                                            (lsp--apply-workspace-edit (lsp:apply-workspace-edit-params-edit params) 'server-requested))
   6850                                        (error
   6851                                         (lsp--error "Failed to apply edits with message %s"
   6852                                                     (error-message-string err))
   6853                                         :json-false))))
   6854                      ((equal method "workspace/configuration")
   6855                       (with-lsp-workspace workspace
   6856                         (if-let ((buf (car buffers)))
   6857                             (lsp-with-current-buffer buf
   6858                               (lsp--build-workspace-configuration-response params))
   6859                           (lsp--with-workspace-temp-buffer (lsp--workspace-root workspace)
   6860                             (lsp--build-workspace-configuration-response params)))))
   6861                      ((equal method "workspace/workspaceFolders")
   6862                       (let ((folders (or (-> workspace
   6863                                              (lsp--workspace-client)
   6864                                              (lsp--client-server-id)
   6865                                              (gethash (lsp-session-server-id->folders (lsp-session))))
   6866                                          (lsp-session-folders (lsp-session)))))
   6867                         (->> folders
   6868                              (-distinct)
   6869                              (-map (lambda (folder)
   6870                                      (list :uri (lsp--path-to-uri folder))))
   6871                              (apply #'vector))))
   6872                      ((equal method "window/workDoneProgress/create")
   6873                       nil ;; no specific reply, no processing required
   6874                       )
   6875                      ((equal method "workspace/semanticTokens/refresh")
   6876                       (when (and lsp-semantic-tokens-enable
   6877                                  (fboundp 'lsp--semantic-tokens-on-refresh))
   6878                         (lsp--semantic-tokens-on-refresh workspace))
   6879                       nil)
   6880                      ((equal method "workspace/codeLens/refresh")
   6881                       (when (and lsp-lens-enable
   6882                                  (fboundp 'lsp--lens-on-refresh))
   6883                         (lsp--lens-on-refresh workspace))
   6884                       nil)
   6885                      (t (lsp-warn "Unknown request method: %s" method) nil))))
   6886     ;; Send response to the server.
   6887     (unless (eq response 'delay-response)
   6888       (lsp--send-request-response workspace recv-time request response))))
   6889 
   6890 (lsp-defun lsp--error-string ((&JSONError :message :code))
   6891   "Format ERR as a user friendly string."
   6892   (format "Error from the Language Server: %s (%s)"
   6893           message
   6894           (or (car (alist-get code lsp--errors)) "Unknown error")))
   6895 
   6896 (defun lsp--get-body-length (headers)
   6897   (let ((content-length (cdr (assoc "Content-Length" headers))))
   6898     (if content-length
   6899         (string-to-number content-length)
   6900 
   6901       ;; This usually means either the server or our parser is
   6902       ;; screwed up with a previous Content-Length
   6903       (error "No Content-Length header"))))
   6904 
   6905 (defun lsp--parse-header (s)
   6906   "Parse string S as a LSP (KEY . VAL) header."
   6907   (let ((pos (string-match "\:" s))
   6908         key val)
   6909     (unless pos
   6910       (signal 'lsp-invalid-header-name (list s)))
   6911     (setq key (substring s 0 pos)
   6912           val (s-trim-left (substring s (+ 1 pos))))
   6913     (when (equal key "Content-Length")
   6914       (cl-assert (cl-loop for c across val
   6915                           when (or (> c ?9) (< c ?0)) return nil
   6916                           finally return t)
   6917                  nil (format "Invalid Content-Length value: %s" val)))
   6918     (cons key val)))
   6919 
   6920 (defmacro lsp--read-json (str)
   6921   "Read json string STR."
   6922   (if (progn
   6923         (require 'json)
   6924         (fboundp 'json-parse-string))
   6925       `(json-parse-string ,str
   6926                           :object-type (if lsp-use-plists
   6927                                            'plist
   6928                                          'hash-table)
   6929                           :null-object nil
   6930                           :false-object nil)
   6931     `(let ((json-array-type 'vector)
   6932            (json-object-type (if lsp-use-plists
   6933                                  'plist
   6934                                'hash-table))
   6935            (json-false nil))
   6936        (json-read-from-string ,str))))
   6937 
   6938 (defmacro lsp-json-read-buffer ()
   6939   "Read json from the current buffer."
   6940   (if (progn
   6941         (require 'json)
   6942         (fboundp 'json-parse-buffer))
   6943       `(json-parse-buffer :object-type (if lsp-use-plists
   6944                                            'plist
   6945                                          'hash-table)
   6946                           :null-object nil
   6947                           :false-object nil)
   6948     `(let ((json-array-type 'vector)
   6949            (json-object-type (if lsp-use-plists
   6950                                  'plist
   6951                                'hash-table))
   6952            (json-false nil))
   6953        (json-read))))
   6954 
   6955 (defun lsp--read-json-file (file-path)
   6956   "Read json file."
   6957   (-> file-path
   6958     (f-read-text)
   6959     (lsp--read-json)))
   6960 
   6961 (defun lsp--parser-on-message (json-data workspace)
   6962   "Called when the parser P read a complete MSG from the server."
   6963   (with-demoted-errors "Error processing message %S."
   6964     (with-lsp-workspace workspace
   6965       (let* ((client (lsp--workspace-client workspace))
   6966              (id (--when-let (lsp:json-response-id json-data)
   6967                    (if (stringp it) (string-to-number it) it)))
   6968              (data (lsp:json-response-result json-data)))
   6969         (pcase (lsp--get-message-type json-data)
   6970           ('response
   6971            (cl-assert id)
   6972            (-let [(callback _ method _ before-send) (gethash id (lsp--client-response-handlers client))]
   6973              (when (lsp--log-io-p method)
   6974                (lsp--log-entry-new
   6975                 (lsp--make-log-entry method id data 'incoming-resp
   6976                                      (lsp--ms-since before-send))
   6977                 workspace))
   6978              (when callback
   6979                (remhash id (lsp--client-response-handlers client))
   6980                (funcall callback (lsp:json-response-result json-data)))))
   6981           ('response-error
   6982            (cl-assert id)
   6983            (-let [(_ callback method _ before-send) (gethash id (lsp--client-response-handlers client))]
   6984              (when (lsp--log-io-p method)
   6985                (lsp--log-entry-new
   6986                 (lsp--make-log-entry method id (lsp:json-response-error-error json-data)
   6987                                      'incoming-resp (lsp--ms-since before-send))
   6988                 workspace))
   6989              (when callback
   6990                (remhash id (lsp--client-response-handlers client))
   6991                (funcall callback (lsp:json-response-error-error json-data)))))
   6992           ('notification
   6993            (lsp--on-notification workspace json-data))
   6994           ('request (lsp--on-request workspace json-data)))))))
   6995 
   6996 (defun lsp--create-filter-function (workspace)
   6997   "Make filter for the workspace."
   6998   (let ((body-received 0)
   6999         leftovers body-length body chunk)
   7000     (lambda (_proc input)
   7001       (setf chunk (if (s-blank? leftovers)
   7002                       input
   7003                     (concat leftovers input)))
   7004 
   7005       (let (messages)
   7006         (while (not (s-blank? chunk))
   7007           (if (not body-length)
   7008               ;; Read headers
   7009               (if-let ((body-sep-pos (string-match-p "\r\n\r\n" chunk)))
   7010                   ;; We've got all the headers, handle them all at once:
   7011                   (setf body-length (lsp--get-body-length
   7012                                      (mapcar #'lsp--parse-header
   7013                                              (split-string
   7014                                               (substring-no-properties chunk
   7015                                                                        (or (string-match-p "Content-Length" chunk)
   7016                                                                            (error "Unable to find Content-Length header."))
   7017                                                                        body-sep-pos)
   7018                                               "\r\n")))
   7019                         body-received 0
   7020                         leftovers nil
   7021                         chunk (substring-no-properties chunk (+ body-sep-pos 4)))
   7022 
   7023                 ;; Haven't found the end of the headers yet. Save everything
   7024                 ;; for when the next chunk arrives and await further input.
   7025                 (setf leftovers chunk
   7026                       chunk nil))
   7027             (let* ((chunk-length (string-bytes chunk))
   7028                    (left-to-receive (- body-length body-received))
   7029                    (this-body (if (< left-to-receive chunk-length)
   7030                                   (prog1 (substring-no-properties chunk 0 left-to-receive)
   7031                                     (setf chunk (substring-no-properties chunk left-to-receive)))
   7032                                 (prog1 chunk
   7033                                   (setf chunk nil))))
   7034                    (body-bytes (string-bytes this-body)))
   7035               (push this-body body)
   7036               (setf body-received (+ body-received body-bytes))
   7037               (when (>= chunk-length left-to-receive)
   7038                 (condition-case err
   7039                     (with-temp-buffer
   7040                       (apply #'insert
   7041                              (nreverse
   7042                               (prog1 body
   7043                                 (setf leftovers nil
   7044                                       body-length nil
   7045                                       body-received nil
   7046                                       body nil))))
   7047                       (decode-coding-region (point-min)
   7048                                             (point-max)
   7049                                             'utf-8)
   7050                       (goto-char (point-min))
   7051                       (push (lsp-json-read-buffer) messages))
   7052 
   7053                   (error
   7054                    (lsp-warn "Failed to parse the following chunk:\n'''\n%s\n'''\nwith message %s"
   7055                              (concat leftovers input)
   7056                              err)))))))
   7057         (mapc (lambda (msg)
   7058                 (lsp--parser-on-message msg workspace))
   7059               (nreverse messages))))))
   7060 
   7061 (defvar-local lsp--line-col-to-point-hash-table nil
   7062   "Hash table with keys (line . col) and values that are either point positions
   7063 or markers.")
   7064 
   7065 (defcustom lsp-imenu-detailed-outline t
   7066   "Whether `lsp-imenu' should include signatures.
   7067 This will be ignored if the server doesn't provide the necessary
   7068 information, for example if it doesn't support DocumentSymbols."
   7069   :group 'lsp-imenu
   7070   :type 'boolean)
   7071 
   7072 (defcustom lsp-imenu-hide-parent-details t
   7073   "Whether `lsp-imenu' should hide signatures of parent nodes."
   7074   :group 'lsp-imenu
   7075   :type 'boolean)
   7076 
   7077 (defface lsp-details-face '((t :height 0.8 :inherit shadow))
   7078   "Used to display additional information throughout `lsp'.
   7079 Things like line numbers, signatures, ... are considered
   7080 additional information. Often, additional faces are defined that
   7081 inherit from this face by default, like `lsp-signature-face', and
   7082 they may be customized for finer control."
   7083   :group 'lsp-mode)
   7084 
   7085 (defface lsp-signature-face '((t :inherit lsp-details-face))
   7086   "Used to display signatures in `imenu', ...."
   7087   :group 'lsp-mode)
   7088 
   7089 (lsp-defun lsp-render-symbol ((&DocumentSymbol :name :detail? :deprecated?)
   7090                               show-detail?)
   7091   "Render INPUT0, an `&DocumentSymbol', to a string.
   7092 If SHOW-DETAIL? is set, make use of its `:detail?' field (often
   7093 the signature)."
   7094   (let ((detail (and show-detail? (s-present? detail?)
   7095                      (propertize (concat " " (s-trim-left detail?))
   7096                                  'face 'lsp-signature-face)))
   7097         (name (if deprecated?
   7098                   (propertize name 'face 'lsp-face-semhl-deprecated) name)))
   7099     (concat name detail)))
   7100 
   7101 (lsp-defun lsp-render-symbol-information ((&SymbolInformation :name :deprecated? :container-name?)
   7102                                           separator)
   7103   "Render a piece of SymbolInformation.
   7104 Handle :deprecated?. If SEPARATOR is non-nil, the
   7105 symbol's (optional) parent, SEPARATOR and the symbol itself are
   7106 concatenated."
   7107   (when (and separator container-name? (not (string-empty-p container-name?)))
   7108     (setq name (concat name separator container-name?)))
   7109   (if deprecated? (propertize name 'face 'lsp-face-semhl-deprecated) name))
   7110 
   7111 (defun lsp--symbol-to-imenu-elem (sym)
   7112   "Convert SYM to imenu element.
   7113 
   7114 SYM is a SymbolInformation message.
   7115 
   7116 Return a cons cell (full-name . start-point)."
   7117   (let ((start-point (ht-get lsp--line-col-to-point-hash-table
   7118                              (lsp--get-line-and-col sym))))
   7119     (cons (lsp-render-symbol-information
   7120            sym (and lsp-imenu-show-container-name
   7121                     lsp-imenu-container-name-separator))
   7122           start-point)))
   7123 
   7124 (lsp-defun lsp--symbol-to-hierarchical-imenu-elem ((sym &as &DocumentSymbol :children?))
   7125   "Convert SYM to hierarchical imenu elements.
   7126 
   7127 SYM is a DocumentSymbol message.
   7128 
   7129 Return cons cell (\"symbol-name (symbol-kind)\" . start-point) if
   7130 SYM doesn't have any children. Otherwise return a cons cell with
   7131 an alist
   7132 
   7133   (\"symbol-name\" . ((\"(symbol-kind)\" . start-point)
   7134                     cons-cells-from-children))"
   7135   (let ((filtered-children (lsp--imenu-filter-symbols children?))
   7136         (signature (lsp-render-symbol sym lsp-imenu-detailed-outline)))
   7137     (if (seq-empty-p filtered-children)
   7138         (cons signature
   7139               (ht-get lsp--line-col-to-point-hash-table
   7140                       (lsp--get-line-and-col sym)))
   7141       (cons signature
   7142             (lsp--imenu-create-hierarchical-index filtered-children)))))
   7143 
   7144 (lsp-defun lsp--symbol-ignore ((&SymbolInformation :kind))
   7145   "Determine if SYM is for the current document and is to be shown."
   7146   ;; It's a SymbolInformation or DocumentSymbol, which is always in the
   7147   ;; current buffer file.
   7148   (and lsp-imenu-index-symbol-kinds
   7149        (numberp kind)
   7150        (let ((clamped-kind (if (< 0 kind (length lsp/symbol-kind-lookup))
   7151                                kind
   7152                              0)))
   7153          (not (memql (aref lsp/symbol-kind-lookup clamped-kind)
   7154                      lsp-imenu-index-symbol-kinds)))))
   7155 
   7156 (lsp-defun lsp--get-symbol-type ((&SymbolInformation :kind))
   7157   "The string name of the kind of SYM."
   7158   (alist-get kind lsp-symbol-kinds "Other"))
   7159 
   7160 (defun lsp--get-line-and-col (sym)
   7161   "Obtain the line and column corresponding to SYM."
   7162   (-let* ((location (lsp:symbol-information-location sym))
   7163           (name-range (or (and location (lsp:location-range location))
   7164                           (lsp:document-symbol-selection-range sym)))
   7165           ((&Range :start (&Position :line :character)) name-range))
   7166     (cons line character)))
   7167 
   7168 (defun lsp--collect-lines-and-cols (symbols)
   7169   "Return a sorted list ((line . col) ...) of the locations of SYMBOLS."
   7170   (let ((stack (mapcar 'identity symbols))
   7171         line-col-list)
   7172     (while stack
   7173       (let ((sym (pop stack)))
   7174         (push (lsp--get-line-and-col sym) line-col-list)
   7175         (unless (seq-empty-p (lsp:document-symbol-children? sym))
   7176           (setf stack (nconc (lsp--imenu-filter-symbols (lsp:document-symbol-children? sym)) stack)))))
   7177     (-sort #'lsp--line-col-comparator line-col-list)))
   7178 
   7179 (defun lsp--convert-line-col-to-points-batch (line-col-list)
   7180   "Convert a sorted list of positions from line-column
   7181 representation to point representation."
   7182   (let ((line-col-to-point-map (ht-create))
   7183         (inhibit-field-text-motion t)
   7184         (curr-line 0))
   7185     (lsp-save-restriction-and-excursion
   7186       (goto-char (point-min))
   7187       (cl-loop for (line . col) in line-col-list do
   7188                (forward-line (- line curr-line))
   7189                (setq curr-line line)
   7190                (let ((line-end (line-end-position)))
   7191                  (if (or (not col) (> col (- line-end (point))))
   7192                      (goto-char line-end)
   7193                    (forward-char col)))
   7194                (ht-set! line-col-to-point-map (cons line col) (if imenu-use-markers
   7195                                                                   (point-marker)
   7196                                                                 (point)))))
   7197     line-col-to-point-map))
   7198 
   7199 (cl-defun lsp--line-col-comparator ((l1 . c1) (l2 . c2))
   7200   (or (< l1 l2)
   7201       (and (= l1 l2)
   7202            (cond ((and c1 c2)
   7203                   (< c1 c2))
   7204                  (c1 t)))))
   7205 
   7206 (defun lsp-imenu-create-uncategorized-index (symbols)
   7207   "Create imenu index from document SYMBOLS.
   7208 This function, unlike `lsp-imenu-create-categorized-index', does
   7209 not categorize by type, but instead returns an `imenu' index
   7210 corresponding to the symbol hierarchy returned by the server
   7211 directly."
   7212   (let* ((lsp--line-col-to-point-hash-table (-> symbols
   7213                                                 lsp--collect-lines-and-cols
   7214                                                 lsp--convert-line-col-to-points-batch)))
   7215     (if (lsp--imenu-hierarchical-p symbols)
   7216         (lsp--imenu-create-hierarchical-index symbols)
   7217       (lsp--imenu-create-non-hierarchical-index symbols))))
   7218 
   7219 (defcustom lsp-imenu-symbol-kinds
   7220   '((1 . "Files")
   7221     (2 . "Modules")
   7222     (3 . "Namespaces")
   7223     (4 . "Packages")
   7224     (5 . "Classes")
   7225     (6 . "Methods")
   7226     (7 . "Properties")
   7227     (8 . "Fields")
   7228     (9 . "Constructors")
   7229     (10 . "Enums")
   7230     (11 . "Interfaces")
   7231     (12 . "Functions")
   7232     (13 . "Variables")
   7233     (14 . "Constants")
   7234     (15 . "Strings")
   7235     (16 . "Numbers")
   7236     (17 . "Booleans")
   7237     (18 . "Arrays")
   7238     (19 . "Objects")
   7239     (20 . "Keys")
   7240     (21 . "Nulls")
   7241     (22 . "Enum Members")
   7242     (23 . "Structs")
   7243     (24 . "Events")
   7244     (25 . "Operators")
   7245     (26 . "Type Parameters"))
   7246   "`lsp-symbol-kinds', but only used by `imenu'.
   7247 A new variable is needed, as it is `imenu' convention to use
   7248 pluralized categories, which `lsp-symbol-kinds' doesn't. If the
   7249 non-pluralized names are preferred, this can be set to
   7250 `lsp-symbol-kinds'."
   7251   :type '(alist :key-type integer :value-type string))
   7252 
   7253 (defun lsp--imenu-kind->name (kind)
   7254   (alist-get kind lsp-imenu-symbol-kinds "?"))
   7255 
   7256 (defun lsp-imenu-create-top-level-categorized-index (symbols)
   7257   "Create an `imenu' index categorizing SYMBOLS by type.
   7258 Only root symbols are categorized.
   7259 
   7260 See `lsp-symbol-kinds' to customize the category naming. SYMBOLS
   7261 shall be a list of DocumentSymbols or SymbolInformation."
   7262   (mapcan
   7263    (-lambda ((type . symbols))
   7264      (let ((cat (lsp--imenu-kind->name type))
   7265            (symbols (lsp-imenu-create-uncategorized-index symbols)))
   7266        ;; If there is no :kind (this is being defensive), or we couldn't look it
   7267        ;; up, just display the symbols inline, without categories.
   7268        (if cat (list (cons cat symbols)) symbols)))
   7269    (sort (seq-group-by #'lsp:document-symbol-kind symbols)
   7270          (-lambda ((kinda) (kindb)) (< kinda kindb)))))
   7271 
   7272 (lsp-defun lsp--symbol->imenu ((sym &as &DocumentSymbol :selection-range (&RangeToPoint :start)))
   7273   "Convert an `&DocumentSymbol' to an `imenu' entry."
   7274   (cons (lsp-render-symbol sym lsp-imenu-detailed-outline) start))
   7275 
   7276 (defun lsp--imenu-create-categorized-index-1 (symbols)
   7277   "Returns an `imenu' index from SYMBOLS categorized by type.
   7278 The result looks like this: ((\"Variables\" . (...)))."
   7279   (->>
   7280    symbols
   7281    (mapcan
   7282     (-lambda ((sym &as &DocumentSymbol :kind :children?))
   7283       (if (seq-empty-p children?)
   7284           (list (list kind (lsp--symbol->imenu sym)))
   7285         (let ((parent (lsp-render-symbol sym (and lsp-imenu-detailed-outline
   7286                                                   (not lsp-imenu-hide-parent-details)))))
   7287           (cons
   7288            (list kind (lsp--symbol->imenu sym))
   7289            (mapcar (-lambda ((type .  imenu-items))
   7290                      (list type (cons parent (mapcan #'cdr imenu-items))))
   7291                    (-group-by #'car (lsp--imenu-create-categorized-index-1 children?))))))))
   7292    (-group-by #'car)
   7293    (mapcar
   7294     (-lambda ((kind . syms))
   7295       (cons kind (mapcan #'cdr syms))))))
   7296 
   7297 (defun lsp--imenu-create-categorized-index (symbols)
   7298   (let ((syms (lsp--imenu-create-categorized-index-1 symbols)))
   7299     (dolist (sym syms)
   7300       (setcar sym (lsp--imenu-kind->name (car sym))))
   7301     syms))
   7302 
   7303 (lsp-defun lsp--symbol-information->imenu ((sym &as &SymbolInformation :location (&Location :range (&RangeToPoint :start))))
   7304   (cons (lsp-render-symbol-information sym nil) start))
   7305 
   7306 (defun lsp--imenu-create-categorized-index-flat (symbols)
   7307   "Create a kind-categorized index for SymbolInformation."
   7308   (mapcar (-lambda ((kind . syms))
   7309             (cons (lsp--imenu-kind->name kind)
   7310                   (mapcan (-lambda ((parent . children))
   7311                             (let ((children (mapcar #'lsp--symbol-information->imenu children)))
   7312                               (if parent (list (cons parent children)) children)))
   7313                           (-group-by #'lsp:symbol-information-container-name? syms))))
   7314           (seq-group-by #'lsp:symbol-information-kind symbols)))
   7315 
   7316 (defun lsp-imenu-create-categorized-index (symbols)
   7317   (if (lsp--imenu-hierarchical-p symbols)
   7318       (lsp--imenu-create-categorized-index symbols)
   7319     (lsp--imenu-create-categorized-index-flat symbols)))
   7320 
   7321 (defcustom lsp-imenu-index-function #'lsp-imenu-create-uncategorized-index
   7322   "Function that should create an `imenu' index.
   7323 It will be called with a list of SymbolInformation or
   7324 DocumentSymbols, whose first level is already filtered. It shall
   7325 then return an appropriate `imenu' index (see
   7326 `imenu-create-index-function').
   7327 
   7328 Note that this interface is not stable, and subject to change any
   7329 time."
   7330   :group 'lsp-imenu
   7331   :type '(radio
   7332           (const :tag "Categorize by type"
   7333                  lsp-imenu-create-categorized-index)
   7334           (const :tag "Categorize root symbols by type"
   7335                  lsp-imenu-create-top-level-categorized-index)
   7336           (const :tag "Uncategorized, inline entries"
   7337                  lsp-imenu-create-uncategorized-index)
   7338           (function :tag "Custom function")))
   7339 
   7340 (defun lsp--imenu-create-index ()
   7341   "Create an `imenu' index based on the language server.
   7342 Respects `lsp-imenu-index-function'."
   7343   (let ((symbols (lsp--imenu-filter-symbols (lsp--get-document-symbols))))
   7344     (funcall lsp-imenu-index-function symbols)))
   7345 
   7346 (defun lsp--imenu-filter-symbols (symbols)
   7347   "Filter out unsupported symbols from SYMBOLS."
   7348   (seq-remove #'lsp--symbol-ignore symbols))
   7349 
   7350 (defun lsp--imenu-hierarchical-p (symbols)
   7351   "Determine whether any element in SYMBOLS has children."
   7352   (seq-some #'lsp-document-symbol? symbols))
   7353 
   7354 (defun lsp--imenu-create-non-hierarchical-index (symbols)
   7355   "Create imenu index for non-hierarchical SYMBOLS.
   7356 
   7357 SYMBOLS are a list of DocumentSymbol messages.
   7358 
   7359 Return a nested alist keyed by symbol names. e.g.
   7360 
   7361    ((\"SomeClass\" (\"(Class)\" . 10)
   7362                  (\"someField (Field)\" . 20)
   7363                  (\"someFunction (Function)\" . 25)
   7364                  (\"SomeSubClass\" (\"(Class)\" . 30)
   7365                                   (\"someSubField (Field)\" . 35))
   7366     (\"someFunction (Function)\" . 40))"
   7367   (seq-map (lambda (nested-alist)
   7368              (cons (car nested-alist)
   7369                    (seq-map #'lsp--symbol-to-imenu-elem (cdr nested-alist))))
   7370            (seq-group-by #'lsp--get-symbol-type symbols)))
   7371 
   7372 (defun lsp--imenu-create-hierarchical-index (symbols)
   7373   "Create imenu index for hierarchical SYMBOLS.
   7374 
   7375 SYMBOLS are a list of DocumentSymbol messages.
   7376 
   7377 Return a nested alist keyed by symbol names. e.g.
   7378 
   7379    ((\"SomeClass\" (\"(Class)\" . 10)
   7380                  (\"someField (Field)\" . 20)
   7381                  (\"someFunction (Function)\" . 25)
   7382                  (\"SomeSubClass\" (\"(Class)\" . 30)
   7383                                   (\"someSubField (Field)\" . 35))
   7384     (\"someFunction (Function)\" . 40))"
   7385   (seq-map #'lsp--symbol-to-hierarchical-imenu-elem
   7386            (seq-sort #'lsp--imenu-symbol-lessp symbols)))
   7387 
   7388 (defun lsp--imenu-symbol-lessp (sym1 sym2)
   7389   (let* ((compare-results (mapcar (lambda (method)
   7390                                     (funcall (alist-get method lsp--imenu-compare-function-alist)
   7391                                              sym1 sym2))
   7392                                   lsp-imenu-sort-methods))
   7393          (result (seq-find (lambda (result)
   7394                              (not (= result 0)))
   7395                            compare-results
   7396                            0)))
   7397     (and (numberp result) (< result 0))))
   7398 
   7399 (lsp-defun lsp--imenu-compare-kind ((&SymbolInformation :kind left)
   7400                                     (&SymbolInformation :kind right))
   7401   "Compare SYM1 and SYM2 by kind."
   7402   (- left right))
   7403 
   7404 (defun lsp--imenu-compare-line-col (sym1 sym2)
   7405   (if (lsp--line-col-comparator
   7406        (lsp--get-line-and-col sym1)
   7407        (lsp--get-line-and-col sym2))
   7408       -1
   7409     1))
   7410 
   7411 (lsp-defun lsp--imenu-compare-name ((&SymbolInformation :name name1)
   7412                                     (&SymbolInformation :name name2))
   7413   "Compare SYM1 and SYM2 by name."
   7414   (let ((result (compare-strings name1 0 (length name1) name2 0 (length name2))))
   7415     (if (numberp result) result 0)))
   7416 
   7417 (defun lsp--imenu-refresh ()
   7418   "Force Imenu to refresh itself."
   7419   (imenu--menubar-select imenu--rescan-item))
   7420 
   7421 (defun lsp-enable-imenu ()
   7422   "Use lsp-imenu for the current buffer."
   7423   (imenu--cleanup)
   7424   (add-function :override (local 'imenu-create-index-function) #'lsp--imenu-create-index)
   7425   (setq-local imenu-menubar-modified-tick -1)
   7426   (setq-local imenu--index-alist nil)
   7427   (when menu-bar-mode
   7428     (lsp--imenu-refresh)))
   7429 
   7430 (defun lsp-resolve-final-command (command &optional test?)
   7431   "Resolve final function COMMAND."
   7432   (let* ((command (lsp-resolve-value command))
   7433          (command (cl-etypecase command
   7434                     (list
   7435                      (cl-assert (seq-every-p (apply-partially #'stringp) command) nil
   7436                                 "Invalid command list")
   7437                      command)
   7438                     (string (list command)))))
   7439     (if (and (file-remote-p default-directory) (not test?))
   7440         (list shell-file-name "-c"
   7441               (string-join (cons "stty raw > /dev/null;"
   7442                                  (mapcar #'shell-quote-argument command))
   7443                            " "))
   7444       command)))
   7445 
   7446 (defun lsp-server-present? (final-command)
   7447   "Check whether FINAL-COMMAND is present."
   7448   (let ((binary-found? (executable-find (cl-first final-command) t)))
   7449     (if binary-found?
   7450         (lsp-log "Command \"%s\" is present on the path." (s-join " " final-command))
   7451       (lsp-log "Command \"%s\" is not present on the path." (s-join " " final-command)))
   7452     binary-found?))
   7453 
   7454 (defun lsp--value-to-string (value)
   7455   "Convert VALUE to a string that can be set as value in an environment
   7456 variable."
   7457   (cond
   7458    ((stringp value) value)
   7459    ((booleanp value) (if value
   7460                          "1"
   7461                        "0"))
   7462    ((and (sequencep value)
   7463          (seq-every-p #'stringp value)) (string-join value ":"))
   7464    (t (user-error "Only strings, booleans, and sequences of strings are supported as environment variables"))))
   7465 
   7466 (defun lsp--compute-process-environment (environment-fn)
   7467   "Append a list of KEY=VALUE from the alist ENVIRONMENT to `process-environment'.
   7468 Ignore non-boolean keys whose value is nil."
   7469   (let ((environment (if environment-fn
   7470                          (funcall environment-fn)
   7471                        nil)))
   7472     (-flatten (cons (cl-loop for (key . value) in environment
   7473                              if (or (eval value)
   7474                                     (eq (get value 'custom-type) 'boolean))
   7475                              collect (concat key "=" (lsp--value-to-string
   7476                                                       (eval value))))
   7477                     process-environment))))
   7478 
   7479 (defun lsp--default-directory-for-connection (&optional path)
   7480   "Return path to be used for the working directory of a LSP process.
   7481 
   7482 If `lsp-use-workspace-root-for-server-default-directory' is
   7483 non-nil, uses `lsp-workspace-root' to find the directory
   7484 corresponding to PATH, else returns `default-directory'."
   7485   (if lsp-use-workspace-root-for-server-default-directory
   7486       (lsp-workspace-root path)
   7487     default-directory))
   7488 
   7489 (defun lsp--fix-remote-cmd (program)
   7490   "Helper for `lsp-stdio-connection'.
   7491 Originally coppied from eglot."
   7492 
   7493   (if (file-remote-p default-directory)
   7494       (list shell-file-name "-c"
   7495             (string-join (cons "stty raw > /dev/null;"
   7496                                (mapcar #'shell-quote-argument program))
   7497                          " "))
   7498     program))
   7499 
   7500 (defvar tramp-use-ssh-controlmaster-options)
   7501 (defvar tramp-ssh-controlmaster-options)
   7502 
   7503 (defun lsp-stdio-connection (command &optional test-command)
   7504   "Returns a connection property list using COMMAND.
   7505 COMMAND can be: A string, denoting the command to launch the
   7506 language server. A list of strings, denoting an executable with
   7507 its command line arguments. A function, that either returns a
   7508 string or a list of strings. In all cases, the launched language
   7509 server should send and receive messages on standard I/O.
   7510 TEST-COMMAND is a function with no arguments which returns
   7511 whether the command is present or not. When not specified
   7512 `lsp-mode' will check whether the first element of the list
   7513 returned by COMMAND is available via `executable-find'"
   7514   (cl-check-type command (or string
   7515                              function
   7516                              (and list
   7517                                   (satisfies (lambda (l)
   7518                                                (seq-every-p (lambda (el)
   7519                                                               (stringp el))
   7520                                                             l))))))
   7521   (list :connect (lambda (filter sentinel name environment-fn workspace)
   7522                    (if (and (functionp 'json-rpc-connection)
   7523                             (not (file-remote-p default-directory)))
   7524                        (lsp-json-rpc-connection workspace (lsp-resolve-final-command command))
   7525                      (let ((final-command (lsp-resolve-final-command command))
   7526                            (process-name (generate-new-buffer-name name))
   7527                            (process-environment
   7528                             (lsp--compute-process-environment environment-fn)))
   7529                        (let* ((stderr-buf (get-buffer-create (format "*%s::stderr*" process-name)))
   7530                               (default-directory (lsp--default-directory-for-connection))
   7531                               (tramp-use-ssh-controlmaster-options 'suppress)
   7532                               (tramp-ssh-controlmaster-options "-o ControlMaster=no -o ControlPath=none")
   7533                               (proc (make-process
   7534                                      :name process-name
   7535                                      :connection-type 'pipe
   7536                                      :buffer (format "*%s*" process-name)
   7537                                      :coding 'no-conversion
   7538                                      :command final-command
   7539                                      :filter filter
   7540                                      :sentinel sentinel
   7541                                      :stderr stderr-buf
   7542                                      :noquery t
   7543                                      :file-handler t)))
   7544                          (set-process-query-on-exit-flag proc nil)
   7545                          (set-process-query-on-exit-flag (get-buffer-process stderr-buf) nil)
   7546                          (with-current-buffer (get-buffer stderr-buf)
   7547                            ;; Make the *NAME::stderr* buffer buffer-read-only, q to bury, etc.
   7548                            (special-mode))
   7549                          (cons proc proc)))))
   7550         :test? (or
   7551                 test-command
   7552                 (lambda ()
   7553                   (lsp-server-present? (lsp-resolve-final-command command t))))))
   7554 
   7555 (defun lsp--open-network-stream (host port name)
   7556   "Open network stream to HOST:PORT.
   7557   NAME will be passed to `open-network-stream'.
   7558   RETRY-COUNT is the number of the retries.
   7559   SLEEP-INTERVAL is the sleep interval between each retry."
   7560   (let* ((retries 0)
   7561          (sleep-interval 0.01)
   7562          (number-of-retries (/ lsp-tcp-connection-timeout sleep-interval))
   7563          connection)
   7564     (while (and (not connection) (< retries number-of-retries))
   7565       (condition-case err
   7566           (setq connection (open-network-stream name nil host port
   7567                                                 :type 'plain
   7568                                                 :coding 'no-conversion))
   7569         (file-error
   7570          (let ((inhibit-message t))
   7571            (lsp--warn "Failed to connect to %s:%s with error message %s"
   7572                       host
   7573                       port
   7574                       (error-message-string err))
   7575            (sleep-for sleep-interval)
   7576            (cl-incf retries)))))
   7577     (or connection (error "Port %s was never taken. Consider increasing `lsp-tcp-connection-timeout'." port))))
   7578 
   7579 (defun lsp--port-available (host port)
   7580   "Return non-nil if HOST and PORT are available."
   7581   (condition-case _err
   7582       (delete-process (open-network-stream "*connection-test*" nil host port :type 'plain))
   7583     (file-error t)))
   7584 
   7585 (defun lsp--find-available-port (host starting-port)
   7586   "Find available port on HOST starting from STARTING-PORT."
   7587   (let ((port starting-port))
   7588     (while (not (lsp--port-available host port))
   7589       (cl-incf port))
   7590     port))
   7591 
   7592 (defun lsp-tcp-connection (command-fn)
   7593   "Returns a connection property list similar to `lsp-stdio-connection'.
   7594 COMMAND-FN can only be a function that takes a single argument, a
   7595 port number. It should return a command for launches a language server
   7596 process listening for TCP connections on the provided port."
   7597   (cl-check-type command-fn function)
   7598   (list
   7599    :connect (lambda (filter sentinel name environment-fn _workspace)
   7600               (let* ((host "localhost")
   7601                      (port (lsp--find-available-port host (cl-incf lsp--tcp-port)))
   7602                      (command (funcall command-fn port))
   7603                      (final-command (if (consp command) command (list command)))
   7604                      (_ (unless (lsp-server-present? final-command)
   7605                           (user-error (format "Couldn't find executable %s" (cl-first final-command)))))
   7606                      (process-environment
   7607                       (lsp--compute-process-environment environment-fn))
   7608                      (proc (make-process :name name :connection-type 'pipe :coding 'no-conversion
   7609                                          :command final-command :sentinel sentinel :stderr (format "*%s::stderr*" name) :noquery t))
   7610                      (tcp-proc (lsp--open-network-stream host port (concat name "::tcp"))))
   7611 
   7612                 ;; TODO: Same :noquery issue (see above)
   7613                 (set-process-query-on-exit-flag proc nil)
   7614                 (set-process-query-on-exit-flag tcp-proc nil)
   7615                 (set-process-filter tcp-proc filter)
   7616                 (cons tcp-proc proc)))
   7617    :test? (lambda () (lsp-server-present? (funcall command-fn 0)))))
   7618 
   7619 (defalias 'lsp-tcp-server 'lsp-tcp-server-command)
   7620 
   7621 (defun lsp-tcp-server-command (command-fn)
   7622   "Create tcp server connection.
   7623 In this mode Emacs is TCP server and the language server connects
   7624 to it. COMMAND is function with one parameter(the port) and it
   7625 should return the command to start the LS server."
   7626   (cl-check-type command-fn function)
   7627   (list
   7628    :connect (lambda (filter sentinel name environment-fn _workspace)
   7629               (let* (tcp-client-connection
   7630                      (tcp-server (make-network-process :name (format "*tcp-server-%s*" name)
   7631                                                        :buffer (format "*tcp-server-%s*" name)
   7632                                                        :family 'ipv4
   7633                                                        :service lsp--tcp-server-port
   7634                                                        :sentinel (lambda (proc _string)
   7635                                                                    (lsp-log "Language server %s is connected." name)
   7636                                                                    (setf tcp-client-connection proc))
   7637                                                        :server 't))
   7638                      (port (process-contact tcp-server :service))
   7639                      (final-command (funcall command-fn port))
   7640                      (process-environment
   7641                       (lsp--compute-process-environment environment-fn))
   7642                      (cmd-proc (make-process :name name
   7643                                              :connection-type 'pipe
   7644                                              :coding 'no-conversion
   7645                                              :command final-command
   7646                                              :stderr (format "*tcp-server-%s*::stderr" name)
   7647                                              :noquery t)))
   7648                 (let ((retries 0))
   7649                   ;; wait for the client to connect (we sit-for 500 ms, so have to double lsp--tcp-server-wait-seconds)
   7650                   (while (and (not tcp-client-connection) (< retries (* 2 lsp--tcp-server-wait-seconds)))
   7651                     (lsp--info "Waiting for connection for %s, retries: %s" name retries)
   7652                     (sit-for 0.500)
   7653                     (cl-incf retries)))
   7654 
   7655                 (unless tcp-client-connection
   7656                   (condition-case nil (delete-process tcp-server) (error))
   7657                   (condition-case nil (delete-process cmd-proc) (error))
   7658                   (error "Failed to create connection to %s on port %s" name port))
   7659                 (lsp--info "Successfully connected to %s" name)
   7660 
   7661                 (set-process-query-on-exit-flag cmd-proc nil)
   7662                 (set-process-query-on-exit-flag tcp-client-connection nil)
   7663                 (set-process-query-on-exit-flag tcp-server nil)
   7664 
   7665                 (set-process-filter tcp-client-connection filter)
   7666                 (set-process-sentinel tcp-client-connection sentinel)
   7667                 (cons tcp-client-connection cmd-proc)))
   7668    :test? (lambda () (lsp-server-present? (funcall command-fn 0)))))
   7669 
   7670 (defalias 'lsp-tramp-connection 'lsp-stdio-connection)
   7671 
   7672 (defun lsp--auto-configure ()
   7673   "Autoconfigure `company', `flycheck', `lsp-ui', etc if they are installed."
   7674   (when (functionp 'lsp-ui-mode)
   7675     (lsp-ui-mode))
   7676 
   7677   (if lsp-headerline-breadcrumb-enable
   7678       (add-hook 'lsp-configure-hook 'lsp-headerline-breadcrumb-mode)
   7679     (remove-hook 'lsp-configure-hook 'lsp-headerline-breadcrumb-mode))
   7680   (if lsp-modeline-code-actions-enable
   7681       (add-hook 'lsp-configure-hook 'lsp-modeline-code-actions-mode)
   7682     (remove-hook 'lsp-configure-hook 'lsp-modeline-code-actions-mode))
   7683   (if lsp-modeline-diagnostics-enable
   7684       (add-hook 'lsp-configure-hook 'lsp-modeline-diagnostics-mode)
   7685     (remove-hook 'lsp-configure-hook 'lsp-modeline-diagnostics-mode))
   7686   (if lsp-modeline-workspace-status-enable
   7687       (add-hook 'lsp-configure-hook 'lsp-modeline-workspace-status-mode)
   7688     (remove-hook 'lsp-configure-hook 'lsp-modeline-workspace-status-mode))
   7689   (if lsp-lens-enable
   7690       (add-hook 'lsp-configure-hook 'lsp-lens--enable)
   7691     (remove-hook 'lsp-configure-hook 'lsp-lens--enable))
   7692   (if lsp-semantic-tokens-enable
   7693       (add-hook 'lsp-configure-hook 'lsp-semantic-tokens--enable)
   7694     (remove-hook 'lsp-configure-hook 'lsp-semantic-tokens--enable))
   7695 
   7696   ;; yas-snippet config
   7697   (setq-local yas-inhibit-overlay-modification-protection t))
   7698 
   7699 (defun lsp--restart-if-needed (workspace)
   7700   "Handler restart for WORKSPACE."
   7701   (when (or (eq lsp-restart 'auto-restart)
   7702             (eq (lsp--workspace-shutdown-action workspace) 'restart)
   7703             (and (eq lsp-restart 'interactive)
   7704                  (let ((query (format
   7705                                "Server %s exited (check corresponding stderr buffer for details). Do you want to restart it?"
   7706                                (lsp--workspace-print workspace))))
   7707                    (y-or-n-p query))))
   7708     (--each (lsp--workspace-buffers workspace)
   7709       (when (lsp-buffer-live-p it)
   7710         (lsp-with-current-buffer it
   7711           (if lsp--buffer-deferred
   7712               (lsp-deferred)
   7713             (lsp--info "Restarting LSP in buffer %s" (buffer-name))
   7714             (lsp)))))))
   7715 
   7716 (defun lsp--update-key (table key fn)
   7717   "Apply FN on value corresponding to KEY in TABLE."
   7718   (let ((existing-value (gethash key table)))
   7719     (if-let ((new-value (funcall fn existing-value)))
   7720         (puthash key new-value table)
   7721       (remhash key table))))
   7722 
   7723 (defun lsp--process-sentinel (workspace process exit-str)
   7724   "Create the sentinel for WORKSPACE."
   7725   (unless (process-live-p process)
   7726     (lsp--handle-process-exit workspace exit-str)))
   7727 
   7728 (defun lsp--handle-process-exit (workspace exit-str)
   7729   (let* ((folder->workspaces (lsp-session-folder->servers (lsp-session)))
   7730          (proc (lsp--workspace-proc workspace)))
   7731     (lsp--warn "%s has exited (%s)"
   7732                (lsp-process-name proc)
   7733                (string-trim-right (or exit-str "")))
   7734     (with-lsp-workspace workspace
   7735       ;; Clean workspace related data in each of the buffers
   7736       ;; in the workspace.
   7737       (--each (lsp--workspace-buffers workspace)
   7738         (when (lsp-buffer-live-p it)
   7739           (lsp-with-current-buffer it
   7740             (setq lsp--buffer-workspaces (delete workspace lsp--buffer-workspaces))
   7741             (lsp--uninitialize-workspace)
   7742             (lsp--spinner-stop)
   7743             (lsp--remove-overlays 'lsp-highlight))))
   7744 
   7745       ;; Cleanup session from references to the closed workspace.
   7746       (--each (hash-table-keys folder->workspaces)
   7747         (lsp--update-key folder->workspaces it (apply-partially 'delete workspace)))
   7748 
   7749       (lsp-process-cleanup proc))
   7750 
   7751     (run-hook-with-args 'lsp-after-uninitialized-functions workspace)
   7752 
   7753     (if (eq (lsp--workspace-shutdown-action workspace) 'shutdown)
   7754         (lsp--info "Workspace %s shutdown." (lsp--workspace-print workspace))
   7755       (lsp--restart-if-needed workspace))
   7756     (lsp--cleanup-hanging-watches)))
   7757 
   7758 (defun lsp-workspace-folders (workspace)
   7759   "Return all folders associated with WORKSPACE."
   7760   (let (result)
   7761     (->> (lsp-session)
   7762          (lsp-session-folder->servers)
   7763          (maphash (lambda (folder workspaces)
   7764                     (when (-contains? workspaces workspace)
   7765                       (push folder result)))))
   7766     result))
   7767 
   7768 (defun lsp--start-workspace (session client-template root &optional initialization-options)
   7769   "Create new workspace for CLIENT-TEMPLATE with project root ROOT.
   7770 INITIALIZATION-OPTIONS are passed to initialize function.
   7771 SESSION is the active session."
   7772   (lsp--spinner-start)
   7773   (-let* ((default-directory root)
   7774           (client (copy-lsp--client client-template))
   7775           (workspace (make-lsp--workspace
   7776                       :root root
   7777                       :client client
   7778                       :status 'starting
   7779                       :buffers (list (lsp-current-buffer))
   7780                       :host-root (file-remote-p root)))
   7781           ((&lsp-cln 'server-id 'environment-fn 'new-connection 'custom-capabilities
   7782                      'multi-root 'initialized-fn) client)
   7783           ((proc . cmd-proc) (funcall
   7784                               (or (plist-get new-connection :connect)
   7785                                   (user-error "Client %s is configured incorrectly" client))
   7786                               (lsp--create-filter-function workspace)
   7787                               (apply-partially #'lsp--process-sentinel workspace)
   7788                               (format "%s" server-id)
   7789                               environment-fn
   7790                               workspace))
   7791           (workspace-folders (gethash server-id (lsp-session-server-id->folders session))))
   7792     (setf (lsp--workspace-proc workspace) proc
   7793           (lsp--workspace-cmd-proc workspace) cmd-proc)
   7794 
   7795     ;; update (lsp-session-folder->servers) depending on whether we are starting
   7796     ;; multi/single folder workspace
   7797     (mapc (lambda (project-root)
   7798             (->> session
   7799                  (lsp-session-folder->servers)
   7800                  (gethash project-root)
   7801                  (cl-pushnew workspace)))
   7802           (or workspace-folders (list root)))
   7803 
   7804     (with-lsp-workspace workspace
   7805       (run-hooks 'lsp-before-initialize-hook)
   7806       (lsp-request-async
   7807        "initialize"
   7808        (append
   7809         (list :processId (unless (file-remote-p (buffer-file-name))
   7810                            (emacs-pid))
   7811               :rootPath (lsp-file-local-name (expand-file-name root))
   7812               :clientInfo (list :name "emacs"
   7813                                 :version (emacs-version))
   7814               :rootUri (lsp--path-to-uri root)
   7815               :capabilities (lsp--client-capabilities custom-capabilities)
   7816               :initializationOptions initialization-options
   7817               :workDoneToken "1")
   7818         (when lsp-server-trace
   7819           (list :trace lsp-server-trace))
   7820         (when multi-root
   7821           (->> workspace-folders
   7822                (-distinct)
   7823                (-map (lambda (folder)
   7824                        (list :uri (lsp--path-to-uri folder)
   7825                              :name (f-filename folder))))
   7826                (apply 'vector)
   7827                (list :workspaceFolders))))
   7828        (-lambda ((&InitializeResult :capabilities))
   7829          ;; we know that Rust Analyzer will send {} which will be parsed as null
   7830          ;; when using plists
   7831          (when (equal 'rust-analyzer server-id)
   7832            (-> capabilities
   7833                (lsp:server-capabilities-text-document-sync?)
   7834                (lsp:set-text-document-sync-options-save? t)))
   7835 
   7836          (setf (lsp--workspace-server-capabilities workspace) capabilities
   7837                (lsp--workspace-status workspace) 'initialized)
   7838 
   7839          (with-lsp-workspace workspace
   7840            (lsp-notify "initialized" lsp--empty-ht))
   7841 
   7842          (when initialized-fn (funcall initialized-fn workspace))
   7843 
   7844          (cl-callf2 -filter #'lsp-buffer-live-p (lsp--workspace-buffers workspace))
   7845          (->> workspace
   7846               (lsp--workspace-buffers)
   7847               (mapc (lambda (buffer)
   7848                       (lsp-with-current-buffer buffer
   7849                         (lsp--open-in-workspace workspace)))))
   7850 
   7851          (with-lsp-workspace workspace
   7852            (run-hooks 'lsp-after-initialize-hook))
   7853          (lsp--info "%s initialized successfully in folders: %s"
   7854                     (lsp--workspace-print workspace)
   7855                     (lsp-workspace-folders workspace)))
   7856        :mode 'detached))
   7857     workspace))
   7858 
   7859 (defun lsp--load-default-session ()
   7860   "Load default session."
   7861   (setq lsp--session (or (condition-case err
   7862                              (lsp--read-from-file lsp-session-file)
   7863                            (error (lsp--error "Failed to parse the session %s, starting with clean one."
   7864                                               (error-message-string err))
   7865                                   nil))
   7866                          (make-lsp-session))))
   7867 
   7868 (defun lsp-session ()
   7869   "Get the session associated with the current buffer."
   7870   (or lsp--session (setq lsp--session (lsp--load-default-session))))
   7871 
   7872 (defun lsp--client-disabled-p (buffer-major-mode client)
   7873   (seq-some
   7874    (lambda (entry)
   7875      (pcase entry
   7876        ((pred symbolp) (eq entry client))
   7877        (`(,mode . ,client-or-list)
   7878         (and (eq mode buffer-major-mode)
   7879              (if (listp client-or-list)
   7880                  (memq client client-or-list)
   7881                (eq client client-or-list))))))
   7882    lsp-disabled-clients))
   7883 
   7884 
   7885 ;; download server
   7886 
   7887 (defcustom lsp-server-install-dir (expand-file-name
   7888                                    (locate-user-emacs-file (f-join ".cache" "lsp")))
   7889   "Directory in which the servers will be installed."
   7890   :risky t
   7891   :type 'directory
   7892   :package-version '(lsp-mode . "6.3")
   7893   :group 'lsp-mode)
   7894 
   7895 (defcustom lsp-verify-signature t
   7896   "Whether to check GPG signatures of downloaded files."
   7897   :type 'boolean
   7898   :package-version '(lsp-mode . "8.0.0")
   7899   :group 'lsp-mode)
   7900 
   7901 (defvar lsp--dependencies (ht))
   7902 
   7903 (defun lsp-dependency (name &rest definitions)
   7904   "Used to specify a language server DEPENDENCY, the server
   7905 executable or other required file path. Typically, the
   7906 DEPENDENCY is found by locating it on the system path using
   7907 `executable-find'.
   7908 
   7909 You can explicitly call lsp-dependency in your environment to
   7910 specify the absolute path to the DEPENDENCY. For example, the
   7911 typescript-language-server requires both the server and the
   7912 typescript compiler. If you have installed them in a team shared
   7913 read-only location, you can instruct lsp-mode to use them via
   7914 
   7915  (eval-after-load `lsp-mode
   7916    `(progn
   7917       (require lsp-javascript)
   7918       (lsp-dependency typescript-language-server (:system ,tls-exe))
   7919       (lsp-dependency typescript (:system ,ts-js))))
   7920 
   7921 where tls-exe is the absolute path to the typescript-language-server
   7922 executable and ts-js is the absolute path to the typescript compiler
   7923 JavaScript file, tsserver.js (the *.js is required for Windows)."
   7924   (ht-set lsp--dependencies name definitions))
   7925 
   7926 (defun lsp--server-binary-present? (client)
   7927   (unless (equal (lsp--client-server-id client) 'lsp-pwsh)
   7928     (condition-case ()
   7929         (-some-> client lsp--client-new-connection (plist-get :test?) funcall)
   7930       (error nil)
   7931       (args-out-of-range nil))))
   7932 
   7933 (define-minor-mode lsp-installation-buffer-mode
   7934   "Mode used in *lsp-installation* buffers.
   7935 It can be used to set-up keybindings, etc. Disabling this mode
   7936 detaches the installation buffer from commands like
   7937 `lsp-select-installation-buffer'."
   7938   :init-value nil
   7939   :lighter nil)
   7940 
   7941 (defface lsp-installation-finished-buffer-face '((t :foreground "orange"))
   7942   "Face used for finished installation buffers.
   7943 Used in `lsp-select-installation-buffer'."
   7944   :group 'lsp-mode)
   7945 
   7946 (defface lsp-installation-buffer-face '((t :foreground "green"))
   7947   "Face used for installation buffers still in progress.
   7948 Used in `lsp-select-installation-buffer'."
   7949   :group 'lsp-mode)
   7950 
   7951 (defun lsp--installation-buffer? (buf)
   7952   "Check whether BUF is an `lsp-async-start-process' buffer."
   7953   (buffer-local-value 'lsp-installation-buffer-mode buf))
   7954 
   7955 (defun lsp-select-installation-buffer (&optional show-finished)
   7956   "Interactively choose an installation buffer.
   7957 If SHOW-FINISHED is set, leftover (finished) installation buffers
   7958 are still shown."
   7959   (interactive "P")
   7960   (let ((bufs (--filter (and (lsp--installation-buffer? it)
   7961                              (or show-finished (get-buffer-process it)))
   7962                         (buffer-list))))
   7963     (pcase bufs
   7964       (`nil (user-error "No installation buffers"))
   7965       (`(,buf) (pop-to-buffer buf))
   7966       (bufs (pop-to-buffer (completing-read "Select installation buffer: "
   7967                                             (--map (propertize (buffer-name it) 'face
   7968                                                                (if (get-buffer-process it)
   7969                                                                    'lsp-installation-buffer-face
   7970                                                                  'lsp-installation-finished-buffer-face))
   7971                                                    bufs)))))))
   7972 
   7973 (defun lsp-cleanup-installation-buffers ()
   7974   "Delete finished *lsp-installation* buffers."
   7975   (interactive)
   7976   (dolist (buf (buffer-list))
   7977     (when (and (lsp--installation-buffer? buf) (not (get-buffer-process buf)))
   7978       (kill-buffer buf))))
   7979 
   7980 (defun lsp--download-status ()
   7981   (-some--> #'lsp--client-download-in-progress?
   7982     (lsp--filter-clients it)
   7983     (-map (-compose #'symbol-name #'lsp--client-server-id) it)
   7984     (format "%s" it)
   7985     (propertize it 'face 'success)
   7986     (format " Installing following servers: %s" it)
   7987     (propertize it
   7988                 'local-map (make-mode-line-mouse-map
   7989                             'mouse-1 #'lsp-select-installation-buffer)
   7990                 'mouse-face 'highlight)))
   7991 
   7992 (defun lsp--install-server-internal (client &optional update?)
   7993   (unless (lsp--client-download-server-fn client)
   7994     (user-error "There is no automatic installation for `%s', you have to install it manually following lsp-mode's documentation."
   7995                 (lsp--client-server-id client)))
   7996 
   7997   (setf (lsp--client-download-in-progress? client) t)
   7998   (add-to-list 'global-mode-string '(t (:eval (lsp--download-status))))
   7999   (cl-flet ((done
   8000              (success? &optional error-message)
   8001              ;; run with idle timer to make sure the lsp command is executed in
   8002              ;; the main thread, see #2739.
   8003              (run-with-timer
   8004               0.0
   8005               nil
   8006               (lambda ()
   8007                 (-let [(&lsp-cln 'server-id 'buffers) client]
   8008                   (setf (lsp--client-download-in-progress? client) nil
   8009                         (lsp--client-buffers client) nil)
   8010                   (if success?
   8011                       (lsp--info "Server %s downloaded, auto-starting in %s buffers." server-id
   8012                                  (length buffers))
   8013                     (lsp--error "Server %s install process failed with the following error message: %s.
   8014 Check `*lsp-install*' and `*lsp-log*' buffer."
   8015                                 server-id
   8016                                 error-message))
   8017                   (seq-do
   8018                    (lambda (buffer)
   8019                      (when (lsp-buffer-live-p buffer)
   8020                        (lsp-with-current-buffer buffer
   8021                          (cl-callf2 -remove-item '(t (:eval (lsp--download-status)))
   8022                                     global-mode-string)
   8023                          (when success? (lsp)))))
   8024                    buffers)
   8025                   (unless (lsp--filter-clients #'lsp--client-download-in-progress?)
   8026                     (cl-callf2 -remove-item '(t (:eval (lsp--download-status)))
   8027                                global-mode-string)))))))
   8028     (lsp--info "Download %s started." (lsp--client-server-id client))
   8029     (condition-case err
   8030         (funcall
   8031          (lsp--client-download-server-fn client)
   8032          client
   8033          (lambda () (done t))
   8034          (lambda (msg) (done nil msg))
   8035          update?)
   8036       (error
   8037        (done nil (error-message-string err))))))
   8038 
   8039 (defun lsp--require-packages ()
   8040   "Load `lsp-client-packages' if needed."
   8041   (when (and lsp-auto-configure (not lsp--client-packages-required))
   8042     (seq-do (lambda (package)
   8043               ;; loading client is slow and `lsp' can be called repeatedly
   8044               (unless (featurep package)
   8045                 (require package nil t)))
   8046             lsp-client-packages)
   8047     (setq lsp--client-packages-required t)))
   8048 
   8049 ;;;###autoload
   8050 (defun lsp-install-server (update? &optional server-id)
   8051   "Interactively install or re-install server.
   8052 When prefix UPDATE? is t force installation even if the server is present."
   8053   (interactive "P")
   8054   (lsp--require-packages)
   8055   (let* ((chosen-client (or (gethash server-id lsp-clients)
   8056                             (lsp--completing-read
   8057                              "Select server to install/re-install: "
   8058                              (or (->> lsp-clients
   8059                                       (ht-values)
   8060                                       (-filter (-andfn
   8061                                                 (-not #'lsp--client-download-in-progress?)
   8062                                                 #'lsp--client-download-server-fn)))
   8063                                  (user-error "There are no servers with automatic installation"))
   8064                              (lambda (client)
   8065                                (let ((server-name (-> client lsp--client-server-id symbol-name)))
   8066                                  (if (lsp--server-binary-present? client)
   8067                                      (concat server-name " (Already installed)")
   8068                                    server-name)))
   8069                              nil
   8070                              t)))
   8071          (update? (or update?
   8072                       (and (not (lsp--client-download-in-progress? chosen-client))
   8073                            (lsp--server-binary-present? chosen-client)))))
   8074     (lsp--install-server-internal chosen-client update?)))
   8075 
   8076 ;;;###autoload
   8077 (defun lsp-uninstall-server (dir)
   8078   "Delete a LSP server from `lsp-server-install-dir'."
   8079   (interactive
   8080    (list (read-directory-name "Uninstall LSP server: " (f-slash lsp-server-install-dir))))
   8081   (unless (file-directory-p dir)
   8082     (user-error "Couldn't find %s directory" dir))
   8083   (delete-directory dir 'recursive)
   8084   (message "Server `%s' uninstalled." (file-name-nondirectory (directory-file-name dir))))
   8085 
   8086 ;;;###autoload
   8087 (defun lsp-uninstall-servers ()
   8088   "Uninstall all installed servers."
   8089   (interactive)
   8090   (let* ((dir lsp-server-install-dir)
   8091          (servers (ignore-errors
   8092                     (directory-files dir t
   8093                                      directory-files-no-dot-files-regexp))))
   8094     (if (or (not (file-directory-p dir)) (zerop (length servers)))
   8095         (user-error "No servers to uninstall")
   8096       (when (yes-or-no-p
   8097              (format "Servers to uninstall: %d (%s), proceed? "
   8098                      (length servers)
   8099                      (mapconcat (lambda (server)
   8100                                   (file-name-nondirectory (directory-file-name server)))
   8101                                 servers " ")))
   8102         (mapc #'lsp-uninstall-server servers)
   8103         (message "All servers uninstalled")))))
   8104 
   8105 ;;;###autoload
   8106 (defun lsp-update-server (&optional server-id)
   8107   "Interactively update (reinstall) a server."
   8108   (interactive)
   8109   (lsp--require-packages)
   8110   (let ((chosen-client (or (gethash server-id lsp-clients)
   8111                            (lsp--completing-read
   8112                             "Select server to update (if not on the list, probably you need to `lsp-install-server`): "
   8113                             (or (->> lsp-clients
   8114                                      (ht-values)
   8115                                      (-filter (-andfn
   8116                                                (-not #'lsp--client-download-in-progress?)
   8117                                                #'lsp--client-download-server-fn
   8118                                                #'lsp--server-binary-present?)))
   8119                                 (user-error "There are no servers to update"))
   8120                             (lambda (client)
   8121                               (-> client lsp--client-server-id symbol-name))
   8122                             nil
   8123                             t))))
   8124     (lsp--install-server-internal chosen-client t)))
   8125 
   8126 ;;;###autoload
   8127 (defun lsp-update-servers ()
   8128   "Update (reinstall) all installed servers."
   8129   (interactive)
   8130   (lsp--require-packages)
   8131   (mapc (lambda (client) (lsp--install-server-internal client t))
   8132         (-filter (-andfn
   8133                   (-not #'lsp--client-download-in-progress?)
   8134                   #'lsp--client-download-server-fn
   8135                   #'lsp--server-binary-present?) (hash-table-values lsp-clients))))
   8136 
   8137 ;;;###autoload
   8138 (defun lsp-ensure-server (server-id)
   8139   "Ensure server SERVER-ID"
   8140   (lsp--require-packages)
   8141   (if-let ((client (gethash server-id lsp-clients)))
   8142       (unless (lsp--server-binary-present? client)
   8143         (lsp--info "Server `%s' is not preset, installing..." server-id)
   8144         (lsp-install-server nil server-id))
   8145     (warn "Unable to find server registration with id %s" server-id)))
   8146 
   8147 (defun lsp-async-start-process (callback error-callback &rest command)
   8148   "Start async process COMMAND with CALLBACK and ERROR-CALLBACK."
   8149   (let ((name (cl-first command)))
   8150     (with-current-buffer (compilation-start (mapconcat #'shell-quote-argument (-filter (lambda (cmd)
   8151                                                                                          (not (null cmd)))
   8152                                                                                        command)
   8153                                                        " ") t
   8154                                             (lambda (&rest _)
   8155                                               (generate-new-buffer-name (format "*lsp-install: %s*" name))))
   8156       (lsp-installation-buffer-mode +1)
   8157       (view-mode +1)
   8158       (add-hook
   8159        'compilation-finish-functions
   8160        (lambda (_buf status)
   8161          (if (string= "finished\n" status)
   8162              (condition-case err
   8163                  (funcall callback)
   8164                (error
   8165                 (funcall error-callback (error-message-string err))))
   8166            (funcall error-callback (s-trim-right status))))
   8167        nil t))))
   8168 
   8169 (defun lsp-resolve-value (value)
   8170   "Resolve VALUE's value.
   8171 If it is function - call it.
   8172 If it is a variable - return it's value
   8173 Otherwise returns value itself."
   8174   (cond
   8175    ((functionp value) (funcall value))
   8176    ((and (symbolp value) (boundp value)) (symbol-value value))
   8177    (value)))
   8178 
   8179 (defvar lsp-deps-providers
   8180   (list :npm (list :path #'lsp--npm-dependency-path
   8181                    :install #'lsp--npm-dependency-install)
   8182         :cargo (list :path #'lsp--cargo-dependency-path
   8183                      :install #'lsp--cargo-dependency-install)
   8184         :system (list :path #'lsp--system-path)
   8185         :download (list :path #'lsp-download-path
   8186                         :install #'lsp-download-install)))
   8187 
   8188 (defun lsp--system-path (path)
   8189   "If PATH is absolute and exists return it as is. Otherwise,
   8190 return the absolute path to the executable defined by PATH or
   8191 nil."
   8192   ;; For node.js 'sub-packages' PATH may point to a *.js file. Consider the
   8193   ;; typescript-language-server. When lsp invokes the server, lsp needs to
   8194   ;; supply the path to the typescript compiler, tsserver.js, as an argument. To
   8195   ;; make code platform independent, one must pass the absolute path to the
   8196   ;; tsserver.js file (Windows requires a *.js file - see help on the JavaScript
   8197   ;; child process spawn command that is invoked by the
   8198   ;; typescript-language-server). This is why we check for existence and not
   8199   ;; that the path is executable.
   8200   (let ((path (lsp-resolve-value path)))
   8201     (cond
   8202      ((and (f-absolute? path)
   8203            (f-exists? path))
   8204       path)
   8205      ((executable-find path t) path))))
   8206 
   8207 (defun lsp-package-path (dependency)
   8208   "Path to the DEPENDENCY each of the registered providers."
   8209   (let (path)
   8210     (-first (-lambda ((provider . rest))
   8211               (setq path (-some-> lsp-deps-providers
   8212                            (plist-get provider)
   8213                            (plist-get :path)
   8214                            (apply rest))))
   8215             (gethash dependency lsp--dependencies))
   8216     path))
   8217 
   8218 (defun lsp-package-ensure (dependency callback error-callback)
   8219   "Asynchronously ensure a package."
   8220   (or (-first (-lambda ((provider . rest))
   8221                 (-some-> lsp-deps-providers
   8222                   (plist-get provider)
   8223                   (plist-get :install)
   8224                   (apply (cl-list* callback error-callback rest))))
   8225               (gethash dependency lsp--dependencies))
   8226       (funcall error-callback (format "Unable to find a way to install %s" dependency))))
   8227 
   8228 
   8229 ;; npm handling
   8230 
   8231 ;; https://docs.npmjs.com/files/folders#executables
   8232 (cl-defun lsp--npm-dependency-path (&key package path &allow-other-keys)
   8233   "Return npm dependency PATH for PACKAGE."
   8234   (let ((path (executable-find
   8235                (f-join lsp-server-install-dir "npm" package
   8236                        (cond ((eq system-type 'windows-nt) "")
   8237                              (t "bin"))
   8238                        path)
   8239                t)))
   8240     (unless (and path (f-exists? path))
   8241       (error "The package %s is not installed.  Unable to find %s" package path))
   8242     path))
   8243 
   8244 (cl-defun lsp--npm-dependency-install (callback error-callback &key package &allow-other-keys)
   8245   (if-let ((npm-binary (executable-find "npm")))
   8246       (progn
   8247         ;; Explicitly `make-directory' to work around NPM bug in
   8248         ;; versions 7.0.0 through 7.4.1. See
   8249         ;; https://github.com/emacs-lsp/lsp-mode/issues/2364 for
   8250         ;; discussion.
   8251         (make-directory (f-join lsp-server-install-dir "npm" package "lib") 'parents)
   8252         (lsp-async-start-process (lambda ()
   8253                                    (if (string-empty-p
   8254                                         (string-trim (shell-command-to-string
   8255                                                       (mapconcat #'shell-quote-argument `(,npm-binary "view" ,package "peerDependencies") " "))))
   8256                                        (funcall callback)
   8257                                      (let ((default-directory (f-dirname (car (last (directory-files-recursively (f-join lsp-server-install-dir "npm" package) "package.json")))))
   8258                                            (process-environment (append '("npm_config_yes=true") process-environment))) ;; Disable prompting for older versions of npx
   8259                                        (when (f-dir-p default-directory)
   8260                                          (lsp-async-start-process callback
   8261                                                                   error-callback
   8262                                                                   (executable-find "npx")
   8263                                                                   "npm-install-peers")))))
   8264                                  error-callback
   8265                                  npm-binary
   8266                                  "-g"
   8267                                  "--prefix"
   8268                                  (f-join lsp-server-install-dir "npm" package)
   8269                                  "install"
   8270                                  package))
   8271     (lsp-log "Unable to install %s via `npm' because it is not present" package)
   8272     nil))
   8273 
   8274 
   8275 ;; Cargo dependency handling
   8276 (cl-defun lsp--cargo-dependency-path (&key package path &allow-other-keys)
   8277   (let ((path (executable-find
   8278                (f-join lsp-server-install-dir
   8279                        "cargo"
   8280                        package
   8281                        "bin"
   8282                        path)
   8283                t)))
   8284     (unless (and path (f-exists? path))
   8285       (error "The package %s is not installed.  Unable to find %s" package path))
   8286     path))
   8287 
   8288 (cl-defun lsp--cargo-dependency-install (callback error-callback &key package git &allow-other-keys)
   8289   (if-let ((cargo-binary (executable-find "cargo")))
   8290       (lsp-async-start-process
   8291        callback
   8292        error-callback
   8293        cargo-binary
   8294        "install"
   8295        package
   8296        (when git
   8297          "--git")
   8298        git
   8299        "--root"
   8300        (f-join lsp-server-install-dir "cargo" package))
   8301     (lsp-log "Unable to install %s via `cargo' because it is not present" package)
   8302     nil))
   8303 
   8304 
   8305 
   8306 ;; Download URL handling
   8307 (cl-defun lsp-download-install (callback error-callback &key url asc-url pgp-key store-path decompress &allow-other-keys)
   8308   (let* ((url (lsp-resolve-value url))
   8309          (store-path (lsp-resolve-value store-path))
   8310          ;; (decompress (lsp-resolve-value decompress))
   8311          (download-path
   8312           (pcase decompress
   8313             (:gzip (concat store-path ".gz"))
   8314             (:zip (concat store-path ".zip"))
   8315             (:targz (concat store-path ".tar.gz"))
   8316             (`nil store-path)
   8317             (_ (error ":decompress must be `:gzip', `:zip', `:targz' or `nil'")))))
   8318     (make-thread
   8319      (lambda ()
   8320        (condition-case err
   8321            (progn
   8322              (when (f-exists? download-path)
   8323                (f-delete download-path))
   8324              (when (f-exists? store-path)
   8325                (f-delete store-path))
   8326              (lsp--info "Starting to download %s to %s..." url download-path)
   8327              (mkdir (f-parent download-path) t)
   8328              (url-copy-file url download-path)
   8329              (lsp--info "Finished downloading %s..." download-path)
   8330              (when (and lsp-verify-signature asc-url pgp-key)
   8331                (if (executable-find epg-gpg-program)
   8332                    (let ((asc-download-path (concat download-path ".asc"))
   8333                          (context (epg-make-context))
   8334                          (fingerprint)
   8335                          (signature))
   8336                      (when (f-exists? asc-download-path)
   8337                        (f-delete asc-download-path))
   8338                      (lsp--info "Starting to download %s to %s..." asc-url asc-download-path)
   8339                      (url-copy-file asc-url asc-download-path)
   8340                      (lsp--info "Finished downloading %s..." asc-download-path)
   8341                      (epg-import-keys-from-string context pgp-key)
   8342                      (setq fingerprint (epg-import-status-fingerprint
   8343                                         (car
   8344                                          (epg-import-result-imports
   8345                                           (epg-context-result-for context 'import)))))
   8346                      (lsp--info "Verifying signature %s..." asc-download-path)
   8347                      (epg-verify-file context asc-download-path download-path)
   8348                      (setq signature (car (epg-context-result-for context 'verify)))
   8349                      (unless (and
   8350                               (eq (epg-signature-status signature) 'good)
   8351                               (equal (epg-signature-fingerprint signature) fingerprint))
   8352                        (error "Failed to verify GPG signature: %s" (epg-signature-to-string signature))))
   8353                  (lsp--warn "GPG is not installed, skipping the signature check.")))
   8354              (when decompress
   8355                (lsp--info "Decompressing %s..." download-path)
   8356                (pcase decompress
   8357                  (:gzip
   8358                   (lsp-gunzip download-path))
   8359                  (:zip (lsp-unzip download-path (f-parent store-path)))
   8360                  (:targz (lsp-tar-gz-decompress download-path (f-parent store-path))))
   8361                (lsp--info "Decompressed %s..." store-path))
   8362              (funcall callback))
   8363          (error (funcall error-callback err)))))))
   8364 
   8365 (cl-defun lsp-download-path (&key store-path binary-path set-executable? &allow-other-keys)
   8366   "Download URL and store it into STORE-PATH.
   8367 
   8368 SET-EXECUTABLE? when non-nil change the executable flags of
   8369 STORE-PATH to make it executable. BINARY-PATH can be specified
   8370 when the binary to start does not match the name of the
   8371 archive (e.g. when the archive has multiple files)"
   8372   (let ((store-path (or (lsp-resolve-value binary-path)
   8373                         (lsp-resolve-value store-path))))
   8374     (cond
   8375      ((executable-find store-path) store-path)
   8376      ((and set-executable? (f-exists? store-path))
   8377       (set-file-modes store-path #o0700)
   8378       store-path)
   8379      ((f-exists? store-path) store-path))))
   8380 
   8381 (defun lsp--find-latest-gh-release-url (url regex)
   8382   "Fetch the latest version in the releases given by URL by using REGEX."
   8383   (let ((url-request-method "GET"))
   8384     (with-current-buffer (url-retrieve-synchronously url)
   8385       (goto-char (point-min))
   8386       (re-search-forward "\n\n" nil 'noerror)
   8387       (delete-region (point-min) (point))
   8388       (let* ((json-result (lsp-json-read-buffer)))
   8389         (message "Latest version found: %s" (lsp-get json-result :tag_name))
   8390         (--> json-result
   8391              (lsp-get it :assets)
   8392              (seq-find (lambda (entry) (string-match-p regex (lsp-get entry :name))) it)
   8393              (lsp-get it :browser_download_url))))))
   8394 
   8395 ;; unzip
   8396 
   8397 (defconst lsp-ext-pwsh-script "powershell -noprofile -noninteractive \
   8398 -nologo -ex bypass -command Expand-Archive -path '%s' -dest '%s'"
   8399   "Powershell script to unzip file.")
   8400 
   8401 (defconst lsp-ext-unzip-script "bash -c 'mkdir -p %2$s && unzip -qq -o %1$s -d %2$s'"
   8402   "Unzip script to unzip file.")
   8403 
   8404 (defcustom lsp-unzip-script (lambda ()
   8405                               (cond ((executable-find "unzip") lsp-ext-unzip-script)
   8406                                     ((executable-find "powershell") lsp-ext-pwsh-script)
   8407                                     (t nil)))
   8408   "The script to unzip."
   8409   :group 'lsp-mode
   8410   :type 'string
   8411   :package-version '(lsp-mode . "8.0.0"))
   8412 
   8413 (defun lsp-unzip (zip-file dest)
   8414   "Unzip ZIP-FILE to DEST."
   8415   (unless lsp-unzip-script
   8416     (error "Unable to find `unzip' or `powershell' on the path, please customize `lsp-unzip-script'"))
   8417   (shell-command (format (lsp-resolve-value lsp-unzip-script) zip-file dest)))
   8418 
   8419 ;; gunzip
   8420 
   8421 (defconst lsp-ext-gunzip-script "gzip -d %1$s"
   8422   "Script to decompress a gzippped file with gzip.")
   8423 
   8424 (defcustom lsp-gunzip-script (lambda ()
   8425                                (cond ((executable-find "gzip") lsp-ext-gunzip-script)
   8426                                      (t nil)))
   8427   "The script to decompress a gzipped file.
   8428 Should be a format string with one argument for the file to be decompressed
   8429 in place."
   8430   :group 'lsp-mode
   8431   :type 'string
   8432   :package-version '(lsp-mode . "8.0.0"))
   8433 
   8434 (defun lsp-gunzip (gz-file)
   8435   "Decompress GZ-FILE in place."
   8436   (unless lsp-gunzip-script
   8437     (error "Unable to find `gzip' on the path, please either customize `lsp-gunzip-script' or manually decompress %s" gz-file))
   8438   (shell-command (format (lsp-resolve-value lsp-gunzip-script) gz-file)))
   8439 
   8440 ;; tar.gz decompression
   8441 
   8442 (defconst lsp-ext-tar-script "bash -c 'mkdir -p %2$s; tar xf %1$s --directory=%2$s'"
   8443   "Script to decompress a .tar.gz file.")
   8444 
   8445 (defcustom lsp-tar-script (lambda ()
   8446                             (cond ((executable-find "tar") lsp-ext-tar-script)
   8447                                   (t nil)))
   8448   "The script to decompress a .tar.gz file.
   8449 Should be a format string with one argument for the file to be decompressed
   8450 in place."
   8451   :group 'lsp-mode
   8452   :type 'string)
   8453 
   8454 (defun lsp-tar-gz-decompress (targz-file dest)
   8455   "Decompress TARGZ-FILE in DEST."
   8456   (unless lsp-tar-script
   8457     (error "Unable to find `tar' on the path, please either customize `lsp-tar-script' or manually decompress %s" targz-file))
   8458   (shell-command (format (lsp-resolve-value lsp-tar-script) targz-file dest)))
   8459 
   8460 
   8461 ;; VSCode marketplace
   8462 
   8463 (defcustom lsp-vscode-ext-url
   8464   "https://marketplace.visualstudio.com/_apis/public/gallery/publishers/%s/vsextensions/%s/%s/vspackage%s"
   8465   "Vscode extension template url."
   8466   :group 'lsp-mode
   8467   :type 'string
   8468   :package-version '(lsp-mode . "8.0.0"))
   8469 
   8470 (defun lsp-vscode-extension-url (publisher name version &optional targetPlatform)
   8471   "Return the URL to vscode extension.
   8472 PUBLISHER is the extension publisher.
   8473 NAME is the name of the extension.
   8474 VERSION is the version of the extension.
   8475 TARGETPLATFORM is the targetPlatform of the extension."
   8476   (format lsp-vscode-ext-url publisher name version (or targetPlatform "")))
   8477 
   8478 
   8479 
   8480 ;; Queueing prompts
   8481 
   8482 (defvar lsp--question-queue nil
   8483   "List of questions yet to be asked by `lsp-ask-question'.")
   8484 
   8485 (defun lsp-ask-question (question options callback)
   8486   "Prompt the user to answer the QUESTION with one of the OPTIONS from the
   8487 minibuffer. Once the user selects an option, the CALLBACK function will be
   8488 called, passing the selected option to it.
   8489 
   8490 If the user is currently being shown a question, the question will be stored in
   8491 `lsp--question-queue', and will be asked once the user has answered the current
   8492 question."
   8493   (add-to-list 'lsp--question-queue `(("question" . ,question)
   8494                                       ("options" . ,options)
   8495                                       ("callback" . ,callback)) t)
   8496   (when (eq (length lsp--question-queue) 1)
   8497     (lsp--process-question-queue)))
   8498 
   8499 (defun lsp--process-question-queue ()
   8500   "Take the first question from `lsp--question-queue', process it, then process
   8501 the next question until the queue is empty."
   8502   (-let* (((&alist "question" "options" "callback") (car lsp--question-queue))
   8503           (answer (completing-read question options nil t)))
   8504     (pop lsp--question-queue)
   8505     (funcall callback answer)
   8506     (when lsp--question-queue
   8507       (lsp--process-question-queue))))
   8508 
   8509 (defun lsp--supports-buffer? (client)
   8510   (and
   8511    ;; both file and client remote or both local
   8512    (eq (---truthy? (file-remote-p (buffer-file-name)))
   8513        (---truthy? (lsp--client-remote? client)))
   8514 
   8515    ;; activation function or major-mode match.
   8516    (if-let ((activation-fn (lsp--client-activation-fn client)))
   8517        (funcall activation-fn (buffer-file-name) major-mode)
   8518      (-contains? (lsp--client-major-modes client) major-mode))
   8519 
   8520    ;; check whether it is enabled if `lsp-enabled-clients' is not null
   8521    (or (null lsp-enabled-clients)
   8522        (or (member (lsp--client-server-id client) lsp-enabled-clients)
   8523            (ignore (lsp--info "Client %s is not in lsp-enabled-clients"
   8524                               (lsp--client-server-id client)))))
   8525 
   8526    ;; check whether it is not disabled.
   8527    (not (lsp--client-disabled-p major-mode (lsp--client-server-id client)))))
   8528 
   8529 (defun lsp--filter-clients (pred)
   8530   (->> lsp-clients hash-table-values (-filter pred)))
   8531 
   8532 (defun lsp--find-clients ()
   8533   "Find clients which can handle current buffer."
   8534   (-when-let (matching-clients (lsp--filter-clients (-andfn #'lsp--supports-buffer?
   8535                                                             #'lsp--server-binary-present?)))
   8536     (lsp-log "Found the following clients for %s: %s"
   8537              (buffer-file-name)
   8538              (s-join ", "
   8539                      (-map (lambda (client)
   8540                              (format "(server-id %s, priority %s)"
   8541                                      (lsp--client-server-id client)
   8542                                      (lsp--client-priority client)))
   8543                            matching-clients)))
   8544     (-let* (((add-on-clients main-clients) (-separate #'lsp--client-add-on? matching-clients))
   8545             (selected-clients (if-let ((main-client (and main-clients
   8546                                                          (--max-by (> (lsp--client-priority it)
   8547                                                                       (lsp--client-priority other))
   8548                                                                    main-clients))))
   8549                                   (cons main-client add-on-clients)
   8550                                 add-on-clients)))
   8551       (lsp-log "The following clients were selected based on priority: %s"
   8552                (s-join ", "
   8553                        (-map (lambda (client)
   8554                                (format "(server-id %s, priority %s)"
   8555                                        (lsp--client-server-id client)
   8556                                        (lsp--client-priority client)))
   8557                              selected-clients)))
   8558       selected-clients)))
   8559 
   8560 (defun lsp-workspace-remove-all-folders()
   8561   "Delete all lsp tracked folders."
   8562   (interactive)
   8563   (--each (lsp-session-folders (lsp-session))
   8564     (lsp-workspace-folders-remove it)))
   8565 
   8566 (defun lsp-register-client (client)
   8567   "Registers LSP client CLIENT."
   8568   (let ((client-id (lsp--client-server-id client)))
   8569     (puthash client-id client lsp-clients)
   8570     (setplist (intern (format "lsp-%s-after-open-hook" client-id))
   8571               `( standard-value (nil) custom-type hook
   8572                  custom-package-version (lsp-mode . "7.0.1")
   8573                  variable-documentation ,(format "Hooks to run after `%s' server is run." client-id)
   8574                  custom-requests nil)))
   8575   (when (and lsp-auto-register-remote-clients
   8576              (not (lsp--client-remote? client)))
   8577     (let ((remote-client (copy-lsp--client client)))
   8578       (setf (lsp--client-remote? remote-client) t
   8579             (lsp--client-server-id remote-client) (intern
   8580                                                    (format "%s-tramp"
   8581                                                            (lsp--client-server-id client)))
   8582             ;; disable automatic download
   8583             (lsp--client-download-server-fn remote-client) nil)
   8584       (lsp-register-client remote-client))))
   8585 
   8586 (defun lsp--create-initialization-options (_session client)
   8587   "Create initialization-options from SESSION and CLIENT.
   8588 Add workspace folders depending on server being multiroot and
   8589 session workspace folder configuration for the server."
   8590   (let* ((initialization-options-or-fn (lsp--client-initialization-options client)))
   8591     (if (functionp initialization-options-or-fn)
   8592         (funcall initialization-options-or-fn)
   8593       initialization-options-or-fn)))
   8594 
   8595 (defvar lsp-client-settings (make-hash-table :test 'equal)
   8596   "For internal use, any external users please use
   8597   `lsp-register-custom-settings' function instead")
   8598 
   8599 (defun lsp-register-custom-settings (props)
   8600   "Register PROPS.
   8601 PROPS is list of triple (path value boolean?) where PATH is the path to the
   8602 property; VALUE can be a literal value, symbol to be evaluated, or either a
   8603 function or lambda function to be called without arguments; BOOLEAN? is an
   8604 optional flag that should be non-nil for boolean settings, when it is nil the
   8605 property will be ignored if the VALUE is nil.
   8606 
   8607 Example: `(lsp-register-custom-settings `((\"foo.bar.buzz.enabled\" t t)))'
   8608 \(note the double parentheses)"
   8609   (mapc
   8610    (-lambda ((path . rest))
   8611      (puthash path rest lsp-client-settings))
   8612    props))
   8613 
   8614 (defun lsp-region-text (region)
   8615   "Get the text for REGION in current buffer."
   8616   (-let (((start . end) (lsp--range-to-region region)))
   8617     (buffer-substring-no-properties start end)))
   8618 
   8619 (defun lsp-ht-set (tbl paths value)
   8620   "Set nested hash table value.
   8621 TBL - a hash table, PATHS is the path to the nested VALUE."
   8622   (pcase paths
   8623     (`(,path) (ht-set! tbl path value))
   8624     (`(,path . ,rst) (let ((nested-tbl (or (gethash path tbl)
   8625                                            (let ((temp-tbl (ht)))
   8626                                              (ht-set! tbl path temp-tbl)
   8627                                              temp-tbl))))
   8628                        (lsp-ht-set nested-tbl rst value)))))
   8629 
   8630 ;; sections
   8631 
   8632 (defalias 'defcustom-lsp 'lsp-defcustom)
   8633 
   8634 (defmacro lsp-defcustom (symbol standard doc &rest args)
   8635   "Defines `lsp-mode' server property."
   8636   (declare (doc-string 3) (debug (name body))
   8637            (indent defun))
   8638   (let ((path (plist-get args :lsp-path)))
   8639     (cl-remf args :lsp-path)
   8640     `(progn
   8641        (lsp-register-custom-settings
   8642         (quote ((,path ,symbol ,(equal ''boolean (plist-get args :type))))))
   8643 
   8644        (defcustom ,symbol ,standard ,doc
   8645          :set (lambda (sym val)
   8646                 (lsp--set-custom-property sym val ,path))
   8647          ,@args))))
   8648 
   8649 (defun lsp--set-custom-property (sym val path)
   8650   (set sym val)
   8651   (let ((section (cl-first (s-split "\\." path))))
   8652     (mapc (lambda (workspace)
   8653             (when (-contains? (lsp--client-synchronize-sections (lsp--workspace-client workspace))
   8654                               section)
   8655               (with-lsp-workspace workspace
   8656                 (lsp--set-configuration (lsp-configuration-section section)))))
   8657           (lsp--session-workspaces (lsp-session)))))
   8658 
   8659 (defun lsp-configuration-section (section)
   8660   "Get settings for SECTION."
   8661   (let ((ret (ht-create)))
   8662     (maphash (-lambda (path (variable boolean?))
   8663                (when (s-matches? (concat (regexp-quote section) "\\..*") path)
   8664                  (let* ((symbol-value (-> variable
   8665                                           lsp-resolve-value
   8666                                           lsp-resolve-value))
   8667                         (value (if (and boolean? (not symbol-value))
   8668                                    :json-false
   8669                                  symbol-value)))
   8670                    (when (or boolean? value)
   8671                      (lsp-ht-set ret (s-split "\\." path) value)))))
   8672              lsp-client-settings)
   8673     ret))
   8674 
   8675 
   8676 (defun lsp--start-connection (session client project-root)
   8677   "Initiates connection created from CLIENT for PROJECT-ROOT.
   8678 SESSION is the active session."
   8679   (when (lsp--client-multi-root client)
   8680     (cl-pushnew project-root (gethash (lsp--client-server-id client)
   8681                                       (lsp-session-server-id->folders session))))
   8682   (run-hook-with-args 'lsp-workspace-folders-changed-functions (list project-root) nil)
   8683 
   8684   (unwind-protect
   8685       (lsp--start-workspace session client project-root (lsp--create-initialization-options session client))
   8686     (lsp--spinner-stop)))
   8687 
   8688 ;; lsp-log-io-mode
   8689 
   8690 (defvar lsp-log-io-mode-map
   8691   (let ((map (make-sparse-keymap)))
   8692     (define-key map (kbd "M-n") #'lsp-log-io-next)
   8693     (define-key map (kbd "M-p") #'lsp-log-io-prev)
   8694     (define-key map (kbd "k") #'lsp--erase-log-buffer)
   8695     (define-key map (kbd "K") #'lsp--erase-session-log-buffers)
   8696     map)
   8697   "Keymap for lsp log buffer mode.")
   8698 
   8699 (define-derived-mode lsp-log-io-mode special-mode "LspLogIo"
   8700   "Special mode for viewing IO logs.")
   8701 
   8702 (defun lsp-workspace-show-log (workspace)
   8703   "Display the log buffer of WORKSPACE."
   8704   (interactive
   8705    (list (if lsp-log-io
   8706              (if (eq (length (lsp-workspaces)) 1)
   8707                  (cl-first (lsp-workspaces))
   8708                (lsp--completing-read "Workspace: " (lsp-workspaces)
   8709                                      #'lsp--workspace-print nil t))
   8710            (user-error "IO logging is disabled"))))
   8711   (pop-to-buffer (lsp--get-log-buffer-create workspace)))
   8712 
   8713 (defalias 'lsp-switch-to-io-log-buffer 'lsp-workspace-show-log)
   8714 
   8715 (defun lsp--get-log-buffer-create (workspace)
   8716   "Return the lsp log buffer of WORKSPACE, creating a new one if needed."
   8717   (let* ((server-id (-> workspace lsp--workspace-client lsp--client-server-id symbol-name))
   8718          (pid (-> workspace lsp--workspace-cmd-proc lsp-process-id)))
   8719     (get-buffer-create (format "*lsp-log: %s:%s*" server-id pid))))
   8720 
   8721 (defun lsp--erase-log-buffer (&optional all)
   8722   "Delete contents of current lsp log buffer.
   8723 When ALL is t, erase all log buffers of the running session."
   8724   (interactive)
   8725   (let* ((workspaces (lsp--session-workspaces (lsp-session)))
   8726          (current-log-buffer (current-buffer)))
   8727     (dolist (w workspaces)
   8728       (let ((b (lsp--get-log-buffer-create w)))
   8729         (when (or all (eq b current-log-buffer))
   8730           (with-current-buffer b
   8731             (let ((inhibit-read-only t))
   8732               (erase-buffer))))))))
   8733 
   8734 (defun lsp--erase-session-log-buffers ()
   8735   "Erase log buffers of the running session."
   8736   (interactive)
   8737   (lsp--erase-log-buffer t))
   8738 
   8739 (defun lsp-log-io-next (arg)
   8740   "Move to next log entry."
   8741   (interactive "P")
   8742   (ewoc-goto-next lsp--log-io-ewoc (or arg 1)))
   8743 
   8744 (defun lsp-log-io-prev (arg)
   8745   "Move to previous log entry."
   8746   (interactive "P")
   8747   (ewoc-goto-prev lsp--log-io-ewoc (or arg 1)))
   8748 
   8749 
   8750 
   8751 (cl-defmethod lsp-process-id ((process process))
   8752   (process-id process))
   8753 
   8754 (cl-defmethod lsp-process-name ((process process)) (process-name process))
   8755 
   8756 (cl-defmethod lsp-process-status ((process process)) (process-status process))
   8757 
   8758 (cl-defmethod lsp-process-kill ((process process))
   8759   (when (process-live-p process)
   8760     (kill-process process)))
   8761 
   8762 (cl-defmethod lsp-process-send ((process process) message)
   8763   (condition-case err
   8764       (process-send-string process (lsp--make-message message))
   8765     (error (lsp--error "Sending to process failed with the following error: %s"
   8766                        (error-message-string err)))))
   8767 
   8768 (cl-defmethod lsp-process-cleanup (process)
   8769   ;; Kill standard error buffer only if the process exited normally.
   8770   ;; Leave it intact otherwise for debugging purposes.
   8771   (let ((buffer (-> process process-name get-buffer)))
   8772     (when (and (eq (process-status process) 'exit)
   8773                (zerop (process-exit-status process))
   8774                (buffer-live-p buffer))
   8775       (kill-buffer buffer))))
   8776 
   8777 
   8778 ;; native JSONRPC
   8779 
   8780 (declare-function json-rpc "ext:json")
   8781 (declare-function json-rpc-connection "ext:json")
   8782 (declare-function json-rpc-send "ext:json")
   8783 (declare-function json-rpc-shutdown "ext:json")
   8784 (declare-function json-rpc-stderr "ext:json")
   8785 (declare-function json-rpc-pid "ext:json")
   8786 
   8787 (defvar lsp-json-rpc-thread nil)
   8788 (defvar lsp-json-rpc-queue nil)
   8789 (defvar lsp-json-rpc-done nil)
   8790 (defvar lsp-json-rpc-mutex (make-mutex))
   8791 (defvar lsp-json-rpc-condition (make-condition-variable lsp-json-rpc-mutex))
   8792 
   8793 (defun lsp-json-rpc-process-queue ()
   8794   (while (not lsp-json-rpc-done)
   8795     (while lsp-json-rpc-queue
   8796       (-let (((proc . message) (pop lsp-json-rpc-queue)))
   8797         (json-rpc-send
   8798          proc message
   8799          :null-object nil
   8800          :false-object :json-false)))
   8801     (with-mutex lsp-json-rpc-mutex
   8802       (condition-wait lsp-json-rpc-condition))))
   8803 
   8804 (cl-defmethod lsp-process-id (process) (json-rpc-pid process))
   8805 
   8806 (cl-defmethod lsp-process-name (_process) "TBD")
   8807 
   8808 (cl-defmethod lsp-process-kill (process) (json-rpc-shutdown process))
   8809 
   8810 (cl-defmethod lsp-process-send (proc message)
   8811   (unless lsp-json-rpc-thread
   8812     (with-current-buffer (get-buffer-create " *json-rpc*")
   8813       (setq lsp-json-rpc-thread (make-thread #'lsp-json-rpc-process-queue "*json-rpc-queue*"))))
   8814 
   8815   (with-mutex lsp-json-rpc-mutex
   8816     (setq lsp-json-rpc-queue (append lsp-json-rpc-queue
   8817                                      (list (cons proc message))))
   8818     (condition-notify lsp-json-rpc-condition)))
   8819 
   8820 (cl-defmethod lsp-process-cleanup (_proc))
   8821 
   8822 (defun lsp-json-rpc-connection (workspace command)
   8823   (let ((con (apply #'json-rpc-connection command))
   8824         (object-type (if lsp-use-plists 'plist 'hash-table)))
   8825     (with-current-buffer (get-buffer-create " *json-rpc*")
   8826       (make-thread
   8827        (lambda ()
   8828          (json-rpc
   8829           con
   8830           (lambda (result err done)
   8831             (run-with-timer
   8832              0.0
   8833              nil
   8834              (lambda ()
   8835                (cond
   8836                 (result (lsp--parser-on-message result workspace))
   8837                 (err (warn "Json parsing failed with the following error: %s" err))
   8838                 (done (lsp--handle-process-exit workspace ""))))))
   8839           :object-type object-type
   8840           :null-object nil
   8841           :false-object nil))
   8842        "*json-rpc-connection*"))
   8843     (cons con con)))
   8844 
   8845 (defun lsp-json-rpc-stderr ()
   8846   (interactive)
   8847   (--when-let (pcase (lsp-workspaces)
   8848                 (`nil (user-error "There are no active servers in the current buffer"))
   8849                 (`(,workspace) workspace)
   8850                 (workspaces (lsp--completing-read "Select server: "
   8851                                                   workspaces
   8852                                                   'lsp--workspace-print nil t)))
   8853     (let ((content (json-rpc-stderr (lsp--workspace-cmd-proc it)))
   8854           (buffer (format "*stderr-%s*" (lsp--workspace-print it)) ))
   8855       (with-current-buffer (get-buffer-create buffer)
   8856         (with-help-window buffer
   8857           (insert content))))))
   8858 
   8859 
   8860 (defun lsp--workspace-print (workspace)
   8861   "Visual representation WORKSPACE."
   8862   (let* ((proc (lsp--workspace-cmd-proc workspace))
   8863          (status (lsp--workspace-status workspace))
   8864          (server-id (-> workspace lsp--workspace-client lsp--client-server-id symbol-name))
   8865          (pid (lsp-process-id proc)))
   8866 
   8867     (if (eq 'initialized status)
   8868         (format "%s:%s" server-id pid)
   8869       (format "%s:%s/%s" server-id pid status))))
   8870 
   8871 (defun lsp--map-tree-widget (m)
   8872   "Build `tree-widget' from a hash-table or plist M."
   8873   (when (lsp-structure-p m)
   8874     (let (nodes)
   8875       (lsp-map (lambda (k v)
   8876                  (push `(tree-widget
   8877                          :tag ,(if (lsp-structure-p v)
   8878                                    (format "%s:" k)
   8879                                  (format "%s: %s" k
   8880                                          (propertize (format "%s" v)
   8881                                                      'face
   8882                                                      'font-lock-string-face)))
   8883                          :open t
   8884                          ,@(lsp--map-tree-widget v))
   8885                        nodes))
   8886                m)
   8887       nodes)))
   8888 
   8889 (defun lsp-buffer-name (buffer-id)
   8890   (if-let ((buffer-name (plist-get buffer-id :buffer-name)))
   8891       (funcall buffer-name buffer-id)
   8892     (buffer-name buffer-id)))
   8893 
   8894 (defun lsp--render-workspace (workspace)
   8895   "Tree node representation of WORKSPACE."
   8896   `(tree-widget :tag ,(lsp--workspace-print workspace)
   8897                 :open t
   8898                 (tree-widget :tag ,(propertize "Buffers" 'face 'font-lock-function-name-face)
   8899                              :open t
   8900                              ,@(->> workspace
   8901                                     (lsp--workspace-buffers)
   8902                                     (--map `(tree-widget
   8903                                              :tag ,(when (lsp-buffer-live-p it)
   8904                                                      (let ((buffer-name (lsp-buffer-name it)))
   8905                                                        (if (lsp-with-current-buffer it buffer-read-only)
   8906                                                            (propertize buffer-name 'face 'font-lock-constant-face)
   8907                                                          buffer-name)))))))
   8908                 (tree-widget :tag ,(propertize "Capabilities" 'face 'font-lock-function-name-face)
   8909                              ,@(-> workspace lsp--workspace-server-capabilities lsp--map-tree-widget))))
   8910 
   8911 (define-derived-mode lsp-browser-mode special-mode "LspBrowser"
   8912   "Define mode for displaying lsp sessions."
   8913   (setq-local display-buffer-base-action '(nil . ((inhibit-same-window . t)))))
   8914 
   8915 (defun lsp-describe-session ()
   8916   "Describes current `lsp-session'."
   8917   (interactive)
   8918   (let ((session (lsp-session))
   8919         (buf (get-buffer-create "*lsp session*"))
   8920         (root (lsp-workspace-root)))
   8921     (with-current-buffer buf
   8922       (lsp-browser-mode)
   8923       (let ((inhibit-read-only t))
   8924         (erase-buffer)
   8925         (--each (lsp-session-folders session)
   8926           (widget-create
   8927            `(tree-widget
   8928              :tag ,(propertize it 'face 'font-lock-keyword-face)
   8929              :open t
   8930              ,@(->> session
   8931                     (lsp-session-folder->servers)
   8932                     (gethash it)
   8933                     (-map 'lsp--render-workspace)))))))
   8934     (pop-to-buffer buf)
   8935     (goto-char (point-min))
   8936     (cl-loop for tag = (widget-get (widget-get (widget-at) :node) :tag)
   8937              until (or (and root (string= tag root)) (eobp))
   8938              do (goto-char (next-overlay-change (point))))))
   8939 
   8940 (defun lsp--session-workspaces (session)
   8941   "Get all workspaces that are part of the SESSION."
   8942   (-> session lsp-session-folder->servers hash-table-values -flatten -uniq))
   8943 
   8944 (defun lsp--find-multiroot-workspace (session client project-root)
   8945   "Look for a multiroot connection in SESSION created from CLIENT for
   8946 PROJECT-ROOT and BUFFER-MAJOR-MODE."
   8947   (when (lsp--client-multi-root client)
   8948     (-when-let (multi-root-workspace (->> session
   8949                                           (lsp--session-workspaces)
   8950                                           (--first (eq (-> it lsp--workspace-client lsp--client-server-id)
   8951                                                        (lsp--client-server-id client)))))
   8952       (with-lsp-workspace multi-root-workspace
   8953         (lsp-notify "workspace/didChangeWorkspaceFolders"
   8954                     (lsp-make-did-change-workspace-folders-params
   8955                      :event (lsp-make-workspace-folders-change-event
   8956                              :added (vector (lsp-make-workspace-folder
   8957                                              :uri (lsp--path-to-uri project-root)
   8958                                              :name (f-filename project-root)))
   8959                              :removed []))))
   8960 
   8961       (->> session (lsp-session-folder->servers) (gethash project-root) (cl-pushnew multi-root-workspace))
   8962       (->> session (lsp-session-server-id->folders) (gethash (lsp--client-server-id client)) (cl-pushnew project-root))
   8963 
   8964       (lsp--persist-session session)
   8965 
   8966       (lsp--info "Opened folder %s in workspace %s" project-root (lsp--workspace-print multi-root-workspace))
   8967       (lsp--open-in-workspace multi-root-workspace)
   8968 
   8969       multi-root-workspace)))
   8970 
   8971 (defun lsp--ensure-lsp-servers (session clients project-root ignore-multi-folder)
   8972   "Ensure that SESSION contain server CLIENTS created for PROJECT-ROOT.
   8973 IGNORE-MULTI-FOLDER to ignore multi folder server."
   8974   (-map (lambda (client)
   8975           (or
   8976            (lsp--find-workspace session client project-root)
   8977            (unless ignore-multi-folder
   8978              (lsp--find-multiroot-workspace session client project-root))
   8979            (lsp--start-connection session client project-root)))
   8980         clients))
   8981 
   8982 (defun lsp--spinner-stop ()
   8983   "Stop the spinner in case all of the workspaces are started."
   8984   (when (--all? (eq (lsp--workspace-status it) 'initialized)
   8985                 lsp--buffer-workspaces)
   8986     (spinner-stop)))
   8987 
   8988 (defun lsp--open-in-workspace (workspace)
   8989   "Open in existing WORKSPACE."
   8990   (if (eq 'initialized (lsp--workspace-status workspace))
   8991       ;; when workspace is initialized just call document did open.
   8992       (progn
   8993         (with-lsp-workspace workspace
   8994           (when-let ((before-document-open-fn (-> workspace
   8995                                                   lsp--workspace-client
   8996                                                   lsp--client-before-file-open-fn)))
   8997             (funcall before-document-open-fn workspace))
   8998           (lsp--text-document-did-open))
   8999         (lsp--spinner-stop))
   9000     ;; when it is not initialized
   9001     (lsp--spinner-start)
   9002     (cl-pushnew (lsp-current-buffer) (lsp--workspace-buffers workspace))))
   9003 
   9004 (defun lsp--find-workspace (session client project-root)
   9005   "Find server connection created with CLIENT in SESSION for PROJECT-ROOT."
   9006   (when-let ((workspace (->> session
   9007                              (lsp-session-folder->servers)
   9008                              (gethash project-root)
   9009                              (--first (eql (-> it lsp--workspace-client lsp--client-server-id)
   9010                                            (lsp--client-server-id client))))))
   9011     (lsp--open-in-workspace workspace)
   9012     workspace))
   9013 
   9014 (defun lsp--read-char (prompt &optional options)
   9015   "Wrapper for `read-char-from-minibuffer' if Emacs +27.
   9016 Fallback to `read-key' otherwise.
   9017 PROMPT is the message and OPTIONS the available options."
   9018   (if (fboundp 'read-char-from-minibuffer)
   9019       (read-char-from-minibuffer prompt options)
   9020     (read-key prompt)))
   9021 
   9022 (defun lsp--find-root-interactively (session)
   9023   "Find project interactively.
   9024 Returns nil if the project should not be added to the current SESSION."
   9025   (condition-case nil
   9026       (let* ((project-root-suggestion (or (lsp--suggest-project-root) default-directory))
   9027              (action (lsp--read-char
   9028                       (format
   9029                        "%s is not part of any project.
   9030 
   9031 %s ==> Import project root %s
   9032 %s ==> Import project by selecting root directory interactively
   9033 %s ==> Import project at current directory %s
   9034 %s ==> Do not ask again for the current project by adding %s to lsp-session-folders-blocklist
   9035 %s ==> Do not ask again for the current project by selecting ignore path interactively
   9036 %s ==> Do nothing: ask again when opening other files from the current project
   9037 
   9038 Select action: "
   9039                        (propertize (buffer-name) 'face 'bold)
   9040                        (propertize "i" 'face 'success)
   9041                        (propertize project-root-suggestion 'face 'bold)
   9042                        (propertize "I" 'face 'success)
   9043                        (propertize "." 'face 'success)
   9044                        (propertize default-directory 'face 'bold)
   9045                        (propertize "d" 'face 'warning)
   9046                        (propertize project-root-suggestion 'face 'bold)
   9047                        (propertize "D" 'face 'warning)
   9048                        (propertize "n" 'face 'warning))
   9049                       '(?i ?\r ?I ?. ?d ?D ?n))))
   9050         (cl-case action
   9051           (?i project-root-suggestion)
   9052           (?\r project-root-suggestion)
   9053           (?I (read-directory-name "Select workspace folder to add: "
   9054                                    (or project-root-suggestion default-directory)
   9055                                    nil
   9056                                    t))
   9057           (?. default-directory)
   9058           (?d (push project-root-suggestion (lsp-session-folders-blocklist session))
   9059               (lsp--persist-session session)
   9060               nil)
   9061           (?D (push (read-directory-name "Select folder to blocklist: "
   9062                                          (or project-root-suggestion default-directory)
   9063                                          nil
   9064                                          t)
   9065                     (lsp-session-folders-blocklist session))
   9066               (lsp--persist-session session)
   9067               nil)
   9068           (t nil)))
   9069     (quit)))
   9070 
   9071 (declare-function tramp-file-name-host "ext:tramp" (file) t)
   9072 (declare-function tramp-dissect-file-name "ext:tramp" (file &optional nodefault))
   9073 
   9074 (defun lsp--files-same-host (f1 f2)
   9075   "Predicate on whether or not two files are on the same host."
   9076   (or (not (or (file-remote-p f1) (file-remote-p f2)))
   9077       (and (file-remote-p f1)
   9078            (file-remote-p f2)
   9079            (progn (require 'tramp)
   9080                   (equal (tramp-file-name-host (tramp-dissect-file-name f1))
   9081                          (tramp-file-name-host (tramp-dissect-file-name f2)))))))
   9082 
   9083 (defun lsp-find-session-folder (session file-name)
   9084   "Look in the current SESSION for folder containing FILE-NAME."
   9085   (let ((file-name-canonical (lsp-f-canonical file-name)))
   9086     (->> session
   9087          (lsp-session-folders)
   9088          (--filter (and (lsp--files-same-host it file-name-canonical)
   9089                         (or (lsp-f-same? it file-name-canonical)
   9090                             (and (f-dir? it)
   9091                                  (lsp-f-ancestor-of? it file-name-canonical)))))
   9092          (--max-by (> (length it)
   9093                       (length other))))))
   9094 
   9095 (defun lsp-find-workspace (server-id &optional file-name)
   9096   "Find workspace for SERVER-ID for FILE-NAME."
   9097   (-when-let* ((session (lsp-session))
   9098                (folder->servers (lsp-session-folder->servers session))
   9099                (workspaces (if file-name
   9100                                (gethash (lsp-find-session-folder session file-name) folder->servers)
   9101                              (lsp--session-workspaces session))))
   9102 
   9103     (--first (eq (lsp--client-server-id (lsp--workspace-client it)) server-id) workspaces)))
   9104 
   9105 (defun lsp--calculate-root (session file-name)
   9106   "Calculate project root for FILE-NAME in SESSION."
   9107   (and
   9108    (->> session
   9109         (lsp-session-folders-blocklist)
   9110         (--first (and (lsp--files-same-host it file-name)
   9111                       (lsp-f-ancestor-of? it file-name)
   9112                       (prog1 t
   9113                         (lsp--info "File %s is in blocklisted directory %s" file-name it))))
   9114         not)
   9115    (or
   9116     (when lsp-auto-guess-root
   9117       (lsp--suggest-project-root))
   9118     (unless lsp-guess-root-without-session
   9119       (lsp-find-session-folder session file-name))
   9120     (unless lsp-auto-guess-root
   9121       (when-let ((root-folder (lsp--find-root-interactively session)))
   9122         (if (or (not (f-equal? root-folder (expand-file-name "~/")))
   9123                 (yes-or-no-p
   9124                  (concat
   9125                   (propertize "[WARNING] " 'face 'warning)
   9126                   "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:
   9127 
   9128 1. Use `I' option from the interactive project import to select subfolder(e. g. `~/foo/bar' instead of `~/').
   9129 2. If your file is under `~/' then create a subfolder and move that file in this folder.
   9130 
   9131 Type `No' to go back to project selection.
   9132 Type `Yes' to confirm `HOME' as project root.
   9133 Type `C-g' to cancel project import process and stop `lsp'")))
   9134             root-folder
   9135           (lsp--calculate-root session file-name)))))))
   9136 
   9137 (defun lsp--try-open-in-library-workspace ()
   9138   "Try opening current file as library file in any of the active workspace.
   9139 The library folders are defined by each client for each of the active workspace."
   9140   (when-let ((workspace (->> (lsp-session)
   9141                              (lsp--session-workspaces)
   9142                              ;; Sort the last active workspaces first as they are more likely to be
   9143                              ;; the correct ones, especially when jumping to a definition.
   9144                              (-sort (lambda (a _b)
   9145                                       (-contains? lsp--last-active-workspaces a)))
   9146                              (--first
   9147                               (and (-> it lsp--workspace-client lsp--supports-buffer?)
   9148                                    (when-let ((library-folders-fn
   9149                                                (-> it lsp--workspace-client lsp--client-library-folders-fn)))
   9150                                      (-first (lambda (library-folder)
   9151                                                (lsp-f-ancestor-of? library-folder (buffer-file-name)))
   9152                                              (funcall library-folders-fn it))))))))
   9153     (lsp--open-in-workspace workspace)
   9154     (view-mode t)
   9155     (lsp--info "Opening read-only library file %s." (buffer-file-name))
   9156     (list workspace)))
   9157 
   9158 (defun lsp--persist-session (session)
   9159   "Persist SESSION to `lsp-session-file'."
   9160   (lsp--persist lsp-session-file (make-lsp-session
   9161                                   :folders (lsp-session-folders session)
   9162                                   :folders-blocklist (lsp-session-folders-blocklist session)
   9163                                   :server-id->folders (lsp-session-server-id->folders session))))
   9164 
   9165 (defun lsp--try-project-root-workspaces (ask-for-client ignore-multi-folder)
   9166   "Try create opening file as a project file.
   9167 When IGNORE-MULTI-FOLDER is t the lsp mode will start new
   9168 language server even if there is language server which can handle
   9169 current language. When IGNORE-MULTI-FOLDER is nil current file
   9170 will be opened in multi folder language server if there is
   9171 such."
   9172   (-let ((session (lsp-session)))
   9173     (-if-let (clients (if ask-for-client
   9174                           (list (lsp--completing-read "Select server to start: "
   9175                                                       (ht-values lsp-clients)
   9176                                                       (-compose 'symbol-name 'lsp--client-server-id) nil t))
   9177                         (lsp--find-clients)))
   9178         (-if-let (project-root (-some-> session
   9179                                  (lsp--calculate-root (buffer-file-name))
   9180                                  (lsp-f-canonical)))
   9181             (progn
   9182               ;; update project roots if needed and persist the lsp session
   9183               (unless (-contains? (lsp-session-folders session) project-root)
   9184                 (cl-pushnew project-root (lsp-session-folders session))
   9185                 (lsp--persist-session session))
   9186               (lsp--ensure-lsp-servers session clients project-root ignore-multi-folder))
   9187           (lsp--warn "%s not in project or it is blocklisted." (buffer-name))
   9188           nil)
   9189       (lsp--warn "No LSP server for %s(check *lsp-log*)." major-mode)
   9190       nil)))
   9191 
   9192 (defun lsp-shutdown-workspace ()
   9193   "Shutdown language server."
   9194   (interactive)
   9195   (--when-let (pcase (lsp-workspaces)
   9196                 (`nil (user-error "There are no active servers in the current buffer"))
   9197                 (`(,workspace) (when (y-or-n-p (format "Are you sure you want to stop the server %s?"
   9198                                                        (lsp--workspace-print workspace)))
   9199                                  workspace))
   9200                 (workspaces (lsp--completing-read "Select server: "
   9201                                                   workspaces
   9202                                                   'lsp--workspace-print nil t)))
   9203     (lsp-workspace-shutdown it)))
   9204 
   9205 (make-obsolete 'lsp-shutdown-workspace 'lsp-workspace-shutdown "lsp-mode 6.1")
   9206 
   9207 (defcustom lsp-auto-select-workspace t
   9208   "Shutdown or restart a single workspace.
   9209 If set and the current buffer has only a single workspace
   9210 associated with it, `lsp-shutdown-workspace' and
   9211 `lsp-restart-workspace' will act on it without asking."
   9212   :type 'boolean
   9213   :group 'lsp-mode)
   9214 
   9215 (defun lsp--read-workspace ()
   9216   "Ask the user to select a workspace.
   9217 Errors if there are none."
   9218   (pcase (lsp-workspaces)
   9219     (`nil (error "No workspaces associated with the current buffer"))
   9220     ((and `(,workspace) (guard lsp-auto-select-workspace)) workspace)
   9221     (workspaces (lsp--completing-read "Select workspace: " workspaces
   9222                                       #'lsp--workspace-print nil t))))
   9223 
   9224 (defun lsp-workspace-shutdown (workspace)
   9225   "Shut the workspace WORKSPACE and the language server associated with it"
   9226   (interactive (list (lsp--read-workspace)))
   9227   (lsp--warn "Stopping %s" (lsp--workspace-print workspace))
   9228   (with-lsp-workspace workspace (lsp--shutdown-workspace)))
   9229 
   9230 (defun lsp-disconnect ()
   9231   "Disconnect the buffer from the language server."
   9232   (interactive)
   9233   (lsp--text-document-did-close t)
   9234   (lsp-managed-mode -1)
   9235   (lsp-mode -1)
   9236   (setq lsp--buffer-workspaces nil)
   9237   (lsp--info "Disconnected"))
   9238 
   9239 (defun lsp-restart-workspace ()
   9240   (interactive)
   9241   (--when-let (pcase (lsp-workspaces)
   9242                 (`nil (user-error "There are no active servers in the current buffer"))
   9243                 (`(,workspace) workspace)
   9244                 (workspaces (lsp--completing-read "Select server: "
   9245                                                   workspaces
   9246                                                   'lsp--workspace-print nil t)))
   9247     (lsp-workspace-restart it)))
   9248 
   9249 (make-obsolete 'lsp-restart-workspace 'lsp-workspace-restart "lsp-mode 6.1")
   9250 
   9251 (defun lsp-workspace-restart (workspace)
   9252   "Restart the workspace WORKSPACE and the language server associated with it"
   9253   (interactive (list (lsp--read-workspace)))
   9254   (lsp--warn "Restarting %s" (lsp--workspace-print workspace))
   9255   (with-lsp-workspace workspace (lsp--shutdown-workspace t)))
   9256 
   9257 ;;;###autoload
   9258 (defun lsp (&optional arg)
   9259   "Entry point for the server startup.
   9260 When ARG is t the lsp mode will start new language server even if
   9261 there is language server which can handle current language. When
   9262 ARG is nil current file will be opened in multi folder language
   9263 server if there is such. When `lsp' is called with prefix
   9264 argument ask the user to select which language server to start."
   9265   (interactive "P")
   9266 
   9267   (lsp--require-packages)
   9268 
   9269   (when (buffer-file-name)
   9270     (let (clients
   9271           (matching-clients (lsp--filter-clients
   9272                              (-andfn #'lsp--supports-buffer?
   9273                                      #'lsp--server-binary-present?))))
   9274       (cond
   9275        (matching-clients
   9276         (when (setq lsp--buffer-workspaces
   9277                     (or (and
   9278                          ;; Don't open as library file if file is part of a project.
   9279                          (not (lsp-find-session-folder (lsp-session) (buffer-file-name)))
   9280                          (lsp--try-open-in-library-workspace))
   9281                         (lsp--try-project-root-workspaces (equal arg '(4))
   9282                                                           (and arg (not (equal arg 1))))))
   9283           (lsp-mode 1)
   9284           (when lsp-auto-configure (lsp--auto-configure))
   9285           (setq lsp-buffer-uri (lsp--buffer-uri))
   9286           (lsp--info "Connected to %s."
   9287                      (apply 'concat (--map (format "[%s %s]"
   9288                                                    (lsp--workspace-print it)
   9289                                                    (lsp--workspace-root it))
   9290                                            lsp--buffer-workspaces)))))
   9291        ;; look for servers which are currently being downloaded.
   9292        ((setq clients (lsp--filter-clients (-andfn #'lsp--supports-buffer?
   9293                                                    #'lsp--client-download-in-progress?)))
   9294         (lsp--info "There are language server(%s) installation in progress.
   9295 The server(s) will be started in the buffer when it has finished."
   9296                    (-map #'lsp--client-server-id clients))
   9297         (seq-do (lambda (client)
   9298                   (cl-pushnew (current-buffer) (lsp--client-buffers client)))
   9299                 clients))
   9300        ;; look for servers to install
   9301        ((setq clients (lsp--filter-clients
   9302                        (-andfn #'lsp--supports-buffer?
   9303                                (-const lsp-enable-suggest-server-download)
   9304                                #'lsp--client-download-server-fn
   9305                                (-not #'lsp--client-download-in-progress?))))
   9306         (let ((client (lsp--completing-read
   9307                        (concat "Unable to find installed server supporting this file. "
   9308                                "The following servers could be installed automatically: ")
   9309                        clients
   9310                        (-compose #'symbol-name #'lsp--client-server-id)
   9311                        nil
   9312                        t)))
   9313           (cl-pushnew (current-buffer) (lsp--client-buffers client))
   9314           (lsp--install-server-internal client)))
   9315        ;; ignore other warnings
   9316        ((not lsp-warn-no-matched-clients)
   9317         nil)
   9318        ;; automatic installation disabled
   9319        ((setq clients (unless matching-clients
   9320                         (lsp--filter-clients (-andfn #'lsp--supports-buffer?
   9321                                                      #'lsp--client-download-server-fn
   9322                                                      (-not (-const lsp-enable-suggest-server-download))
   9323                                                      (-not #'lsp--server-binary-present?)))))
   9324         (lsp--warn "The following servers support current file but automatic download is disabled: %s
   9325 \(If you have already installed the server check *lsp-log*)."
   9326                    (mapconcat (lambda (client)
   9327                                 (symbol-name (lsp--client-server-id client)))
   9328                               clients
   9329                               " ")))
   9330        ;; no clients present
   9331        ((setq clients (unless matching-clients
   9332                         (lsp--filter-clients (-andfn #'lsp--supports-buffer?
   9333                                                      (-not #'lsp--server-binary-present?)))))
   9334         (lsp--warn "The following servers support current file but do not have automatic installation: %s
   9335 You may find the installation instructions at https://emacs-lsp.github.io/lsp-mode/page/languages.
   9336 \(If you have already installed the server check *lsp-log*)."
   9337                    (mapconcat (lambda (client)
   9338                                 (symbol-name (lsp--client-server-id client)))
   9339                               clients
   9340                               " ")))
   9341        ;; no matches
   9342        ((-> #'lsp--supports-buffer? lsp--filter-clients not)
   9343         (lsp--error "There are no language servers supporting current mode `%s' registered with `lsp-mode'.
   9344 This issue might be caused by:
   9345 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'.
   9346 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'.
   9347 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/ .
   9348 4. You are over `tramp'. In this case follow https://emacs-lsp.github.io/lsp-mode/page/remote/.
   9349 5. You have disabled the `lsp-mode' clients for that file. (Check `lsp-enabled-clients' and `lsp-disabled-clients').
   9350 You can customize `lsp-warn-no-matched-clients' to disable this message."
   9351                     major-mode major-mode major-mode))))))
   9352 
   9353 (defun lsp--buffer-visible-p ()
   9354   "Return non nil if current buffer is visible."
   9355   (or (buffer-modified-p) (get-buffer-window nil t)))
   9356 
   9357 (defun lsp--init-if-visible ()
   9358   "Run `lsp' for the current buffer if the buffer is visible.
   9359 Returns non nil if `lsp' was run for the buffer."
   9360   (when (lsp--buffer-visible-p)
   9361     (remove-hook 'window-configuration-change-hook #'lsp--init-if-visible t)
   9362     (lsp)
   9363     t))
   9364 
   9365 ;;;###autoload
   9366 (defun lsp-deferred ()
   9367   "Entry point that defers server startup until buffer is visible.
   9368 `lsp-deferred' will wait until the buffer is visible before invoking `lsp'.
   9369 This avoids overloading the server with many files when starting Emacs."
   9370   ;; Workspace may not be initialized yet. Use a buffer local variable to
   9371   ;; remember that we deferred loading of this buffer.
   9372   (setq lsp--buffer-deferred t)
   9373   (let ((buffer (current-buffer)))
   9374     ;; Avoid false positives as desktop-mode restores buffers by deferring
   9375     ;; visibility check until the stack clears.
   9376     (run-with-idle-timer 0 nil (lambda ()
   9377                                  (when (buffer-live-p buffer)
   9378                                    (with-current-buffer buffer
   9379                                      (unless (lsp--init-if-visible)
   9380                                        (add-hook 'window-configuration-change-hook #'lsp--init-if-visible nil t))))))))
   9381 
   9382 
   9383 
   9384 (defvar lsp-file-truename-cache (ht))
   9385 
   9386 (defmacro lsp-with-cached-filetrue-name (&rest body)
   9387   "Executes BODY caching the `file-truename' calls."
   9388   `(let ((old-fn (symbol-function 'file-truename)))
   9389      (unwind-protect
   9390          (progn
   9391            (fset 'file-truename
   9392                  (lambda (file-name &optional counter prev-dirs)
   9393                    (or (gethash file-name lsp-file-truename-cache)
   9394                        (puthash file-name (apply old-fn (list file-name counter prev-dirs))
   9395                                 lsp-file-truename-cache))))
   9396            ,@body)
   9397        (fset 'file-truename old-fn))))
   9398 
   9399 
   9400 (defun lsp-virtual-buffer-call (key &rest args)
   9401   (when lsp--virtual-buffer
   9402     (when-let ((fn (plist-get lsp--virtual-buffer key)))
   9403       (apply fn args))))
   9404 
   9405 (defun lsp-translate-column (column)
   9406   "Translate COLUMN taking into account virtual buffers."
   9407   (or (lsp-virtual-buffer-call :real->virtual-char column)
   9408       column))
   9409 
   9410 (defun lsp-translate-line (line)
   9411   "Translate LINE taking into account virtual buffers."
   9412   (or (lsp-virtual-buffer-call :real->virtual-line line)
   9413       line))
   9414 
   9415 
   9416 ;; lsp internal validation.
   9417 
   9418 (defmacro lsp--doctor (&rest checks)
   9419   `(-let [buf (current-buffer)]
   9420      (with-current-buffer (get-buffer-create "*lsp-performance*")
   9421        (with-help-window (current-buffer)
   9422          ,@(-map (-lambda ((msg form))
   9423                    `(insert (format "%s: %s\n" ,msg
   9424                                     (let ((res (with-current-buffer buf
   9425                                                  ,form)))
   9426                                       (cond
   9427                                        ((eq res :optional) (propertize "OPTIONAL" 'face 'warning))
   9428                                        (res (propertize "OK" 'face 'success))
   9429                                        (t (propertize "ERROR" 'face 'error)))))))
   9430                  (-partition 2 checks))))))
   9431 
   9432 (define-obsolete-function-alias 'lsp-diagnose
   9433   'lsp-doctor "lsp-mode 8.0.0")
   9434 
   9435 (defun lsp-doctor ()
   9436   "Validate performance settings."
   9437   (interactive)
   9438   (lsp--doctor
   9439    "Checking for Native JSON support" (functionp 'json-serialize)
   9440    "Check emacs supports `read-process-output-max'" (boundp 'read-process-output-max)
   9441    "Check `read-process-output-max' default has been changed from 4k"
   9442    (and (boundp 'read-process-output-max)
   9443         (> read-process-output-max 4096))
   9444    "Byte compiled against Native JSON (recompile lsp-mode if failing when Native JSON available)"
   9445    (condition-case _err
   9446        (progn (lsp--make-message (list "a" "b"))
   9447               nil)
   9448      (error t))
   9449    "`gc-cons-threshold' increased?" (> gc-cons-threshold 800000)
   9450    "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)
   9451    "Using emacs 28+ with native compilation?"
   9452    (or (and (fboundp 'native-comp-available-p)
   9453             (native-comp-available-p))
   9454        :optional)))
   9455 
   9456 (declare-function package-version-join "ext:package")
   9457 (declare-function package-desc-version "ext:package")
   9458 (declare-function package--alist "ext:package")
   9459 
   9460 (defun lsp-version ()
   9461   "Return string describing current version of `lsp-mode'."
   9462   (interactive)
   9463   (unless (featurep 'package)
   9464     (require 'package))
   9465   (let ((ver (format "lsp-mode %s, Emacs %s, %s"
   9466                      (package-version-join
   9467                       (package-desc-version
   9468                        (car (alist-get 'lsp-mode (package--alist)))))
   9469                      emacs-version
   9470                      system-type)))
   9471     (if (called-interactively-p 'interactive)
   9472         (lsp--info "%s" ver)
   9473       ver)))
   9474 
   9475 
   9476 
   9477 ;; org-mode/virtual-buffer
   9478 
   9479 (declare-function org-babel-get-src-block-info "ext:ob-core")
   9480 (declare-function org-do-remove-indentation "ext:org-macs")
   9481 (declare-function org-src-get-lang-mode "ext:org-src")
   9482 (declare-function org-element-context "ext:org-element")
   9483 
   9484 (defun lsp--virtual-buffer-update-position ()
   9485   (-if-let (virtual-buffer (-first (-lambda ((&plist :in-range))
   9486                                      (funcall in-range))
   9487                                    lsp--virtual-buffer-connections))
   9488       (unless (equal virtual-buffer lsp--virtual-buffer)
   9489         (lsp-org))
   9490     (when lsp-managed-mode
   9491       (lsp-managed-mode -1)
   9492       (lsp-mode -1)
   9493       (setq lsp--buffer-workspaces nil)
   9494       (setq lsp--virtual-buffer nil)
   9495       (setq lsp-buffer-uri nil)
   9496 
   9497       ;; force refresh of diagnostics
   9498       (run-hooks 'lsp-after-diagnostics-hook))))
   9499 
   9500 (defun lsp-virtual-buffer-on-change (start end length)
   9501   "Adjust on change event to be executed against the proper language server."
   9502   (let ((max-point (max end
   9503                         (or (plist-get lsp--before-change-vals :end) 0)
   9504                         (+ start length))))
   9505     (when-let ((virtual-buffer (-first (lambda (vb)
   9506                                          (let ((lsp--virtual-buffer vb))
   9507                                            (and (lsp-virtual-buffer-call :in-range start)
   9508                                                 (lsp-virtual-buffer-call :in-range max-point))))
   9509                                        lsp--virtual-buffer-connections)))
   9510       (lsp-with-current-buffer virtual-buffer
   9511         (lsp-on-change start end length
   9512                        (lambda (&rest _)
   9513                          (list :range (lsp--range (list :character 0 :line 0)
   9514                                                   lsp--virtual-buffer-point-max)
   9515                                :text (lsp--buffer-content))))))))
   9516 
   9517 (defun lsp-virtual-buffer-before-change (start _end)
   9518   (when-let ((virtual-buffer (-first (lambda (vb)
   9519                                        (lsp-with-current-buffer vb
   9520                                          (lsp-virtual-buffer-call :in-range start)))
   9521                                      lsp--virtual-buffer-connections)))
   9522     (lsp-with-current-buffer virtual-buffer
   9523       (setq lsp--virtual-buffer-point-max
   9524             (lsp--point-to-position (lsp-virtual-buffer-call :last-point))))))
   9525 
   9526 (defun lsp-patch-on-change-event ()
   9527   (remove-hook 'after-change-functions #'lsp-on-change t)
   9528   (add-hook 'after-change-functions #'lsp-virtual-buffer-on-change nil t)
   9529   (add-hook 'before-change-functions #'lsp-virtual-buffer-before-change nil t))
   9530 
   9531 (defun lsp-kill-virtual-buffers ()
   9532   (mapc #'lsp-virtual-buffer-disconnect lsp--virtual-buffer-connections))
   9533 
   9534 (defun lsp--move-point-in-indentation (point indentation)
   9535   (save-excursion
   9536     (goto-char point)
   9537     (if (<= point (+ (line-beginning-position) indentation))
   9538         (line-beginning-position)
   9539       point)))
   9540 
   9541 (declare-function flycheck-checker-supports-major-mode-p "ext:flycheck")
   9542 (declare-function flycheck-add-mode "ext:flycheck")
   9543 (declare-function lsp-diagnostics-lsp-checker-if-needed "lsp-diagnostics")
   9544 
   9545 (defalias 'lsp-client-download-server-fn 'lsp--client-download-server-fn)
   9546 
   9547 (defun lsp-flycheck-add-mode (mode)
   9548   "Register flycheck support for MODE."
   9549   (lsp-diagnostics-lsp-checker-if-needed)
   9550   (unless (flycheck-checker-supports-major-mode-p 'lsp mode)
   9551     (flycheck-add-mode 'lsp mode)))
   9552 
   9553 (defun lsp-progress-spinner-type ()
   9554   "Retrieve the spinner type value, if value is not a symbol of `spinner-types
   9555 defaults to `progress-bar."
   9556   (or (car (assoc lsp-progress-spinner-type spinner-types)) 'progress-bar))
   9557 
   9558 (defun lsp-org ()
   9559   (interactive)
   9560   (-if-let ((virtual-buffer &as &plist :workspaces) (-first (-lambda ((&plist :in-range))
   9561                                                               (funcall in-range))
   9562                                                             lsp--virtual-buffer-connections))
   9563       (unless (equal lsp--virtual-buffer virtual-buffer)
   9564         (setq lsp--buffer-workspaces workspaces)
   9565         (setq lsp--virtual-buffer virtual-buffer)
   9566         (setq lsp-buffer-uri nil)
   9567         (lsp-mode 1)
   9568         (lsp-managed-mode 1)
   9569         (lsp-patch-on-change-event))
   9570 
   9571     (save-excursion
   9572       (-let* (virtual-buffer
   9573               (wcb (lambda (f)
   9574                      (with-current-buffer (plist-get virtual-buffer :buffer)
   9575                        (-let* (((&plist :major-mode :buffer-file-name
   9576                                         :goto-buffer :workspaces) virtual-buffer)
   9577                                (lsp--virtual-buffer virtual-buffer)
   9578                                (lsp--buffer-workspaces workspaces))
   9579                          (save-excursion
   9580                            (funcall goto-buffer)
   9581                            (funcall f))))))
   9582               ((&plist :begin :end :post-blank :language) (cl-second (org-element-context)))
   9583               ((&alist :tangle file-name) (cl-third (org-babel-get-src-block-info 'light)))
   9584 
   9585               (file-name (if file-name
   9586                              (f-expand file-name)
   9587                            (user-error "You should specify file name in the src block header.")))
   9588               (begin-marker (progn
   9589                               (goto-char begin)
   9590                               (forward-line)
   9591                               (set-marker (make-marker) (point))))
   9592               (end-marker (progn
   9593                             (goto-char end)
   9594                             (forward-line (1- (- post-blank)))
   9595                             (set-marker (make-marker) (1+ (point)))))
   9596               (buf (current-buffer))
   9597               (src-block (buffer-substring-no-properties begin-marker
   9598                                                          (1- end-marker)))
   9599               (indentation (with-temp-buffer
   9600                              (insert src-block)
   9601 
   9602                              (goto-char (point-min))
   9603                              (let ((indentation (current-indentation)))
   9604                                (plist-put lsp--virtual-buffer :indentation indentation)
   9605                                (org-do-remove-indentation)
   9606                                (goto-char (point-min))
   9607                                (- indentation (current-indentation))))))
   9608         (add-hook 'post-command-hook #'lsp--virtual-buffer-update-position nil t)
   9609 
   9610         (when (fboundp 'flycheck-add-mode)
   9611           (lsp-flycheck-add-mode 'org-mode))
   9612 
   9613         (setq lsp--virtual-buffer
   9614               (list
   9615                :in-range (lambda (&optional point)
   9616                            (<= begin-marker (or point (point)) (1- end-marker)))
   9617                :goto-buffer (lambda () (goto-char begin-marker))
   9618                :buffer-string
   9619                (lambda ()
   9620                  (let ((src-block (buffer-substring-no-properties
   9621                                    begin-marker
   9622                                    (1- end-marker))))
   9623                    (with-temp-buffer
   9624                      (insert src-block)
   9625 
   9626                      (goto-char (point-min))
   9627                      (while (not (eobp))
   9628                        (delete-region (point) (if (> (+ (point) indentation) (line-end-position))
   9629                                                   (line-end-position)
   9630                                                 (+ (point) indentation)))
   9631                        (forward-line))
   9632                      (buffer-substring-no-properties (point-min)
   9633                                                      (point-max)))))
   9634                :buffer buf
   9635                :begin begin-marker
   9636                :end end-marker
   9637                :indentation indentation
   9638                :last-point (lambda () (1- end-marker))
   9639                :cur-position (lambda ()
   9640                                (lsp-save-restriction-and-excursion
   9641                                  (list :line (- (lsp--cur-line)
   9642                                                 (lsp--cur-line begin-marker))
   9643                                        :character (let ((character (- (point)
   9644                                                                       (line-beginning-position)
   9645                                                                       indentation)))
   9646                                                     (if (< character 0)
   9647                                                         0
   9648                                                       character)))))
   9649                :line/character->point (-lambda (line character)
   9650                                         (-let [inhibit-field-text-motion t]
   9651                                           (+ indentation
   9652                                              (lsp-save-restriction-and-excursion
   9653                                                (goto-char begin-marker)
   9654                                                (forward-line line)
   9655                                                (-let [line-end (line-end-position)]
   9656                                                  (if (> character (- line-end (point)))
   9657                                                      line-end
   9658                                                    (forward-char character)
   9659                                                    (point)))))))
   9660                :major-mode (org-src-get-lang-mode language)
   9661                :buffer-file-name file-name
   9662                :buffer-uri (lsp--path-to-uri file-name)
   9663                :with-current-buffer wcb
   9664                :buffer-live? (lambda (_) (buffer-live-p buf))
   9665                :buffer-name (lambda (_)
   9666                               (propertize (format "%s(%s:%s)%s"
   9667                                                   (buffer-name buf)
   9668                                                   begin-marker
   9669                                                   end-marker
   9670                                                   language)
   9671                                           'face 'italic))
   9672                :real->virtual-line (lambda (line)
   9673                                      (+ line (line-number-at-pos begin-marker) -1))
   9674                :real->virtual-char (lambda (char) (+ char indentation))
   9675                :cleanup (lambda ()
   9676                           (set-marker begin-marker nil)
   9677                           (set-marker end-marker nil))))
   9678         (setf virtual-buffer lsp--virtual-buffer)
   9679         (puthash file-name virtual-buffer lsp--virtual-buffer-mappings)
   9680         (push virtual-buffer lsp--virtual-buffer-connections)
   9681 
   9682         ;; TODO: tangle only connected sections
   9683         (add-hook 'after-save-hook 'org-babel-tangle nil t)
   9684         (add-hook 'lsp-after-open-hook #'lsp-patch-on-change-event nil t)
   9685         (add-hook 'kill-buffer-hook #'lsp-kill-virtual-buffers nil t)
   9686 
   9687         (setq lsp--buffer-workspaces
   9688               (lsp-with-current-buffer virtual-buffer
   9689                 (lsp)
   9690                 (plist-put virtual-buffer :workspaces (lsp-workspaces))
   9691                 (lsp-workspaces)))))))
   9692 
   9693 (defun lsp-virtual-buffer-disconnect (virtual-buffer)
   9694   (interactive (list (or
   9695                       lsp--virtual-buffer
   9696                       (when lsp--virtual-buffer-connections
   9697                         (lsp--completing-read "Select virtual buffer to disconnect: "
   9698                                               lsp--virtual-buffer-connections
   9699                                               (-lambda ((&plist :buffer-file-name))
   9700                                                 buffer-file-name))))))
   9701   (-if-let ((&plist :buffer-file-name file-name :cleanup) virtual-buffer)
   9702       (progn
   9703         (lsp-with-current-buffer virtual-buffer
   9704           (lsp--text-document-did-close))
   9705         (setq lsp--virtual-buffer-connections (-remove-item virtual-buffer lsp--virtual-buffer-connections))
   9706         (when (eq virtual-buffer lsp--virtual-buffer)
   9707           (setf lsp--virtual-buffer nil))
   9708         (when cleanup (funcall cleanup))
   9709         (remhash file-name lsp--virtual-buffer-mappings)
   9710 
   9711         (lsp--virtual-buffer-update-position)
   9712         (lsp--info "Disconnected from buffer %s" file-name))
   9713     (lsp--error "Nothing to disconnect from?")))
   9714 
   9715 
   9716 ;; inlay hints
   9717 
   9718 (defface lsp-inlay-hint-face
   9719   '((t :inherit font-lock-comment-face))
   9720   "The face to use for the JavaScript inlays."
   9721   :group 'lsp-mode
   9722   :package-version '(lsp-mode . "9.0.0"))
   9723 
   9724 (defface lsp-inlay-hint-type-face
   9725   '((t :inherit lsp-inlay-hint-face))
   9726   "Face for inlay type hints (e.g. inferred variable types)."
   9727   :group 'lsp-mode
   9728   :package-version '(lsp-mode . "9.0.0"))
   9729 
   9730 (defcustom lsp-inlay-hint-type-format "%s"
   9731   "Format string for variable inlays (part of the inlay face)."
   9732   :type '(string :tag "String")
   9733   :group 'lsp-mode
   9734   :package-version '(lsp-mode . "9.0.0"))
   9735 
   9736 (defface lsp-inlay-hint-parameter-face
   9737   '((t :inherit lsp-inlay-hint-face))
   9738   "Face for inlay parameter hints (e.g. function parameter names at
   9739 call-site)."
   9740   :group 'lsp-mode
   9741   :package-version '(lsp-mode . "9.0.0"))
   9742 
   9743 (defcustom lsp-inlay-hint-param-format "%s"
   9744   "Format string for parameter inlays (part of the inlay face)."
   9745   :type '(string :tag "String")
   9746   :group 'lsp-mode
   9747   :package-version '(lsp-mode . "9.0.0"))
   9748 
   9749 (defcustom lsp-update-inlay-hints-on-scroll t
   9750   "If non-nil update inlay hints immediately when scrolling or
   9751 modifying window sizes."
   9752   :type 'boolean
   9753   :package-version '(lsp-mode . "9.0.0"))
   9754 
   9755 (defun lsp--format-inlay (text kind)
   9756   (cond
   9757    ((eql kind lsp/inlay-hint-kind-type-hint) (format lsp-inlay-hint-type-format text))
   9758    ((eql kind lsp/inlay-hint-kind-parameter-hint) (format lsp-inlay-hint-param-format text))
   9759    (t text)))
   9760 
   9761 (defun lsp--face-for-inlay (kind)
   9762   (cond
   9763    ((eql kind lsp/inlay-hint-kind-type-hint) 'lsp-inlay-hint-type-face)
   9764    ((eql kind lsp/inlay-hint-kind-parameter-hint) 'lsp-inlay-hint-parameter-face)
   9765    (t 'lsp-inlay-hint-face)))
   9766 
   9767 (defun lsp--update-inlay-hints-scroll-function (window start)
   9768   (lsp-update-inlay-hints start (window-end window t)))
   9769 
   9770 (defun lsp--update-inlay-hints ()
   9771   (lsp-update-inlay-hints (window-start) (window-end nil t)))
   9772 
   9773 (defun lsp--label-from-inlay-hints-response (label)
   9774   "Returns a string label built from an array of
   9775 InlayHintLabelParts or the argument itself if it's already a
   9776 string."
   9777   (cl-typecase label
   9778     (string label)
   9779     (vector
   9780      (string-join (mapcar (lambda (part)
   9781                             (-let (((&InlayHintLabelPart :value) part))
   9782                               value))
   9783                           label)))))
   9784 
   9785 (defun lsp-update-inlay-hints (start end)
   9786   (lsp-request-async
   9787    "textDocument/inlayHint"
   9788    (lsp-make-inlay-hints-params
   9789     :text-document (lsp--text-document-identifier)
   9790     :range (lsp-make-range :start
   9791                            (lsp-point-to-position start)
   9792                            :end
   9793                            (lsp-point-to-position end)))
   9794    (lambda (res)
   9795      (lsp--remove-overlays 'lsp-inlay-hint)
   9796      (dolist (hint res)
   9797        (-let* (((&InlayHint :label :position :kind? :padding-left? :padding-right?) hint)
   9798                (kind (or kind? lsp/inlay-hint-kind-type-hint))
   9799                (label (lsp--label-from-inlay-hints-response label))
   9800                (pos (lsp--position-to-point position))
   9801                (overlay (make-overlay pos pos nil 'front-advance 'end-advance)))
   9802          (when (stringp label)
   9803            (overlay-put overlay 'lsp-inlay-hint t)
   9804            (overlay-put overlay 'before-string
   9805                         (format "%s%s%s"
   9806                                 (if padding-left? " " "")
   9807                                 (propertize (lsp--format-inlay label kind)
   9808                                             'font-lock-face (lsp--face-for-inlay kind))
   9809                                 (if padding-right? " " "")))))))
   9810    :mode 'tick))
   9811 
   9812 (define-minor-mode lsp-inlay-hints-mode
   9813   "Mode for displaying inlay hints."
   9814   :lighter nil
   9815   (cond
   9816    ((and lsp-inlay-hints-mode lsp--buffer-workspaces)
   9817     (add-hook 'lsp-on-idle-hook #'lsp--update-inlay-hints nil t)
   9818     (when lsp-update-inlay-hints-on-scroll
   9819       (add-to-list (make-local-variable 'window-scroll-functions)
   9820                    #'lsp--update-inlay-hints-scroll-function)))
   9821    (t
   9822     (lsp--remove-overlays 'lsp-inlay-hint)
   9823     (remove-hook 'lsp-on-idle-hook #'lsp--update-inlay-hints t)
   9824     (setf window-scroll-functions
   9825           (delete #'lsp--update-inlay-hints-scroll-function window-scroll-functions)))))
   9826 
   9827 
   9828 
   9829 ;;;###autoload
   9830 (defun lsp-start-plain ()
   9831   "Start `lsp-mode' using minimal configuration using the latest `melpa' version
   9832 of the packages.
   9833 
   9834 In case the major-mode that you are using for "
   9835   (interactive)
   9836   (let ((start-plain (make-temp-file "plain" nil ".el")))
   9837     (url-copy-file "https://raw.githubusercontent.com/emacs-lsp/lsp-mode/master/scripts/lsp-start-plain.el"
   9838                    start-plain t)
   9839     (async-shell-command
   9840      (format "%s -q -l %s %s"
   9841              (expand-file-name invocation-name invocation-directory)
   9842              start-plain
   9843              (or (buffer-file-name) ""))
   9844      (generate-new-buffer " *lsp-start-plain*"))))
   9845 
   9846 
   9847 
   9848 (provide 'lsp-mode)
   9849 ;;; lsp-mode.el ends here