config

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

lsp-mode.el (438020B)


      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 ;; Package-Version: 20241202.334
      9 ;; Package-Revision: c3be413f8545
     10 
     11 ;; URL: https://github.com/emacs-lsp/lsp-mode
     12 ;; This program is free software; you can redistribute it and/or modify
     13 ;; it under the terms of the GNU General Public License as published by
     14 ;; the Free Software Foundation, either version 3 of the License, or
     15 ;; (at your option) any later version.
     16 
     17 ;; This program is distributed in the hope that it will be useful,
     18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     20 ;; GNU General Public License for more details.
     21 
     22 ;; You should have received a copy of the GNU General Public License
     23 ;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
     24 
     25 ;;; Commentary:
     26 
     27 ;; Emacs client/library for the Language Server Protocol
     28 
     29 ;;; Code:
     30 
     31 (require 'cl-generic)
     32 (require 'cl-lib)
     33 (require 'compile)
     34 (require 'dash)
     35 (require 'epg)
     36 (require 'ewoc)
     37 (require 'f)
     38 (require 'filenotify)
     39 (require 'files)
     40 (require 'ht)
     41 (require 'imenu)
     42 (require 'inline)
     43 (require 'json)
     44 (require 'lv)
     45 (require 'markdown-mode)
     46 (require 'network-stream)
     47 (require 'pcase)
     48 (require 'rx)
     49 (require 's)
     50 (require 'seq)
     51 (require 'spinner)
     52 (require 'subr-x)
     53 (require 'tree-widget)
     54 (require 'url-parse)
     55 (require 'url-util)
     56 (require 'widget)
     57 (require 'xref)
     58 (require 'minibuffer)
     59 (require 'help-mode)
     60 (require 'lsp-protocol)
     61 
     62 (defgroup lsp-mode nil
     63   "Language Server Protocol client."
     64   :group 'tools
     65   :tag "Language Server (lsp-mode)")
     66 
     67 (declare-function evil-set-command-property "ext:evil-common")
     68 (declare-function projectile-project-root "ext:projectile")
     69 (declare-function yas-expand-snippet "ext:yasnippet")
     70 (declare-function dap-mode "ext:dap-mode")
     71 (declare-function dap-auto-configure-mode "ext:dap-mode")
     72 
     73 (defvar yas-inhibit-overlay-modification-protection)
     74 (defvar yas-indent-line)
     75 (defvar yas-wrap-around-region)
     76 (defvar yas-also-auto-indent-first-line)
     77 (defvar dap-auto-configure-mode)
     78 (defvar dap-ui-menu-items)
     79 (defvar company-minimum-prefix-length)
     80 
     81 (defconst lsp--message-type-face
     82   `((1 . ,compilation-error-face)
     83     (2 . ,compilation-warning-face)
     84     (3 . ,compilation-message-face)
     85     (4 . ,compilation-info-face)))
     86 
     87 (defconst lsp--errors
     88   '((-32700 "Parse Error")
     89     (-32600 "Invalid Request")
     90     (-32601 "Method not Found")
     91     (-32602 "Invalid Parameters")
     92     (-32603 "Internal Error")
     93     (-32099 "Server Start Error")
     94     (-32000 "Server End Error")
     95     (-32002 "Server Not Initialized")
     96     (-32001 "Unknown Error Code")
     97     (-32800 "Request Cancelled"))
     98   "Alist of error codes to user friendly strings.")
     99 
    100 (defconst lsp--empty-ht (make-hash-table))
    101 
    102 (eval-and-compile
    103   (defun dash-expand:&lsp-wks (key source)
    104     `(,(intern-soft (format "lsp--workspace-%s" (eval key))) ,source))
    105 
    106   (defun dash-expand:&lsp-cln (key source)
    107     `(,(intern-soft (format "lsp--client-%s" (eval key))) ,source)))
    108 
    109 (define-obsolete-variable-alias 'lsp-print-io 'lsp-log-io "lsp-mode 6.1")
    110 
    111 (defcustom lsp-log-io nil
    112   "If non-nil, log all messages from the language server to a *lsp-log* buffer."
    113   :group 'lsp-mode
    114   :type 'boolean)
    115 
    116 (defcustom lsp-log-io-allowlist-methods '()
    117   "The methods to filter before print to lsp-log-io."
    118   :group 'lsp-mode
    119   :type '(repeat string)
    120   :package-version '(lsp-mode . "9.0.0"))
    121 
    122 (defcustom lsp-log-max message-log-max
    123   "Maximum number of lines to keep in the log buffer.
    124 If nil, disable message logging.  If t, log messages but don’t truncate
    125 the buffer when it becomes large."
    126   :group 'lsp-mode
    127   :type '(choice (const :tag "Disable" nil)
    128                  (integer :tag "lines")
    129                  (const :tag "Unlimited" t))
    130   :package-version '(lsp-mode . "6.1"))
    131 
    132 (defcustom lsp-io-messages-max t
    133   "Maximum number of messages that can be locked in a `lsp-io' buffer."
    134   :group 'lsp-mode
    135   :type '(choice (const :tag "Unlimited" t)
    136                  (integer :tag "Messages"))
    137   :package-version '(lsp-mode . "6.1"))
    138 
    139 (defcustom lsp-keep-workspace-alive t
    140   "If non nil keep workspace alive when the last workspace buffer is closed."
    141   :group 'lsp-mode
    142   :type 'boolean)
    143 
    144 (defcustom lsp-enable-snippet t
    145   "Enable/disable snippet completion support."
    146   :group 'lsp-completion
    147   :type 'boolean)
    148 
    149 (defcustom lsp-enable-folding t
    150   "Enable/disable code folding support."
    151   :group 'lsp-mode
    152   :type 'boolean
    153   :package-version '(lsp-mode . "6.1"))
    154 
    155 (define-obsolete-variable-alias 'lsp-enable-semantic-highlighting 'lsp-semantic-tokens-enable "lsp-mode 8.0.0")
    156 
    157 (defcustom lsp-semantic-tokens-enable nil
    158   "Enable/disable support for semantic tokens.
    159 As defined by the Language Server Protocol 3.16."
    160   :group 'lsp-semantic-tokens
    161   :type 'boolean)
    162 
    163 (defcustom lsp-folding-range-limit nil
    164   "The maximum number of folding ranges to receive from the language server."
    165   :group 'lsp-mode
    166   :type '(choice (const :tag "No limit." nil)
    167                  (integer :tag "Number of lines."))
    168   :package-version '(lsp-mode . "6.1"))
    169 
    170 (defcustom lsp-folding-line-folding-only nil
    171   "If non-nil, only fold complete lines."
    172   :group 'lsp-mode
    173   :type 'boolean
    174   :package-version '(lsp-mode . "6.1"))
    175 
    176 (defcustom lsp-client-packages
    177   '( ccls lsp-actionscript lsp-ada lsp-angular lsp-ansible lsp-asm lsp-astro
    178      lsp-autotools lsp-awk lsp-bash lsp-beancount lsp-bufls lsp-clangd
    179      lsp-clojure lsp-cmake lsp-cobol lsp-credo lsp-crystal lsp-csharp lsp-css
    180      lsp-cucumber lsp-cypher lsp-d lsp-dart lsp-dhall lsp-docker lsp-dockerfile
    181      lsp-earthly lsp-elixir lsp-elm lsp-emmet lsp-erlang lsp-eslint lsp-fortran lsp-futhark
    182      lsp-fsharp lsp-gdscript lsp-gleam lsp-glsl lsp-go lsp-golangci-lint lsp-grammarly
    183      lsp-graphql lsp-groovy lsp-hack lsp-haskell lsp-haxe lsp-idris lsp-java
    184      lsp-javascript lsp-jq lsp-json lsp-kotlin lsp-latex lsp-lisp lsp-ltex
    185      lsp-lua lsp-fennel lsp-magik lsp-markdown lsp-marksman lsp-mdx lsp-meson lsp-metals lsp-mint
    186      lsp-mojo lsp-move lsp-mssql lsp-nextflow lsp-nginx lsp-nim lsp-nix lsp-nushell lsp-ocaml
    187      lsp-openscad lsp-pascal lsp-perl lsp-perlnavigator lsp-php lsp-pls
    188      lsp-purescript lsp-pwsh lsp-pyls lsp-pylsp lsp-pyright lsp-python-ms
    189      lsp-qml lsp-r lsp-racket lsp-remark lsp-rf lsp-roslyn lsp-rubocop lsp-ruby-lsp
    190      lsp-ruby-syntax-tree lsp-ruff lsp-rust lsp-semgrep lsp-shader
    191      lsp-solargraph lsp-solidity lsp-sonarlint lsp-sorbet lsp-sourcekit
    192      lsp-sql lsp-sqls lsp-steep lsp-svelte lsp-tailwindcss lsp-terraform
    193      lsp-tex lsp-tilt lsp-toml lsp-trunk lsp-ttcn3 lsp-typeprof lsp-typespec lsp-v
    194      lsp-vala lsp-verilog lsp-vetur lsp-vhdl lsp-vimscript lsp-volar lsp-wgsl
    195      lsp-xml lsp-yaml lsp-yang lsp-zig)
    196   "List of the clients to be automatically required."
    197   :group 'lsp-mode
    198   :type '(repeat symbol))
    199 
    200 (defcustom lsp-progress-via-spinner t
    201   "If non-nil, display LSP $/progress reports via a spinner in the modeline."
    202   :group 'lsp-mode
    203   :type 'boolean)
    204 
    205 (defcustom lsp-progress-spinner-type 'progress-bar
    206   "Holds the type of spinner to be used in the mode-line.
    207 Takes a value accepted by `spinner-start'."
    208   :group 'lsp-mode
    209   :type `(choice :tag "Choose a spinner by name"
    210                  ,@(mapcar (lambda (c) (list 'const (car c)))
    211                            spinner-types)))
    212 
    213 (defvar-local lsp-use-workspace-root-for-server-default-directory nil
    214   "Use `lsp-workspace-root' for `default-directory' when starting LSP process.")
    215 
    216 (defvar-local lsp--cur-workspace nil)
    217 
    218 (defvar-local lsp--cur-version 0)
    219 (defvar-local lsp--virtual-buffer-connections nil)
    220 (defvar-local lsp--virtual-buffer nil)
    221 (defvar lsp--virtual-buffer-mappings (ht))
    222 
    223 (defvar lsp--uri-file-prefix (pcase system-type
    224                                (`windows-nt "file:///")
    225                                (_ "file://"))
    226   "Prefix for a file-uri.")
    227 
    228 (defvar-local lsp-buffer-uri nil
    229   "If set, return it instead of calculating it using `buffer-file-name'.")
    230 
    231 (define-error 'lsp-error "Unknown lsp-mode error")
    232 (define-error 'lsp-empty-response-error
    233   "Empty response from the language server" 'lsp-error)
    234 (define-error 'lsp-timed-out-error
    235   "Timed out while waiting for a response from the language server" 'lsp-error)
    236 (define-error 'lsp-capability-not-supported
    237   "Capability not supported by the language server" 'lsp-error)
    238 (define-error 'lsp-file-scheme-not-supported
    239   "Unsupported file scheme" 'lsp-error)
    240 (define-error 'lsp-client-already-exists-error
    241   "A client with this server-id already exists" 'lsp-error)
    242 (define-error 'lsp-no-code-actions
    243   "No code actions" 'lsp-error)
    244 
    245 (defcustom lsp-auto-guess-root nil
    246   "Automatically guess the project root using projectile/project.
    247 Do *not* use this setting unless you are familiar with `lsp-mode'
    248 internals and you are sure that all of your projects are
    249 following `projectile'/`project.el' conventions."
    250   :group 'lsp-mode
    251   :type 'boolean)
    252 
    253 (defcustom lsp-guess-root-without-session nil
    254   "Ignore the session file when calculating the project root.
    255 You almost always want to set lsp-auto-guess-root too.
    256 Do *not* use this setting unless you are familiar with `lsp-mode'
    257 internals and you are sure that all of your projects are
    258 following `projectile'/`project.el' conventions."
    259   :group 'lsp-mode
    260   :type 'boolean)
    261 
    262 (defcustom lsp-restart 'interactive
    263   "Defines how server-exited events must be handled."
    264   :group 'lsp-mode
    265   :type '(choice (const interactive)
    266                  (const auto-restart)
    267                  (const ignore)))
    268 
    269 (defcustom lsp-session-file (expand-file-name (locate-user-emacs-file ".lsp-session-v1"))
    270   "File where session information is stored."
    271   :group 'lsp-mode
    272   :type 'file)
    273 
    274 (defcustom lsp-auto-configure t
    275   "Auto configure `lsp-mode' main features.
    276 When set to t `lsp-mode' will auto-configure completion,
    277 code-actions, breadcrumb, `flycheck', `flymake', `imenu', symbol highlighting,
    278 lenses, links, and so on.
    279 
    280 For finer granularity you may use `lsp-enable-*' properties."
    281   :group 'lsp-mode
    282   :type 'boolean
    283   :package-version '(lsp-mode . "6.1"))
    284 
    285 (defcustom lsp-disabled-clients nil
    286   "A list of disabled/blocklisted clients.
    287 Each entry in the list can be either:
    288 a symbol, the server-id for the LSP client, or
    289 a cons pair (MAJOR-MODE . CLIENTS), where MAJOR-MODE is the major-mode,
    290 and CLIENTS is either a client or a list of clients.
    291 
    292 This option can also be used as a file- or directory-local variable to
    293 disable a language server for individual files or directories/projects
    294 respectively."
    295   :group 'lsp-mode
    296   :type '(repeat (symbol))
    297   :safe 'listp
    298   :package-version '(lsp-mode . "6.1"))
    299 
    300 (defvar lsp-clients (make-hash-table :test 'eql)
    301   "Hash table server-id -> client.
    302 It contains all of the clients that are currently registered.")
    303 
    304 (defvar lsp-enabled-clients nil
    305   "List of clients allowed to be used for projects.
    306 When nil, all registered clients are considered candidates.")
    307 
    308 (defvar lsp-last-id 0
    309   "Last request id.")
    310 
    311 (defcustom lsp-before-initialize-hook nil
    312   "List of functions to be called before a Language Server has been initialized
    313 for a new workspace."
    314   :type 'hook
    315   :group 'lsp-mode)
    316 
    317 (defcustom lsp-after-initialize-hook nil
    318   "List of functions to be called after a Language Server has been initialized
    319 for a new workspace."
    320   :type 'hook
    321   :group 'lsp-mode)
    322 
    323 (defcustom lsp-before-open-hook nil
    324   "List of functions to be called before a new file with LSP support is opened."
    325   :type 'hook
    326   :group 'lsp-mode)
    327 
    328 (defcustom lsp-after-open-hook nil
    329   "List of functions to be called after a new file with LSP support is opened."
    330   :type 'hook
    331   :group 'lsp-mode)
    332 
    333 (defcustom lsp-enable-file-watchers t
    334   "If non-nil lsp-mode will watch the files in the workspace if
    335 the server has requested that."
    336   :type 'boolean
    337   :group 'lsp-mode
    338   :package-version '(lsp-mode . "6.1"))
    339 ;;;###autoload(put 'lsp-enable-file-watchers 'safe-local-variable #'booleanp)
    340 
    341 (define-obsolete-variable-alias 'lsp-file-watch-ignored 'lsp-file-watch-ignored-directories "8.0.0")
    342 
    343 (defcustom lsp-file-watch-ignored-directories
    344   '(; SCM tools
    345     "[/\\\\]\\.git\\'"
    346     "[/\\\\]\\.github\\'"
    347     "[/\\\\]\\.gitlab\\'"
    348     "[/\\\\]\\.circleci\\'"
    349     "[/\\\\]\\.hg\\'"
    350     "[/\\\\]\\.bzr\\'"
    351     "[/\\\\]_darcs\\'"
    352     "[/\\\\]\\.svn\\'"
    353     "[/\\\\]_FOSSIL_\\'"
    354     ;; IDE or build tools
    355     "[/\\\\]\\.idea\\'"
    356     "[/\\\\]\\.ensime_cache\\'"
    357     "[/\\\\]\\.eunit\\'"
    358     "[/\\\\]node_modules"
    359     "[/\\\\]\\.yarn\\'"
    360     "[/\\\\]\\.fslckout\\'"
    361     "[/\\\\]\\.tox\\'"
    362     "[/\\\\]\\.nox\\'"
    363     "[/\\\\]dist\\'"
    364     "[/\\\\]dist-newstyle\\'"
    365     "[/\\\\]\\.stack-work\\'"
    366     "[/\\\\]\\.bloop\\'"
    367     "[/\\\\]\\.metals\\'"
    368     "[/\\\\]target\\'"
    369     "[/\\\\]\\.ccls-cache\\'"
    370     "[/\\\\]\\.vs\\'"
    371     "[/\\\\]\\.vscode\\'"
    372     "[/\\\\]\\.venv\\'"
    373     "[/\\\\]\\.mypy_cache\\'"
    374     "[/\\\\]\\.pytest_cache\\'"
    375     ;; Swift Package Manager
    376     "[/\\\\]\\.build\\'"
    377     ;; Python
    378     "[/\\\\]__pycache__\\'"
    379     "[/\\\\]site-packages\\'"
    380     "[/\\\\].pyenv\\'"
    381     ;; Autotools output
    382     "[/\\\\]\\.deps\\'"
    383     "[/\\\\]build-aux\\'"
    384     "[/\\\\]autom4te.cache\\'"
    385     "[/\\\\]\\.reference\\'"
    386     ;; Bazel
    387     "[/\\\\]bazel-[^/\\\\]+\\'"
    388     ;; CSharp
    389     "[/\\\\]\\.cache[/\\\\]lsp-csharp\\'"
    390     "[/\\\\]\\.meta\\'"
    391     "[/\\\\]\\.nuget\\'"
    392     ;; Unity
    393     "[/\\\\]Library\\'"
    394     ;; Clojure
    395     "[/\\\\]\\.lsp\\'"
    396     "[/\\\\]\\.clj-kondo\\'"
    397     "[/\\\\]\\.shadow-cljs\\'"
    398     "[/\\\\]\\.babel_cache\\'"
    399     "[/\\\\]\\.cpcache\\'"
    400     "[/\\\\]\\checkouts\\'"
    401     ;; Gradle
    402     "[/\\\\]\\.gradle\\'"
    403     ;; Maven
    404     "[/\\\\]\\.m2\\'"
    405     ;; .Net Core build-output
    406     "[/\\\\]bin/Debug\\'"
    407     "[/\\\\]obj\\'"
    408     ;; OCaml and Dune
    409     "[/\\\\]_opam\\'"
    410     "[/\\\\]_build\\'"
    411     ;; Elixir
    412     "[/\\\\]\\.elixir_ls\\'"
    413     ;; Elixir Credo
    414     "[/\\\\]\\.elixir-tools\\'"
    415     ;; terraform and terragrunt
    416     "[/\\\\]\\.terraform\\'"
    417     "[/\\\\]\\.terragrunt-cache\\'"
    418     ;; nix-direnv
    419     "[/\\\\]\\result"
    420     "[/\\\\]\\result-bin"
    421     "[/\\\\]\\.direnv\\'")
    422   "List of regexps matching directory paths which won't be monitored when
    423 creating file watches. Customization of this variable is only honored at
    424 the global level or at a root of an lsp workspace."
    425   :group 'lsp-mode
    426   :type '(repeat string)
    427   :package-version '(lsp-mode . "8.0.0"))
    428 
    429 (define-obsolete-function-alias 'lsp-file-watch-ignored 'lsp-file-watch-ignored-directories "7.0.1")
    430 
    431 (defun lsp-file-watch-ignored-directories ()
    432   lsp-file-watch-ignored-directories)
    433 
    434 ;; Allow lsp-file-watch-ignored-directories as a file or directory-local variable
    435 ;;;###autoload(put 'lsp-file-watch-ignored-directories 'safe-local-variable 'lsp--string-listp)
    436 
    437 (defcustom lsp-file-watch-ignored-files
    438   '(
    439     ;; Flycheck tempfiles
    440     "[/\\\\]flycheck_[^/\\\\]+\\'"
    441     ;; lockfiles
    442     "[/\\\\]\\.#[^/\\\\]+\\'"
    443     ;; backup files
    444     "[/\\\\][^/\\\\]+~\\'" )
    445   "List of regexps matching files for which change events will
    446 not be sent to the server.
    447 
    448 This setting has no impact on whether a file-watch is created for
    449 a directory; it merely prevents notifications pertaining to
    450 matched files from being sent to the server.  To prevent a
    451 file-watch from being created for a directory, customize
    452 `lsp-file-watch-ignored-directories'
    453 
    454 Customization of this variable is only honored at the global
    455 level or at a root of an lsp workspace."
    456   :group 'lsp-mode
    457   :type '(repeat string)
    458   :package-version '(lsp-mode . "8.0.0"))
    459 
    460 ;; Allow lsp-file-watch-ignored-files as a file or directory-local variable
    461 ;;;###autoload(put 'lsp-file-watch-ignored-files 'safe-local-variable 'lsp--string-listp)
    462 
    463 (defcustom lsp-after-uninitialized-functions nil
    464   "List of functions to be called after a Language Server has been uninitialized."
    465   :type 'hook
    466   :group 'lsp-mode
    467   :package-version '(lsp-mode . "6.3"))
    468 
    469 (defconst lsp--sync-full 1)
    470 (defconst lsp--sync-incremental 2)
    471 
    472 (defcustom lsp-debounce-full-sync-notifications t
    473   "If non-nil debounce full sync events.
    474 This flag affects only servers which do not support incremental updates."
    475   :type 'boolean
    476   :group 'lsp-mode
    477   :package-version '(lsp-mode . "6.1"))
    478 
    479 (defcustom lsp-debounce-full-sync-notifications-interval 1.0
    480   "Time to wait before sending full sync synchronization after buffer modification."
    481   :type 'float
    482   :group 'lsp-mode
    483   :package-version '(lsp-mode . "6.1"))
    484 
    485 (defvar lsp--stderr-index 0)
    486 
    487 (defvar lsp--delayed-requests nil)
    488 (defvar lsp--delay-timer nil)
    489 
    490 (defcustom lsp-document-sync-method nil
    491   "How to sync the document with the language server."
    492   :type '(choice (const :tag "Documents are synced by always sending the full content of the document." lsp--sync-full)
    493                  (const :tag "Documents are synced by always sending incremental changes to the document." lsp--sync-incremental)
    494                  (const :tag "Use the method recommended by the language server." nil))
    495   :group 'lsp-mode)
    496 
    497 (defcustom lsp-auto-execute-action t
    498   "Auto-execute single action."
    499   :type 'boolean
    500   :group 'lsp-mode)
    501 
    502 (defcustom lsp-enable-links t
    503   "If non-nil, all references to links in a file will be made clickable, if
    504 supported by the language server."
    505   :type 'boolean
    506   :group 'lsp-mode
    507   :package-version '(lsp-mode . "6.1"))
    508 
    509 (defcustom lsp-enable-imenu t
    510   "If non-nil, automatically enable `imenu' integration when server provides
    511 `textDocument/documentSymbol'."
    512   :type 'boolean
    513   :group 'lsp-mode
    514   :package-version '(lsp-mode . "6.2"))
    515 
    516 (defcustom lsp-enable-dap-auto-configure t
    517   "If non-nil, enable `dap-auto-configure-mode`."
    518   :type 'boolean
    519   :group 'lsp-mode
    520   :package-version '(lsp-mode . "7.0"))
    521 
    522 (defcustom lsp-eldoc-enable-hover t
    523   "If non-nil, `eldoc' will display hover info when it is present."
    524   :type 'boolean
    525   :group 'lsp-mode)
    526 
    527 (defcustom lsp-eldoc-render-all nil
    528   "Display all of the info returned by textDocument/hover.
    529 If this is set to nil, `eldoc' will show only the symbol information."
    530   :type 'boolean
    531   :group 'lsp-mode)
    532 
    533 (defcustom lsp-enable-symbol-highlighting t
    534   "Highlight references of the symbol at point."
    535   :type 'boolean
    536   :group 'lsp-mode)
    537 
    538 (defcustom lsp-enable-xref t
    539   "Enable xref integration."
    540   :type 'boolean
    541   :group 'lsp-mode)
    542 
    543 (define-obsolete-variable-alias
    544   'lsp-references-exclude-definition
    545   'lsp-references-exclude-declaration
    546   "9.0.1")
    547 
    548 (defcustom lsp-references-exclude-declaration 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     ("\\.fnl$" . "fennel")
    787     ("\\.mdx\\'" . "mdx")
    788     ("\\.nu$" . "nushell")
    789     ("\\.php$" . "php")
    790     ("\\.ps[dm]?1\\'" . "powershell")
    791     ("\\.rs\\'" . "rust")
    792     ("\\.spec\\'" . "rpm-spec")
    793     ("\\.sql$" . "sql")
    794     ("\\.svelte$" . "svelte")
    795     ("\\.toml\\'" . "toml")
    796     ("\\.ts$" . "typescript")
    797     ("\\.tsp$" . "typespec")
    798     ("\\.tsx$" . "typescriptreact")
    799     ("\\.ttcn3$" . "ttcn3")
    800     ("\\.vue$" . "vue")
    801     ("\\.xml$" . "xml")
    802     ("\\ya?ml$" . "yaml")
    803     ("^PKGBUILD$" . "shellscript")
    804     ("^go\\.mod\\'" . "go.mod")
    805     ("^settings\\.json$" . "jsonc")
    806     ("^yang\\.settings$" . "jsonc")
    807     ("^meson\\(_options\\.txt\\|\\.\\(build\\|format\\)\\)\\'" . "meson")
    808     (ada-mode . "ada")
    809     (ada-ts-mode . "ada")
    810     (gpr-mode . "gpr")
    811     (gpr-ts-mode . "gpr")
    812     (awk-mode . "awk")
    813     (awk-ts-mode . "awk")
    814     (nxml-mode . "xml")
    815     (sql-mode . "sql")
    816     (vimrc-mode . "vim")
    817     (vimscript-ts-mode . "vim")
    818     (sh-mode . "shellscript")
    819     (bash-ts-mode . "shellscript")
    820     (ebuild-mode . "shellscript")
    821     (pkgbuild-mode . "shellscript")
    822     (envrc-file-mode . "shellscript")
    823     (scala-mode . "scala")
    824     (scala-ts-mode . "scala")
    825     (julia-mode . "julia")
    826     (julia-ts-mode . "julia")
    827     (clojure-mode . "clojure")
    828     (clojurec-mode . "clojure")
    829     (clojurescript-mode . "clojurescript")
    830     (clojure-ts-mode . "clojure")
    831     (clojure-ts-clojurec-mode . "clojure")
    832     (clojure-ts-clojurescript-mode . "clojurescript")
    833     (java-mode . "java")
    834     (java-ts-mode . "java")
    835     (jdee-mode . "java")
    836     (groovy-mode . "groovy")
    837     (nextflow-mode . "nextflow")
    838     (python-mode . "python")
    839     (python-ts-mode . "python")
    840     (cython-mode . "python")
    841     ("\\(\\.mojo\\|\\.🔥\\)\\'" . "mojo")
    842     (lsp--render-markdown . "markdown")
    843     (move-mode . "move")
    844     (rust-mode . "rust")
    845     (rust-ts-mode . "rust")
    846     (rustic-mode . "rust")
    847     (kotlin-mode . "kotlin")
    848     (kotlin-ts-mode . "kotlin")
    849     (css-mode . "css")
    850     (css-ts-mode . "css")
    851     (less-mode . "less")
    852     (less-css-mode . "less")
    853     (lua-mode . "lua")
    854     (lua-ts-mode . "lua")
    855     (sass-mode . "sass")
    856     (ssass-mode . "sass")
    857     (scss-mode . "scss")
    858     (scad-mode . "openscad")
    859     (xml-mode . "xml")
    860     (c-mode . "c")
    861     (c-ts-mode . "c")
    862     (c++-mode . "cpp")
    863     (c++-ts-mode . "cpp")
    864     (cuda-mode . "cuda")
    865     (objc-mode . "objective-c")
    866     (html-mode . "html")
    867     (html-ts-mode . "html")
    868     (sgml-mode . "html")
    869     (mhtml-mode . "html")
    870     (mint-mode . "mint")
    871     (go-dot-mod-mode . "go.mod")
    872     (go-mod-ts-mode . "go.mod")
    873     (go-mode . "go")
    874     (go-ts-mode . "go")
    875     (graphql-mode . "graphql")
    876     (haskell-mode . "haskell")
    877     (haskell-ts-mode . "haskell")
    878     (hack-mode . "hack")
    879     (php-mode . "php")
    880     (php-ts-mode . "php")
    881     (powershell-mode . "powershell")
    882     (powershell-mode . "PowerShell")
    883     (powershell-ts-mode . "powershell")
    884     (json-mode . "json")
    885     (json-ts-mode . "json")
    886     (jsonc-mode . "jsonc")
    887     (rjsx-mode . "javascript")
    888     (js2-mode . "javascript")
    889     (js-mode . "javascript")
    890     (js-ts-mode . "javascript")
    891     (typescript-mode . "typescript")
    892     (typescript-ts-mode . "typescript")
    893     (typespec-mode . "typespec")
    894     (tsx-ts-mode . "typescriptreact")
    895     (svelte-mode . "svelte")
    896     (fsharp-mode . "fsharp")
    897     (reason-mode . "reason")
    898     (caml-mode . "ocaml")
    899     (tuareg-mode . "ocaml")
    900     (futhark-mode . "futhark")
    901     (swift-mode . "swift")
    902     (elixir-mode . "elixir")
    903     (elixir-ts-mode . "elixir")
    904     (heex-ts-mode . "elixir")
    905     (conf-javaprop-mode . "spring-boot-properties")
    906     (yaml-mode . "yaml")
    907     (yaml-ts-mode . "yaml")
    908     (ruby-mode . "ruby")
    909     (enh-ruby-mode . "ruby")
    910     (ruby-ts-mode . "ruby")
    911     (feature-mode . "cucumber")
    912     (fortran-mode . "fortran")
    913     (f90-mode . "fortran")
    914     (elm-mode . "elm")
    915     (dart-mode . "dart")
    916     (erlang-mode . "erlang")
    917     (dockerfile-mode . "dockerfile")
    918     (dockerfile-ts-mode . "dockerfile")
    919     (csharp-mode . "csharp")
    920     (csharp-tree-sitter-mode . "csharp")
    921     (csharp-ts-mode . "csharp")
    922     (plain-tex-mode . "plaintex")
    923     (context-mode . "context")
    924     (cypher-mode . "cypher")
    925     (latex-mode . "latex")
    926     (LaTeX-mode . "latex")
    927     (v-mode . "v")
    928     (vhdl-mode . "vhdl")
    929     (vhdl-ts-mode . "vhdl")
    930     (verilog-mode . "verilog")
    931     (terraform-mode . "terraform")
    932     (ess-julia-mode . "julia")
    933     (ess-r-mode . "r")
    934     (crystal-mode . "crystal")
    935     (nim-mode . "nim")
    936     (dhall-mode . "dhall")
    937     (cmake-mode . "cmake")
    938     (cmake-ts-mode . "cmake")
    939     (purescript-mode . "purescript")
    940     (gdscript-mode . "gdscript")
    941     (gdscript-ts-mode . "gdscript")
    942     (perl-mode . "perl")
    943     (cperl-mode . "perl")
    944     (robot-mode . "robot")
    945     (racket-mode . "racket")
    946     (nix-mode . "nix")
    947     (nix-ts-mode . "nix")
    948     (prolog-mode . "prolog")
    949     (vala-mode . "vala")
    950     (actionscript-mode . "actionscript")
    951     (d-mode . "d")
    952     (zig-mode . "zig")
    953     (zig-ts-mode . "zig")
    954     (text-mode . "plaintext")
    955     (markdown-mode . "markdown")
    956     (gfm-mode . "markdown")
    957     (beancount-mode . "beancount")
    958     (conf-toml-mode . "toml")
    959     (toml-ts-mode . "toml")
    960     (org-mode . "org")
    961     (org-journal-mode . "org")
    962     (nginx-mode . "nginx")
    963     (magik-mode . "magik")
    964     (magik-ts-mode . "magik")
    965     (idris-mode . "idris")
    966     (idris2-mode . "idris2")
    967     (gleam-mode . "gleam")
    968     (gleam-ts-mode . "gleam")
    969     (graphviz-dot-mode . "dot")
    970     (tiltfile-mode . "tiltfile")
    971     (solidity-mode . "solidity")
    972     (bibtex-mode . "bibtex")
    973     (rst-mode . "restructuredtext")
    974     (glsl-mode . "glsl")
    975     (shader-mode . "shaderlab")
    976     (wgsl-mode . "wgsl")
    977     (jq-mode . "jq")
    978     (jq-ts-mode . "jq")
    979     (protobuf-mode . "protobuf")
    980     (nushell-mode . "nushell")
    981     (nushell-ts-mode . "nushell")
    982     (meson-mode . "meson")
    983     (yang-mode . "yang"))
    984   "Language id configuration.")
    985 
    986 (defvar lsp--last-active-workspaces nil
    987   "Keep track of last active workspace.
    988 We want to try the last workspace first when jumping into a library
    989 directory")
    990 
    991 (defvar lsp-method-requirements
    992   '(("textDocument/callHierarchy" :capability :callHierarchyProvider)
    993     ("textDocument/codeAction" :capability :codeActionProvider)
    994     ("codeAction/resolve"
    995      :check-command (lambda (workspace)
    996                       (with-lsp-workspace workspace
    997                         (lsp:code-action-options-resolve-provider?
    998                          (lsp--capability-for-method "textDocument/codeAction")))))
    999     ("textDocument/codeLens" :capability :codeLensProvider)
   1000     ("textDocument/completion" :capability :completionProvider)
   1001     ("completionItem/resolve"
   1002      :check-command (lambda (wk)
   1003                       (with-lsp-workspace wk
   1004                         (lsp:completion-options-resolve-provider?
   1005                          (lsp--capability-for-method "textDocument/completion")))))
   1006     ("textDocument/inlineCompletion" :capability :inlineCompletionProvider)
   1007     ("textDocument/declaration" :capability :declarationProvider)
   1008     ("textDocument/definition" :capability :definitionProvider)
   1009     ("textDocument/documentColor" :capability :colorProvider)
   1010     ("textDocument/documentLink" :capability :documentLinkProvider)
   1011     ("textDocument/inlayHint" :capability :inlayHintProvider)
   1012     ("textDocument/documentHighlight" :capability :documentHighlightProvider)
   1013     ("textDocument/documentSymbol" :capability :documentSymbolProvider)
   1014     ("textDocument/foldingRange" :capability :foldingRangeProvider)
   1015     ("textDocument/formatting" :capability :documentFormattingProvider)
   1016     ("textDocument/hover" :capability :hoverProvider)
   1017     ("textDocument/implementation" :capability :implementationProvider)
   1018     ("textDocument/linkedEditingRange" :capability :linkedEditingRangeProvider)
   1019     ("textDocument/onTypeFormatting" :capability :documentOnTypeFormattingProvider)
   1020     ("textDocument/prepareRename"
   1021      :check-command (lambda (workspace)
   1022                       (with-lsp-workspace workspace
   1023                         (lsp:rename-options-prepare-provider?
   1024                          (lsp--capability-for-method "textDocument/rename")))))
   1025     ("textDocument/rangeFormatting" :capability :documentRangeFormattingProvider)
   1026     ("textDocument/references" :capability :referencesProvider)
   1027     ("textDocument/rename" :capability :renameProvider)
   1028     ("textDocument/selectionRange" :capability :selectionRangeProvider)
   1029     ("textDocument/semanticTokens" :capability :semanticTokensProvider)
   1030     ("textDocument/semanticTokensFull"
   1031      :check-command (lambda (workspace)
   1032                       (with-lsp-workspace workspace
   1033                         (lsp-get (lsp--capability :semanticTokensProvider) :full))))
   1034     ("textDocument/semanticTokensFull/Delta"
   1035      :check-command (lambda (workspace)
   1036                       (with-lsp-workspace workspace
   1037                         (let ((capFull (lsp-get (lsp--capability :semanticTokensProvider) :full)))
   1038                           (and (not (booleanp capFull)) (lsp-get capFull :delta))))))
   1039     ("textDocument/semanticTokensRangeProvider"
   1040      :check-command (lambda (workspace)
   1041                       (with-lsp-workspace workspace
   1042                         (lsp-get (lsp--capability :semanticTokensProvider) :range))))
   1043     ("textDocument/signatureHelp" :capability :signatureHelpProvider)
   1044     ("textDocument/typeDefinition" :capability :typeDefinitionProvider)
   1045     ("textDocument/typeHierarchy" :capability :typeHierarchyProvider)
   1046     ("textDocument/diagnostic" :capability :diagnosticProvider)
   1047     ("workspace/executeCommand" :capability :executeCommandProvider)
   1048     ("workspace/symbol" :capability :workspaceSymbolProvider))
   1049 
   1050   "Map methods to requirements.
   1051 It is used by request-sending functions to determine which server
   1052 must be used for handling a particular message.")
   1053 
   1054 (defconst lsp--file-change-type
   1055   `((created . 1)
   1056     (changed . 2)
   1057     (deleted . 3)))
   1058 
   1059 (defconst lsp--watch-kind
   1060   `((create . 1)
   1061     (change . 2)
   1062     (delete . 4)))
   1063 
   1064 (defvar lsp-window-body-width 40
   1065   "Window body width when rendering doc.")
   1066 
   1067 (defface lsp-face-highlight-textual
   1068   '((t :inherit highlight))
   1069   "Face used for textual occurrences of symbols."
   1070   :group 'lsp-mode)
   1071 
   1072 (defface lsp-face-highlight-read
   1073   '((t :inherit highlight :underline t))
   1074   "Face used for highlighting symbols being read."
   1075   :group 'lsp-mode)
   1076 
   1077 (defface lsp-face-highlight-write
   1078   '((t :inherit highlight :weight bold))
   1079   "Face used for highlighting symbols being written to."
   1080   :group 'lsp-mode)
   1081 
   1082 (define-obsolete-variable-alias 'lsp-lens-auto-enable
   1083   'lsp-lens-enable "lsp-mode 7.0.1")
   1084 
   1085 (defcustom lsp-lens-enable t
   1086   "Auto enable lenses if server supports."
   1087   :group 'lsp-lens
   1088   :type 'boolean
   1089   :package-version '(lsp-mode . "6.3"))
   1090 
   1091 (defcustom lsp-symbol-highlighting-skip-current nil
   1092   "If non-nil skip current symbol when setting symbol highlights."
   1093   :group 'lsp-mode
   1094   :type 'boolean)
   1095 
   1096 (defcustom lsp-file-watch-threshold 1000
   1097   "Show warning if the files to watch are more than.
   1098 Set to nil to disable the warning."
   1099   :type 'number
   1100   :group 'lsp-mode)
   1101 ;;;###autoload(put 'lsp-file-watch-threshold 'safe-local-variable (lambda (i) (or (numberp i) (not i))))
   1102 
   1103 (defvar lsp-custom-markup-modes
   1104   '((rust-mode "no_run" "rust,no_run" "rust,ignore" "rust,should_panic"))
   1105   "Mode to uses with markdown code blocks.
   1106 They are added to `markdown-code-lang-modes'")
   1107 
   1108 (defcustom lsp-signature-render-documentation t
   1109   "Display signature documentation in `eldoc'."
   1110   :type 'boolean
   1111   :group 'lsp-mode
   1112   :package-version '(lsp-mode . "6.2"))
   1113 
   1114 (defcustom lsp-signature-auto-activate '(:on-trigger-char :on-server-request)
   1115   "Auto activate signature conditions."
   1116   :type '(repeat (choice (const :tag "On trigger chars pressed." :on-trigger-char)
   1117                          (const :tag "After selected completion." :after-completion)
   1118                          (const :tag "When the server has sent show signature help." :on-server-request)))
   1119   :group 'lsp-mode
   1120   :package-version '(lsp-mode . "6.2"))
   1121 
   1122 (defcustom lsp-signature-doc-lines 20
   1123   "If number, limit the number of lines to show in the docs."
   1124   :type 'number
   1125   :group 'lsp-mode
   1126   :package-version '(lsp-mode . "6.3"))
   1127 
   1128 (defcustom lsp-signature-function 'lsp-lv-message
   1129   "The function used for displaying signature info.
   1130 It will be called with one param - the signature info. When
   1131 called with nil the signature info must be cleared."
   1132   :type 'function
   1133   :group 'lsp-mode
   1134   :package-version '(lsp-mode . "6.3"))
   1135 
   1136 (defcustom lsp-keymap-prefix "s-l"
   1137   "LSP-mode keymap prefix."
   1138   :group 'lsp-mode
   1139   :type 'string
   1140   :package-version '(lsp-mode . "6.3"))
   1141 
   1142 (defvar-local lsp--buffer-workspaces ()
   1143   "List of the buffer workspaces.")
   1144 
   1145 (defvar-local lsp--buffer-deferred nil
   1146   "Whether buffer was loaded via `lsp-deferred'.")
   1147 
   1148 (defvar lsp--session nil
   1149   "Contain the `lsp-session' for the current Emacs instance.")
   1150 
   1151 (defvar lsp--tcp-port 10000)
   1152 
   1153 (defvar lsp--client-packages-required nil
   1154   "If nil, `lsp-client-packages' are yet to be required.")
   1155 
   1156 (defvar lsp--tcp-server-port 0
   1157   "The server socket which is opened when using `lsp-tcp-server' (a server
   1158 socket is opened in Emacs and the language server connects to it).  The
   1159 default value of 0 ensures that a random high port is used. Set it to a positive
   1160 integer to use a specific port.")
   1161 
   1162 (defvar lsp--tcp-server-wait-seconds 10
   1163   "Wait this amount of time for the client to connect to our server socket
   1164 when using `lsp-tcp-server'.")
   1165 
   1166 (defvar-local lsp--document-symbols nil
   1167   "The latest document symbols.")
   1168 
   1169 (defvar-local lsp--document-selection-range-cache nil
   1170   "The document selection cache.")
   1171 
   1172 (defvar-local lsp--document-symbols-request-async nil
   1173   "If non-nil, request document symbols asynchronously.")
   1174 
   1175 (defvar-local lsp--document-symbols-tick -1
   1176   "The value of `buffer-chars-modified-tick' when document
   1177   symbols were last retrieved.")
   1178 
   1179 (defvar-local lsp--have-document-highlights nil
   1180   "Set to `t' on symbol highlighting, cleared on
   1181 `lsp--cleanup-highlights-if-needed'. Checking a separately
   1182 defined flag is substantially faster than unconditionally
   1183 calling `remove-overlays'.")
   1184 
   1185 ;; Buffer local variable for storing number of lines.
   1186 (defvar lsp--log-lines)
   1187 
   1188 (defvar-local lsp--eldoc-saved-message nil)
   1189 
   1190 (defvar lsp--on-change-timer nil)
   1191 (defvar lsp--on-idle-timer nil)
   1192 
   1193 (defvar-local lsp--signature-last nil)
   1194 (defvar-local lsp--signature-last-index nil)
   1195 (defvar lsp--signature-last-buffer nil)
   1196 
   1197 (defvar-local lsp--virtual-buffer-point-max nil)
   1198 
   1199 (cl-defmethod lsp-execute-command (_server _command _arguments)
   1200   "Ask SERVER to execute COMMAND with ARGUMENTS.")
   1201 
   1202 (defun lsp-elt (sequence n)
   1203   "Return Nth element of SEQUENCE or nil if N is out of range."
   1204   (cond
   1205    ((listp sequence) (elt sequence n))
   1206    ((arrayp sequence)
   1207     (and (> (length sequence) n) (aref sequence n)))
   1208    (t (and (> (length sequence) n) (elt sequence n)))))
   1209 
   1210 ;; define seq-first and seq-rest for older emacs
   1211 (defun lsp-seq-first (sequence)
   1212   "Return the first element of SEQUENCE."
   1213   (lsp-elt sequence 0))
   1214 
   1215 (defun lsp-seq-rest (sequence)
   1216   "Return a sequence of the elements of SEQUENCE except the first one."
   1217   (seq-drop sequence 1))
   1218 
   1219 ;;;###autoload
   1220 (defun lsp--string-listp (sequence)
   1221   "Return t if all elements of SEQUENCE are strings, else nil."
   1222   (not (seq-find (lambda (x) (not (stringp x))) sequence)))
   1223 
   1224 (defun lsp--string-vector-p (candidate)
   1225   "Returns true if CANDIDATE is a vector data structure and
   1226 every element of it is of type string, else nil."
   1227   (and
   1228    (vectorp candidate)
   1229    (seq-every-p #'stringp candidate)))
   1230 
   1231 (make-obsolete 'lsp--string-vector-p nil "lsp-mode 8.0.0")
   1232 
   1233 (defun lsp--editable-vector-match (widget value)
   1234   "Function for `lsp-editable-vector' :match."
   1235   ;; Value must be a list or a vector and all the members must match the type.
   1236   (and (or (listp value) (vectorp value))
   1237        (length (cdr (lsp--editable-vector-match-inline widget value)))))
   1238 
   1239 (defun lsp--editable-vector-match-inline (widget value)
   1240   "Value for `lsp-editable-vector' :match-inline."
   1241   (let ((type (nth 0 (widget-get widget :args)))
   1242         (ok t)
   1243         found)
   1244     (while (and value ok)
   1245       (let ((answer (widget-match-inline type value)))
   1246         (if answer
   1247             (let ((head (if (vectorp answer) (aref answer 0) (car answer)))
   1248                   (tail (if (vectorp answer) (seq-drop 1 answer) (cdr answer))))
   1249               (setq found (append found head)
   1250                     value tail))
   1251           (setq ok nil))))
   1252     (cons found value)))
   1253 
   1254 (defun lsp--editable-vector-value-to-external (_widget internal-value)
   1255   "Convert the internal list value to a vector."
   1256   (if (listp internal-value)
   1257       (apply 'vector internal-value)
   1258     internal-value))
   1259 
   1260 (defun lsp--editable-vector-value-to-internal (_widget external-value)
   1261   "Convert the external vector value to a list."
   1262   (if (vectorp external-value)
   1263       (append external-value nil)
   1264     external-value))
   1265 
   1266 (define-widget 'lsp--editable-vector 'editable-list
   1267   "A subclass of `editable-list' that accepts and returns a
   1268 vector instead of a list."
   1269   :value-to-external 'lsp--editable-vector-value-to-external
   1270   :value-to-internal 'lsp--editable-vector-value-to-internal
   1271   :match 'lsp--editable-vector-match
   1272   :match-inline 'lsp--editable-vector-match-inline)
   1273 
   1274 (define-widget 'lsp-repeatable-vector 'lsp--editable-vector
   1275   "A variable length homogeneous vector."
   1276   :tag "Repeat"
   1277   :format "%{%t%}:\n%v%i\n")
   1278 
   1279 (define-widget 'lsp-string-vector 'lazy
   1280   "A vector of zero or more elements, every element of which is a string.
   1281 Appropriate for any language-specific `defcustom' that needs to
   1282 serialize as a JSON array of strings.
   1283 
   1284 Deprecated. Use `lsp-repeatable-vector' instead. "
   1285   :offset 4
   1286   :tag "Vector"
   1287   :type '(lsp-repeatable-vector string))
   1288 
   1289 (make-obsolete 'lsp-string-vector nil "lsp-mode 8.0.0")
   1290 
   1291 (defvar lsp--show-message t
   1292   "If non-nil, show debug message from `lsp-mode'.")
   1293 
   1294 (defun lsp--message  (format &rest args)
   1295   "Wrapper for `message'
   1296 
   1297 We `inhibit-message' the message when the cursor is in the
   1298 minibuffer and when emacs version is before emacs 27 due to the
   1299 fact that we often use `lsp--info', `lsp--warn' and `lsp--error'
   1300 in async context and the call to these function is removing the
   1301 minibuffer prompt. The issue with async messages is already fixed
   1302 in emacs 27.
   1303 
   1304 See #2049"
   1305   (when lsp--show-message
   1306     (let ((inhibit-message (or inhibit-message
   1307                                (and (minibufferp)
   1308                                     (version< emacs-version "27.0")))))
   1309       (apply #'message format args))))
   1310 
   1311 (defun lsp--info (format &rest args)
   1312   "Display lsp info message with FORMAT with ARGS."
   1313   (lsp--message "%s :: %s" (propertize "LSP" 'face 'success) (apply #'format format args)))
   1314 
   1315 (defun lsp--warn (format &rest args)
   1316   "Display lsp warn message with FORMAT with ARGS."
   1317   (lsp--message "%s :: %s" (propertize "LSP" 'face 'warning) (apply #'format format args)))
   1318 
   1319 (defun lsp--error (format &rest args)
   1320   "Display lsp error message with FORMAT with ARGS."
   1321   (lsp--message "%s :: %s" (propertize "LSP" 'face 'error) (apply #'format format args)))
   1322 
   1323 (defun lsp-log (format &rest args)
   1324   "Log message to the ’*lsp-log*’ buffer.
   1325 
   1326 FORMAT and ARGS i the same as for `message'."
   1327   (when lsp-log-max
   1328     (let ((log-buffer (get-buffer "*lsp-log*"))
   1329           (inhibit-read-only t))
   1330       (unless log-buffer
   1331         (setq log-buffer (get-buffer-create "*lsp-log*"))
   1332         (with-current-buffer log-buffer
   1333           (buffer-disable-undo)
   1334           (view-mode 1)
   1335           (set (make-local-variable 'lsp--log-lines) 0)))
   1336       (with-current-buffer log-buffer
   1337         (save-excursion
   1338           (let* ((message (apply 'format format args))
   1339                  ;; Count newlines in message.
   1340                  (newlines (1+ (cl-loop with start = 0
   1341                                         for count from 0
   1342                                         while (string-match "\n" message start)
   1343                                         do (setq start (match-end 0))
   1344                                         finally return count))))
   1345             (goto-char (point-max))
   1346 
   1347             ;; in case the buffer is not empty insert before last \n to preserve
   1348             ;; the point position(in case it is in the end)
   1349             (if (eq (point) (point-min))
   1350                 (progn
   1351                   (insert "\n")
   1352                   (backward-char))
   1353               (backward-char)
   1354               (insert "\n"))
   1355             (insert message)
   1356 
   1357             (setq lsp--log-lines (+ lsp--log-lines newlines))
   1358 
   1359             (when (and (integerp lsp-log-max) (> lsp--log-lines lsp-log-max))
   1360               (let ((to-delete (- lsp--log-lines lsp-log-max)))
   1361                 (goto-char (point-min))
   1362                 (forward-line to-delete)
   1363                 (delete-region (point-min) (point))
   1364                 (setq lsp--log-lines lsp-log-max)))))))))
   1365 
   1366 (defalias 'lsp-message 'lsp-log)
   1367 
   1368 (defalias 'lsp-ht 'ht)
   1369 
   1370 (defalias 'lsp-file-local-name 'file-local-name)
   1371 
   1372 (defun lsp-f-canonical (file-name)
   1373   "Return the canonical FILE-NAME, without a trailing slash."
   1374   (directory-file-name (expand-file-name file-name)))
   1375 
   1376 (defalias 'lsp-canonical-file-name 'lsp-f-canonical)
   1377 
   1378 (defun lsp-f-same? (path-a path-b)
   1379   "Return t if PATH-A and PATH-B are references to the same file.
   1380 Symlinks are not followed."
   1381   (when (and (f-exists? path-a)
   1382              (f-exists? path-b))
   1383     (equal
   1384      (lsp-f-canonical (directory-file-name (f-expand path-a)))
   1385      (lsp-f-canonical (directory-file-name (f-expand path-b))))))
   1386 
   1387 (defun lsp-f-parent (path)
   1388   "Return the parent directory to PATH.
   1389 Symlinks are not followed."
   1390   (let ((parent (file-name-directory
   1391                  (directory-file-name (f-expand path default-directory)))))
   1392     (unless (lsp-f-same? path parent)
   1393       (if (f-relative? path)
   1394           (f-relative parent)
   1395         (directory-file-name parent)))))
   1396 
   1397 (defun lsp-f-ancestor-of? (path-a path-b)
   1398   "Return t if PATH-A is an ancestor of PATH-B.
   1399 Symlinks are not followed."
   1400   (unless (lsp-f-same? path-a path-b)
   1401     (s-prefix? (concat (lsp-f-canonical path-a) (f-path-separator))
   1402                (lsp-f-canonical path-b))))
   1403 
   1404 ;; compat
   1405 (if (version< emacs-version "29.1")
   1406     ;; Undo macro probably introduced in 29.1
   1407     (defmacro lsp-with-undo-amalgamate (&rest body)
   1408       "Like `progn' but perform BODY with amalgamated undo barriers.
   1409 
   1410 This allows multiple operations to be undone in a single step.
   1411 When undo is disabled this behaves like `progn'."
   1412       (declare (indent 0) (debug t))
   1413       (let ((handle (make-symbol "--change-group-handle--")))
   1414         `(let ((,handle (prepare-change-group))
   1415                ;; Don't truncate any undo data in the middle of this,
   1416                ;; otherwise Emacs might truncate part of the resulting
   1417                ;; undo step: we want to mimic the behavior we'd get if the
   1418                ;; undo-boundaries were never added in the first place.
   1419                (undo-outer-limit nil)
   1420                (undo-limit most-positive-fixnum)
   1421                (undo-strong-limit most-positive-fixnum))
   1422            (unwind-protect
   1423                (progn
   1424                  (activate-change-group ,handle)
   1425                  ,@body)
   1426              (progn
   1427                (accept-change-group ,handle)
   1428                (undo-amalgamate-change-group ,handle))))))
   1429   (defalias 'lsp-with-undo-amalgamate 'with-undo-amalgamate))
   1430 
   1431 (defun lsp--merge-results (results method)
   1432   "Merge RESULTS by filtering the empty hash-tables and merging
   1433 the lists according to METHOD."
   1434   (pcase (--map (if (vectorp it)
   1435                     (append it nil) it)
   1436                 (-filter #'identity results))
   1437     (`() ())
   1438     ;; only one result - simply return it
   1439     (`(,fst) fst)
   1440     ;; multiple results merge it based on strategy
   1441     (results
   1442      (pcase method
   1443        ("textDocument/hover" (pcase (seq-filter
   1444                                      (-compose #'not #'lsp-empty?)
   1445                                      results)
   1446                                (`(,hover) hover)
   1447                                (hovers (lsp-make-hover
   1448                                         :contents
   1449                                         (-mapcat
   1450                                          (-lambda ((&Hover :contents))
   1451                                            (if (and (sequencep contents)
   1452                                                     (not (stringp contents)))
   1453                                                (append contents ())
   1454                                              (list contents)))
   1455                                          hovers)))))
   1456        ("textDocument/completion"
   1457         (lsp-make-completion-list
   1458          :is-incomplete (seq-some
   1459                          #'lsp:completion-list-is-incomplete
   1460                          results)
   1461          :items (cl-mapcan (lambda (it) (append (if (lsp-completion-list? it)
   1462                                                     (lsp:completion-list-items it)
   1463                                                   it)
   1464                                                 nil))
   1465                            results)))
   1466        ("completionItem/resolve"
   1467         (let ((item (cl-first results)))
   1468           (when-let* ((details (seq-filter #'identity
   1469                                           (seq-map #'lsp:completion-item-detail? results))))
   1470             (lsp:set-completion-item-detail?
   1471              item
   1472              (string-join details " ")))
   1473           (when-let* ((docs (seq-filter #'identity
   1474                                        (seq-map #'lsp:completion-item-documentation? results))))
   1475             (lsp:set-completion-item-documentation?
   1476              item
   1477              (lsp-make-markup-content
   1478               :kind (or (seq-some (lambda (it)
   1479                                     (when (equal (lsp:markup-content-kind it)
   1480                                                  lsp/markup-kind-markdown)
   1481                                       lsp/markup-kind-markdown))
   1482                                   docs)
   1483                         lsp/markup-kind-plain-text)
   1484               :value (string-join (seq-map (lambda (doc)
   1485                                              (or (lsp:markup-content-value doc)
   1486                                                  (and (stringp doc) doc)))
   1487                                            docs)
   1488                                   "\n"))))
   1489           (when-let* ((edits (seq-filter #'identity
   1490                                         (seq-map #'lsp:completion-item-additional-text-edits? results))))
   1491             (lsp:set-completion-item-additional-text-edits?
   1492              item
   1493              (cl-mapcan (lambda (it) (if (seqp it) it (list it))) edits)))
   1494           item))
   1495        (_ (cl-mapcan (lambda (it) (if (seqp it) it (list it))) results))))))
   1496 
   1497 (defun lsp--spinner-start ()
   1498   "Start spinner indication."
   1499   (condition-case _err (spinner-start (lsp-progress-spinner-type)) (error)))
   1500 
   1501 (defun lsp--propertize (str type)
   1502   "Propertize STR as per TYPE."
   1503   (propertize str 'face (alist-get type lsp--message-type-face)))
   1504 
   1505 (defun lsp-workspaces ()
   1506   "Return the lsp workspaces associated with the current project."
   1507   (if lsp--cur-workspace (list lsp--cur-workspace) lsp--buffer-workspaces))
   1508 
   1509 (defun lsp--completing-read (prompt collection transform-fn &optional predicate
   1510                                     require-match initial-input
   1511                                     hist def inherit-input-method)
   1512   "Wrap `completing-read' to provide transformation function and disable sort.
   1513 
   1514 TRANSFORM-FN will be used to transform each of the items before displaying.
   1515 
   1516 PROMPT COLLECTION PREDICATE REQUIRE-MATCH INITIAL-INPUT HIST DEF
   1517 INHERIT-INPUT-METHOD will be proxied to `completing-read' without changes."
   1518   (let* ((col (--map (cons (funcall transform-fn it) it) collection))
   1519          (completion (completing-read prompt
   1520                                       (lambda (string pred action)
   1521                                         (if (eq action 'metadata)
   1522                                             `(metadata (display-sort-function . identity))
   1523                                           (complete-with-action action col string pred)))
   1524                                       predicate require-match initial-input hist
   1525                                       def inherit-input-method)))
   1526     (cdr (assoc completion col))))
   1527 
   1528 (defconst lsp--system-arch (lambda ()
   1529                              (setq lsp--system-arch
   1530                                    (pcase system-type
   1531                                      ('windows-nt
   1532                                       (pcase system-configuration
   1533                                         ((rx bol "x86_64-") 'x64)
   1534                                         (_ 'x86)))
   1535                                      ('darwin
   1536                                       (pcase system-configuration
   1537                                         ((rx "aarch64-") 'arm64)
   1538                                         (_ 'x64)))
   1539                                      ('gnu/linux
   1540                                        (pcase system-configuration
   1541                                          ((rx bol "aarch64-") 'arm64)
   1542                                          ((rx bol "x86_64") 'x64)
   1543                                          ((rx bol (| "i386" "i886")) 'x32)))
   1544                                      (_
   1545                                       (pcase system-configuration
   1546                                         ((rx bol "x86_64") 'x64)
   1547                                         ((rx bol (| "i386" "i886")) 'x32))))))
   1548   "Return the system architecture of `Emacs'.
   1549 Special values:
   1550   `x64'       64bit
   1551   `x32'       32bit
   1552   `arm64'     ARM 64bit")
   1553 
   1554 (defmacro lsp-with-current-buffer (buffer-id &rest body)
   1555   (declare (indent 1) (debug t))
   1556   `(if-let* ((wcb (plist-get ,buffer-id :with-current-buffer)))
   1557        (with-lsp-workspaces (plist-get ,buffer-id :workspaces)
   1558          (funcall wcb (lambda () ,@body)))
   1559      (with-current-buffer ,buffer-id
   1560        ,@body)))
   1561 
   1562 (defvar lsp--throw-on-input nil
   1563   "Make `lsp-*-while-no-input' throws `input' on interrupted.")
   1564 
   1565 (defmacro lsp--catch (tag bodyform &rest handlers)
   1566   "Catch TAG thrown in BODYFORM.
   1567 The return value from TAG will be handled in HANDLERS by `pcase'."
   1568   (declare (debug (form form &rest (pcase-PAT body))) (indent 2))
   1569   (let ((re-sym (make-symbol "re")))
   1570     `(let ((,re-sym (catch ,tag ,bodyform)))
   1571        (pcase ,re-sym
   1572          ,@handlers))))
   1573 
   1574 (defmacro lsp--while-no-input (&rest body)
   1575   "Wrap BODY in `while-no-input' and respecting `non-essential'.
   1576 If `lsp--throw-on-input' is set, will throw if input is pending, else
   1577 return value of `body' or nil if interrupted."
   1578   (declare (debug t) (indent 0))
   1579   `(if non-essential
   1580        (let ((res (while-no-input ,@body)))
   1581          (cond
   1582           ((and lsp--throw-on-input (equal res t))
   1583            (throw 'input :interrupted))
   1584           ((booleanp res) nil)
   1585           (t res)))
   1586      ,@body))
   1587 
   1588 ;; A ‘lsp--client’ object describes the client-side behavior of a language
   1589 ;; server.  It is used to start individual server processes, each of which is
   1590 ;; represented by a ‘lsp--workspace’ object.  Client objects are normally
   1591 ;; created using ‘lsp-define-stdio-client’ or ‘lsp-define-tcp-client’.  Each
   1592 ;; workspace refers to exactly one client, but there can be multiple workspaces
   1593 ;; for a single client.
   1594 (cl-defstruct lsp--client
   1595   ;; ‘language-id’ is a function that receives a buffer as a single argument
   1596   ;; and should return the language identifier for that buffer.  See
   1597   ;; https://microsoft.github.io/language-server-protocol/specification#textdocumentitem
   1598   ;; for a list of language identifiers.  Also consult the documentation for
   1599   ;; the language server represented by this client to find out what language
   1600   ;; identifiers it supports or expects.
   1601   (language-id nil)
   1602 
   1603   ;; ‘add-on?’ when set to t the server will be started no matter whether there
   1604   ;; is another server handling the same mode.
   1605   (add-on? nil)
   1606   ;; ‘new-connection’ is a function that should start a language server process
   1607   ;; and return a cons (COMMAND-PROCESS . COMMUNICATION-PROCESS).
   1608   ;; COMMAND-PROCESS must be a process object representing the server process
   1609   ;; just started.  COMMUNICATION-PROCESS must be a process (including pipe and
   1610   ;; network processes) that ‘lsp-mode’ uses to communicate with the language
   1611   ;; server using the language server protocol.  COMMAND-PROCESS and
   1612   ;; COMMUNICATION-PROCESS may be the same process; in that case
   1613   ;; ‘new-connection’ may also return that process as a single
   1614   ;; object. ‘new-connection’ is called with two arguments, FILTER and
   1615   ;; SENTINEL.  FILTER should be used as process filter for
   1616   ;; COMMUNICATION-PROCESS, and SENTINEL should be used as process sentinel for
   1617   ;; COMMAND-PROCESS.
   1618   (new-connection nil)
   1619 
   1620   ;; ‘ignore-regexps’ is a list of regexps.  When a data packet from the
   1621   ;; language server matches any of these regexps, it will be ignored.  This is
   1622   ;; intended for dealing with language servers that output non-protocol data.
   1623   (ignore-regexps nil)
   1624 
   1625   ;; ‘ignore-messages’ is a list of regexps.  When a message from the language
   1626   ;; server matches any of these regexps, it will be ignored.  This is useful
   1627   ;; for filtering out unwanted messages; such as servers that send nonstandard
   1628   ;; message types, or extraneous log messages.
   1629   (ignore-messages nil)
   1630 
   1631   ;; ‘notification-handlers’ is a hash table mapping notification method names
   1632   ;; (strings) to functions handling the respective notifications.  Upon
   1633   ;; receiving a notification, ‘lsp-mode’ will call the associated handler
   1634   ;; function passing two arguments, the ‘lsp--workspace’ object and the
   1635   ;; deserialized notification parameters.
   1636   (notification-handlers (make-hash-table :test 'equal))
   1637 
   1638   ;; ‘request-handlers’ is a hash table mapping request method names
   1639   ;; (strings) to functions handling the respective notifications.  Upon
   1640   ;; receiving a request, ‘lsp-mode’ will call the associated handler function
   1641   ;; passing two arguments, the ‘lsp--workspace’ object and the deserialized
   1642   ;; request parameters.
   1643   (request-handlers (make-hash-table :test 'equal))
   1644 
   1645   ;; ‘response-handlers’ is a hash table mapping integral JSON-RPC request
   1646   ;; identifiers for pending asynchronous requests to functions handling the
   1647   ;; respective responses.  Upon receiving a response from the language server,
   1648   ;; ‘lsp-mode’ will call the associated response handler function with a
   1649   ;; single argument, the deserialized response parameters.
   1650   (response-handlers (make-hash-table :test 'eql))
   1651 
   1652   ;; ‘prefix-function’ is called for getting the prefix for completion.
   1653   ;; The function takes no parameter and returns a cons (start . end) representing
   1654   ;; the start and end bounds of the prefix. If it's not set, the client uses a
   1655   ;; default prefix function."
   1656   (prefix-function nil)
   1657 
   1658   ;; Contains mapping of scheme to the function that is going to be used to load
   1659   ;; the file.
   1660   (uri-handlers (make-hash-table :test #'equal))
   1661 
   1662   ;; ‘action-handlers’ is a hash table mapping action to a handler function. It
   1663   ;; can be used in `lsp-execute-code-action' to determine whether the action
   1664   ;; current client is interested in executing the action instead of sending it
   1665   ;; to the server.
   1666   (action-handlers (make-hash-table :test 'equal))
   1667 
   1668   ;; `action-filter' can be set to a function that modifies any incoming
   1669   ;; `CodeAction' in place before it is executed. The return value is ignored.
   1670   ;; This can be used to patch up broken code action requests before they are
   1671   ;; sent back to the LSP server. See `lsp-fix-code-action-booleans' for an
   1672   ;; example of a function that can be useful here.
   1673   (action-filter nil)
   1674 
   1675   ;; major modes supported by the client.
   1676   major-modes
   1677   ;; Function that will be called to decide if this language client
   1678   ;; should manage a particular buffer. The function will be passed
   1679   ;; the file name and major mode to inform the decision. Setting
   1680   ;; `activation-fn' will override `major-modes', if
   1681   ;; present.
   1682   activation-fn
   1683   ;; Break the tie when major-mode is supported by multiple clients.
   1684   (priority 0)
   1685   ;; Unique identifier for representing the client object.
   1686   server-id
   1687   ;; defines whether the client supports multi root workspaces.
   1688   multi-root
   1689   ;; Initialization options or a function that returns initialization options.
   1690   initialization-options
   1691   ;; `semantic-tokens-faces-overrides’ is a plist that can be used to extend, or
   1692   ;; completely replace, the faces used for semantic highlighting on a
   1693   ;; client-by-client basis.
   1694   ;;
   1695   ;; It recognizes four members, all of which are optional: `:types’ and
   1696   ;; `:modifiers’, respectively, should be face definition lists akin to
   1697   ;; `:lsp-semantic-token-faces’. If specified, each of these face lists will be
   1698   ;; merged with the default face definition list.
   1699   ;;
   1700   ;; Alternatively, if the plist members `:discard-default-types’ or
   1701   ;; `:discard-default-modifiers' are non-nil, the default `:type' or `:modifiers'
   1702   ;; face definitions will be replaced entirely by their respective overrides.
   1703   ;;
   1704   ;; For example, setting `:semantic-tokens-faces-overrides' to
   1705   ;; `(:types (("macro" . font-lock-keyword-face)))' will remap "macro" tokens from
   1706   ;; their default face `lsp-face-semhl-macro' to `font-lock-keyword-face'.
   1707   ;;
   1708   ;; `(:types (("macro" . font-lock-keyword-face) ("not-quite-a-macro" . some-face)))'
   1709   ;; will also remap "macro", but on top of that associate the fictional token type
   1710   ;; "not-quite-a-macro" with the face named `some-face'.
   1711   ;;
   1712   ;; `(:types (("macro" . font-lock-keyword-face))
   1713   ;;   :modifiers (("declaration" . lsp-face-semhl-interface))
   1714   ;;   :discard-default-types t
   1715   ;;   :discard-default-modifiers t)'
   1716   ;; will discard all default face definitions, hence leaving the client with
   1717   ;; only one token type "macro", mapped to `font-lock-keyword-face', and one
   1718   ;; modifier type "declaration", mapped to `lsp-face-semhl-interface'.
   1719   semantic-tokens-faces-overrides
   1720   ;; Provides support for registering LSP Server specific capabilities.
   1721   custom-capabilities
   1722   ;; Function which returns the folders that are considered to be not projects but library files.
   1723   ;; The function accepts one parameter currently active workspace.
   1724   ;; See: https://github.com/emacs-lsp/lsp-mode/issues/225.
   1725   library-folders-fn
   1726   ;; function which will be called when opening file in the workspace to perform
   1727   ;; client specific initialization. The function accepts one parameter
   1728   ;; currently active workspace.
   1729   before-file-open-fn
   1730   ;; Function which will be called right after a workspace has been initialized.
   1731   initialized-fn
   1732   ;; ‘remote?’ indicate whether the client can be used for LSP server over TRAMP.
   1733   (remote? nil)
   1734 
   1735   ;; ‘completion-in-comments?’ t if the client supports completion in comments.
   1736   (completion-in-comments? nil)
   1737 
   1738   ;; ‘path->uri-fn’ the function to use for path->uri conversion for the client.
   1739   (path->uri-fn nil)
   1740 
   1741   ;; ‘uri->path-fn’ the function to use for uri->path conversion for the client.
   1742   (uri->path-fn nil)
   1743   ;; Function that returns an environment structure that will be used
   1744   ;; to set some environment variables when starting the language
   1745   ;; server process. These environment variables enable some
   1746   ;; additional features in the language server. The environment
   1747   ;; structure is an alist of the form (KEY . VALUE), where KEY is a
   1748   ;; string (regularly in all caps), and VALUE may be a string, a
   1749   ;; boolean, or a sequence of strings.
   1750   environment-fn
   1751 
   1752   ;; ‘after-open-fn’ workspace after open specific hooks.
   1753   (after-open-fn nil)
   1754 
   1755   ;; ‘async-request-handlers’ is a hash table mapping request method names
   1756   ;; (strings) to functions handling the respective requests that may take
   1757   ;; time to finish.  Upon receiving a request, ‘lsp-mode’ will call the
   1758   ;; associated handler function passing three arguments, the ‘lsp--workspace’
   1759   ;; object, the deserialized request parameters and the callback which accept
   1760   ;; result as its parameter.
   1761   (async-request-handlers (make-hash-table :test 'equal))
   1762   download-server-fn
   1763   download-in-progress?
   1764   buffers
   1765   synchronize-sections)
   1766 
   1767 (defun lsp-clients-executable-find (find-command &rest args)
   1768   "Finds an executable by invoking a search command.
   1769 
   1770 FIND-COMMAND is the executable finder that searches for the
   1771 actual language server executable. ARGS is a list of arguments to
   1772 give to FIND-COMMAND to find the language server.  Returns the
   1773 output of FIND-COMMAND if it exits successfully, nil otherwise.
   1774 
   1775 Typical uses include finding an executable by invoking `find' in
   1776 a project, finding LLVM commands on macOS with `xcrun', or
   1777 looking up project-specific language servers for projects written
   1778 in the various dynamic languages, e.g. `nvm', `pyenv' and `rbenv'
   1779 etc."
   1780   (when-let* ((find-command-path (executable-find find-command))
   1781               (executable-path
   1782                (with-temp-buffer
   1783                  (when (zerop (apply 'call-process find-command-path nil t nil args))
   1784                    (buffer-substring-no-properties (point-min) (point-max))))))
   1785     (string-trim executable-path)))
   1786 
   1787 (defvar lsp--already-widened nil)
   1788 
   1789 (defmacro lsp-save-restriction-and-excursion (&rest form)
   1790   (declare (indent 0) (debug t))
   1791   `(if lsp--already-widened
   1792        (save-excursion ,@form)
   1793      (-let [lsp--already-widened t]
   1794        (save-restriction
   1795          (widen)
   1796          (save-excursion ,@form)))))
   1797 
   1798 ;; from http://emacs.stackexchange.com/questions/8082/how-to-get-buffer-position-given-line-number-and-column-number
   1799 (defun lsp--line-character-to-point (line character)
   1800   "Return the point for character CHARACTER on line LINE."
   1801   (or (lsp-virtual-buffer-call :line/character->point line character)
   1802       (let ((inhibit-field-text-motion t))
   1803         (lsp-save-restriction-and-excursion
   1804           (goto-char (point-min))
   1805           (forward-line line)
   1806           ;; server may send character position beyond the current line and we
   1807           ;; should fallback to line end.
   1808           (-let [line-end (line-end-position)]
   1809             (if (> character (- line-end (point)))
   1810                 line-end
   1811               (forward-char character)
   1812               (point)))))))
   1813 
   1814 (lsp-defun lsp--position-to-point ((&Position :line :character))
   1815   "Convert `Position' object in PARAMS to a point."
   1816   (lsp--line-character-to-point line character))
   1817 
   1818 (lsp-defun lsp--range-to-region ((&RangeToPoint :start :end))
   1819   (cons start end))
   1820 
   1821 (lsp-defun lsp--range-text ((&RangeToPoint :start :end))
   1822   (buffer-substring start end))
   1823 
   1824 (lsp-defun lsp--find-wrapping-range ((&SelectionRange :parent? :range (&RangeToPoint :start :end)))
   1825   (cond
   1826    ((and
   1827      (region-active-p)
   1828      (<= start (region-beginning) end)
   1829      (<= start (region-end) end)
   1830      (or (not (= start (region-beginning)))
   1831          (not (= end (region-end)))))
   1832     (cons start end))
   1833    ((and (<= start (point) end)
   1834          (not (region-active-p)))
   1835     (cons start end))
   1836    (parent? (lsp--find-wrapping-range parent?))))
   1837 
   1838 (defun lsp--get-selection-range ()
   1839   (or
   1840    (-when-let ((cache . cache-tick) lsp--document-selection-range-cache)
   1841      (when (= cache-tick (buffer-modified-tick)) cache))
   1842    (let ((response (cl-first
   1843                     (lsp-request
   1844                      "textDocument/selectionRange"
   1845                      (list :textDocument (lsp--text-document-identifier)
   1846                            :positions (vector (lsp--cur-position)))))))
   1847      (setq lsp--document-selection-range-cache
   1848            (cons response (buffer-modified-tick)))
   1849      response)))
   1850 
   1851 (defun lsp-extend-selection ()
   1852   "Extend selection."
   1853   (interactive)
   1854   (unless (lsp-feature? "textDocument/selectionRange")
   1855     (signal 'lsp-capability-not-supported (list "selectionRangeProvider")))
   1856   (-when-let ((start . end) (lsp--find-wrapping-range (lsp--get-selection-range)))
   1857     (goto-char start)
   1858     (set-mark (point))
   1859     (goto-char end)
   1860     (exchange-point-and-mark)))
   1861 
   1862 (defun lsp-warn (message &rest args)
   1863   "Display a warning message made from (`format-message' MESSAGE ARGS...).
   1864 This is equivalent to `display-warning', using `lsp-mode' as the type and
   1865 `:warning' as the level."
   1866   (display-warning 'lsp-mode (apply #'format-message message args)))
   1867 
   1868 (defun lsp--get-uri-handler (scheme)
   1869   "Get uri handler for SCHEME in the current workspace."
   1870   (--some (gethash scheme (lsp--client-uri-handlers (lsp--workspace-client it)))
   1871           (or (lsp-workspaces) (lsp--session-workspaces (lsp-session)))))
   1872 
   1873 (defun lsp--fix-path-casing (path)
   1874   "On windows, downcases path because the windows file system is
   1875 case-insensitive.
   1876 
   1877 On other systems, returns path without change."
   1878   (if (eq system-type 'windows-nt) (downcase path) path))
   1879 
   1880 (defun lsp--uri-to-path (uri)
   1881   "Convert URI to a file path."
   1882   (if-let* ((fn (->> (lsp-workspaces)
   1883                     (-keep (-compose #'lsp--client-uri->path-fn #'lsp--workspace-client))
   1884                     (cl-first))))
   1885       (funcall fn uri)
   1886     (lsp--uri-to-path-1 uri)))
   1887 
   1888 (defun lsp-remap-path-if-needed (file-name)
   1889   (-if-let ((virtual-buffer &as &plist :buffer) (gethash file-name lsp--virtual-buffer-mappings))
   1890       (propertize (buffer-local-value 'buffer-file-name buffer)
   1891                   'lsp-virtual-buffer virtual-buffer)
   1892     file-name))
   1893 
   1894 (defun lsp--uri-to-path-1 (uri)
   1895   "Convert URI to a file path."
   1896   (let* ((url (url-generic-parse-url (url-unhex-string uri)))
   1897          (type (url-type url))
   1898          (target (url-target url))
   1899          (file
   1900           (concat (decode-coding-string (url-filename url)
   1901                                         (or locale-coding-system 'utf-8))
   1902                   (when (and target
   1903                              (not (s-match
   1904                                    (rx "#" (group (1+ num)) (or "," "#")
   1905                                        (group (1+ num))
   1906                                        string-end)
   1907                                    uri)))
   1908                     (concat "#" target))))
   1909          (file-name (if (and type (not (string= type "file")))
   1910                         (if-let* ((handler (lsp--get-uri-handler type)))
   1911                             (funcall handler uri)
   1912                           uri)
   1913                       ;; `url-generic-parse-url' is buggy on windows:
   1914                       ;; https://github.com/emacs-lsp/lsp-mode/pull/265
   1915                       (or (and (eq system-type 'windows-nt)
   1916                                (eq (elt file 0) ?\/)
   1917                                (substring file 1))
   1918                           file))))
   1919     (->> file-name
   1920          (concat (-some #'lsp--workspace-host-root (lsp-workspaces)))
   1921          (lsp-remap-path-if-needed))))
   1922 
   1923 (defun lsp--buffer-uri ()
   1924   "Return URI of the current buffer."
   1925   (or lsp-buffer-uri
   1926       (plist-get lsp--virtual-buffer :buffer-uri)
   1927       (lsp--path-to-uri
   1928        (or (buffer-file-name) (buffer-file-name (buffer-base-buffer))))))
   1929 
   1930 (defun lsp-register-client-capabilities (&rest _args)
   1931   "Implemented only to make `company-lsp' happy.
   1932 DELETE when `lsp-mode.el' is deleted.")
   1933 
   1934 (defconst lsp--url-path-allowed-chars
   1935   (url--allowed-chars (append '(?/) url-unreserved-chars))
   1936   "`url-unreserved-chars' with additional delim ?/.
   1937 This set of allowed chars is enough for hexifying local file paths.")
   1938 
   1939 (defun lsp--path-to-uri-1 (path)
   1940   (concat lsp--uri-file-prefix
   1941           (--> path
   1942             (expand-file-name it)
   1943             (or (file-remote-p it 'localname t) it)
   1944             (url-hexify-string it lsp--url-path-allowed-chars))))
   1945 
   1946 (defun lsp--path-to-uri (path)
   1947   "Convert PATH to a uri."
   1948   (if-let* ((uri-fn (->> (lsp-workspaces)
   1949                         (-keep (-compose #'lsp--client-path->uri-fn #'lsp--workspace-client))
   1950                         (cl-first))))
   1951       (funcall uri-fn path)
   1952     (lsp--path-to-uri-1 path)))
   1953 
   1954 (defun lsp--string-match-any (regex-list str)
   1955   "Return the first regex, if any, within REGEX-LIST matching STR."
   1956   (--first (string-match it str) regex-list))
   1957 
   1958 (cl-defstruct lsp-watch
   1959   (descriptors (make-hash-table :test 'equal))
   1960   root-directory)
   1961 
   1962 (defun lsp--folder-watch-callback (event callback watch ignored-files ignored-directories)
   1963   (let ((file-name (cl-third event))
   1964         (event-type (cl-second event)))
   1965     (cond
   1966      ((and (file-directory-p file-name)
   1967            (equal 'created event-type)
   1968            (not (lsp--string-match-any ignored-directories file-name)))
   1969 
   1970       (lsp-watch-root-folder (file-truename file-name) callback ignored-files ignored-directories watch)
   1971 
   1972       ;; process the files that are already present in
   1973       ;; the directory.
   1974       (->> (directory-files-recursively file-name ".*" t)
   1975            (seq-do (lambda (f)
   1976                      (unless (file-directory-p f)
   1977                        (funcall callback (list nil 'created f)))))))
   1978      ((and (memq event-type '(created deleted changed))
   1979            (not (file-directory-p file-name))
   1980            (not (lsp--string-match-any ignored-files file-name)))
   1981       (funcall callback event))
   1982      ((and (memq event-type '(renamed))
   1983            (not (file-directory-p file-name))
   1984            (not (lsp--string-match-any ignored-files file-name)))
   1985       (funcall callback `(,(cl-first event) deleted ,(cl-third event)))
   1986       (funcall callback `(,(cl-first event) created ,(cl-fourth event)))))))
   1987 
   1988 (defun lsp--ask-about-watching-big-repo (number-of-directories dir)
   1989   "Ask the user if they want to watch NUMBER-OF-DIRECTORIES from a repository DIR.
   1990 This is useful when there is a lot of files in a repository, as
   1991 that may slow Emacs down. Returns t if the user wants to watch
   1992 the entire repository, nil otherwise."
   1993   (prog1
   1994       (yes-or-no-p
   1995        (format
   1996         "Watching all the files in %s would require adding watches to %s directories, so watching the repo may slow Emacs down.
   1997 Do you want to watch all files in %s? "
   1998         dir
   1999         number-of-directories
   2000         dir))
   2001     (lsp--info
   2002      (concat "You can configure this warning with the `lsp-enable-file-watchers' "
   2003              "and `lsp-file-watch-threshold' variables"))))
   2004 
   2005 
   2006 (defun lsp--path-is-watchable-directory (path dir ignored-directories)
   2007   "Figure out whether PATH (inside of DIR) is meant to have a file watcher set.
   2008 IGNORED-DIRECTORIES is a list of regexes to filter out directories we don't
   2009 want to watch."
   2010   (let
   2011       ((full-path (f-join dir path)))
   2012     (and (file-accessible-directory-p full-path)
   2013          (not (equal path "."))
   2014          (not (equal path ".."))
   2015          (not (lsp--string-match-any ignored-directories full-path)))))
   2016 
   2017 
   2018 (defun lsp--all-watchable-directories (dir ignored-directories &optional visited)
   2019   "Traverse DIR recursively returning a list of paths that should have watchers.
   2020 IGNORED-DIRECTORIES will be used for exclusions.
   2021 VISITED is used to track already-visited directories to avoid infinite loops."
   2022   (let* ((dir (if (f-symlink? dir)
   2023                   (file-truename dir)
   2024                 dir))
   2025          ;; Initialize visited directories if not provided
   2026          (visited (or visited (make-hash-table :test 'equal))))
   2027     (if (gethash dir visited)
   2028         ;; If the directory has already been visited, skip it
   2029         nil
   2030       ;; Mark the current directory as visited
   2031       (puthash dir t visited)
   2032       (apply #'nconc
   2033              ;; the directory itself is assumed to be part of the set
   2034              (list dir)
   2035              ;; collect all subdirectories that are watchable
   2036              (-map
   2037               (lambda (path) (lsp--all-watchable-directories (f-join dir path) ignored-directories visited))
   2038               ;; but only look at subdirectories that are watchable
   2039               (-filter (lambda (path) (lsp--path-is-watchable-directory path dir ignored-directories))
   2040                        (directory-files dir)))))))
   2041 
   2042 (defun lsp-watch-root-folder (dir callback ignored-files ignored-directories &optional watch warn-big-repo?)
   2043   "Create recursive file notification watch in DIR.
   2044 CALLBACK will be called when there are changes in any of
   2045 the monitored files. WATCHES is a hash table directory->file
   2046 notification handle which contains all of the watch that
   2047 already have been created. Watches will not be created for
   2048 any directory that matches any regex in IGNORED-DIRECTORIES.
   2049 Watches will not be created for any file that matches any
   2050 regex in IGNORED-FILES."
   2051   (let* ((dir (if (f-symlink? dir)
   2052                   (file-truename dir)
   2053                 dir))
   2054          (watch (or watch (make-lsp-watch :root-directory dir)))
   2055          (dirs-to-watch (lsp--all-watchable-directories dir ignored-directories)))
   2056     (lsp-log "Creating watchers for following %s folders:\n  %s"
   2057              (length dirs-to-watch)
   2058              (s-join "\n  " dirs-to-watch))
   2059     (when (or
   2060            (not warn-big-repo?)
   2061            (not lsp-file-watch-threshold)
   2062            (let ((number-of-directories (length dirs-to-watch)))
   2063              (or
   2064               (< number-of-directories lsp-file-watch-threshold)
   2065               (condition-case nil
   2066                   (lsp--ask-about-watching-big-repo number-of-directories dir)
   2067                 (quit)))))
   2068       (dolist (current-dir dirs-to-watch)
   2069         (condition-case err
   2070             (progn
   2071               (puthash
   2072                current-dir
   2073                (file-notify-add-watch current-dir
   2074                                       '(change)
   2075                                       (lambda (event)
   2076                                         (lsp--folder-watch-callback event callback watch ignored-files ignored-directories)))
   2077                (lsp-watch-descriptors watch)))
   2078           (error (lsp-log "Failed to create a watch for %s: message" (error-message-string err)))
   2079           (file-missing (lsp-log "Failed to create a watch for %s: message" (error-message-string err))))))
   2080     watch))
   2081 
   2082 (defun lsp-kill-watch (watch)
   2083   "Delete WATCH."
   2084   (-> watch lsp-watch-descriptors hash-table-values (-each #'file-notify-rm-watch))
   2085   (ht-clear! (lsp-watch-descriptors watch)))
   2086 
   2087 (defun lsp-json-bool (val)
   2088   "Convert VAL to JSON boolean."
   2089   (if val t :json-false))
   2090 
   2091 (defmacro with-lsp-workspace (workspace &rest body)
   2092   "Helper macro for invoking BODY in WORKSPACE context."
   2093   (declare (debug (form body))
   2094            (indent 1))
   2095   `(let ((lsp--cur-workspace ,workspace)) ,@body))
   2096 
   2097 (defmacro with-lsp-workspaces (workspaces &rest body)
   2098   "Helper macro for invoking BODY against multiple WORKSPACES."
   2099   (declare (debug (form body))
   2100            (indent 1))
   2101   `(let ((lsp--buffer-workspaces ,workspaces)) ,@body))
   2102 
   2103 
   2104 
   2105 (defmacro lsp-consistency-check (package)
   2106   `(defconst ,(intern (concat (symbol-name package)
   2107                               "-plist-value-when-compiled"))
   2108      (eval-when-compile lsp-use-plists)))
   2109 
   2110 
   2111 ;; loading code-workspace files
   2112 
   2113 ;;;###autoload
   2114 (defun lsp-load-vscode-workspace (file)
   2115   "Load vscode workspace from FILE"
   2116   (interactive "fSelect file to import: ")
   2117   (mapc #'lsp-workspace-folders-remove (lsp-session-folders (lsp-session)))
   2118 
   2119   (let ((dir (f-dirname file)))
   2120     (->> file
   2121          (json-read-file)
   2122          (alist-get 'folders)
   2123          (-map (-lambda ((&alist 'path))
   2124                  (lsp-workspace-folders-add (expand-file-name path dir)))))))
   2125 
   2126 ;;;###autoload
   2127 (defun lsp-save-vscode-workspace (file)
   2128   "Save vscode workspace to FILE"
   2129   (interactive "FSelect file to save to: ")
   2130 
   2131   (let ((json-encoding-pretty-print t))
   2132     (f-write-text (json-encode
   2133                    `((folders . ,(->> (lsp-session)
   2134                                       (lsp-session-folders)
   2135                                       (--map `((path . ,it)))))))
   2136                   'utf-8
   2137                   file)))
   2138 
   2139 
   2140 (defmacro lsp-foreach-workspace (&rest body)
   2141   "Execute BODY for each of the current workspaces."
   2142   (declare (debug (form body)))
   2143   `(--map (with-lsp-workspace it ,@body) (lsp-workspaces)))
   2144 
   2145 (defmacro when-lsp-workspace (workspace &rest body)
   2146   "Helper macro for invoking BODY in WORKSPACE context if present."
   2147   (declare (debug (form body))
   2148            (indent 1))
   2149   `(when-let* ((lsp--cur-workspace ,workspace)) ,@body))
   2150 
   2151 (lsp-defun lsp--window-show-quick-pick (_workspace (&ShowQuickPickParams :place-holder :can-pick-many :items))
   2152   (if-let* ((selectfunc (if can-pick-many #'completing-read-multiple #'completing-read))
   2153             (itemLabels (seq-map (-lambda ((item &as &QuickPickItem :label)) (format "%s" label))
   2154                                  items))
   2155             (result (funcall-interactively
   2156                      selectfunc
   2157                      (format "%s%s " place-holder (if can-pick-many " (* for all)" "")) itemLabels))
   2158             (choices (if (listp result)
   2159                          (if (equal result '("*"))
   2160                              itemLabels
   2161                            result)
   2162                        (list result))))
   2163       (vconcat (seq-filter #'identity (seq-map (-lambda ((item &as &QuickPickItem :label :user-data))
   2164                                                  (if (member label choices)
   2165                                                      (lsp-make-quick-pick-item :label label :picked t :user-data user-data)
   2166                                                    nil))
   2167                                                items)))))
   2168 
   2169 (lsp-defun lsp--window-show-input-box (_workspace (&ShowInputBoxParams :prompt :value?))
   2170   (read-string (format "%s: " prompt) (or value? "")))
   2171 
   2172 (lsp-defun lsp--window-show-message (_workspace (&ShowMessageRequestParams :message :type))
   2173   "Send the server's messages to log.
   2174 PARAMS - the data sent from _WORKSPACE."
   2175   (funcall (cl-case type
   2176              (1 'lsp--error)
   2177              (2 'lsp--warn)
   2178              (t 'lsp--info))
   2179            "%s"
   2180            message))
   2181 
   2182 (lsp-defun lsp--window-log-message (workspace (&ShowMessageRequestParams :message :type))
   2183   "Send the server's messages to log.
   2184 PARAMS - the data sent from WORKSPACE."
   2185   (ignore
   2186    (let ((client (lsp--workspace-client workspace)))
   2187      (when (or (not client)
   2188                (cl-notany (-rpartial #'string-match-p message)
   2189                           (lsp--client-ignore-messages client)))
   2190        (lsp-log "%s" (lsp--propertize message type))))))
   2191 
   2192 (lsp-defun lsp--window-log-message-request ((&ShowMessageRequestParams :message :type :actions?))
   2193   "Display a message request to user sending the user selection back to server."
   2194   (let* ((message (lsp--propertize message type))
   2195          (choices (seq-map #'lsp:message-action-item-title actions?)))
   2196     (if choices
   2197         (completing-read (concat message " ") (seq-into choices 'list) nil t)
   2198       (lsp-log message))))
   2199 
   2200 (lsp-defun lsp--window-show-document ((&ShowDocumentParams :uri :selection?))
   2201   "Show document URI in a buffer and go to SELECTION if any."
   2202   (let ((path (lsp--uri-to-path uri)))
   2203     (when (f-exists? path)
   2204       (with-current-buffer (find-file path)
   2205         (when selection?
   2206           (goto-char (lsp--position-to-point (lsp:range-start selection?))))
   2207         t))))
   2208 
   2209 (defcustom lsp-progress-prefix "⌛ "
   2210   "Progress prefix."
   2211   :group 'lsp-mode
   2212   :type 'string
   2213   :package-version '(lsp-mode . "8.0.0"))
   2214 
   2215 (defcustom lsp-progress-function #'lsp-on-progress-modeline
   2216   "Function for handling the progress notifications."
   2217   :group 'lsp-mode
   2218   :type '(choice
   2219           (const :tag "Use modeline" lsp-on-progress-modeline)
   2220           (const :tag "Legacy(uses either `progress-reporter' or `spinner' based on `lsp-progress-via-spinner')"
   2221                  lsp-on-progress-legacy)
   2222           (const :tag "Ignore" ignore)
   2223           (function :tag "Other function"))
   2224   :package-version '(lsp-mode . "8.0.0"))
   2225 
   2226 (defcustom lsp-request-while-no-input-may-block nil
   2227   "Have `lsp-request-while-no-input` block unless `non-essential` is t."
   2228   :group 'lsp-mode
   2229   :type 'boolean)
   2230 
   2231 (defun lsp--progress-status ()
   2232   "Returns the status of the progress for the current workspaces."
   2233   (-let ((progress-status
   2234           (s-join
   2235            "|"
   2236            (-keep
   2237             (lambda (workspace)
   2238               (let ((tokens (lsp--workspace-work-done-tokens workspace)))
   2239                 (unless (ht-empty? tokens)
   2240                   (mapconcat
   2241                    (-lambda ((&WorkDoneProgressBegin :message? :title :percentage?))
   2242                      (concat (if percentage?
   2243                                  (if (numberp percentage?)
   2244                                      (format "%.0f%%%% " percentage?)
   2245                                    (format "%s%%%% " percentage?))
   2246                                "")
   2247                              (or message? title)))
   2248                    (ht-values tokens)
   2249                    "|"))))
   2250             (lsp-workspaces)))))
   2251     (unless (s-blank? progress-status)
   2252       (concat lsp-progress-prefix progress-status " "))))
   2253 
   2254 (lsp-defun lsp-on-progress-modeline (workspace (&ProgressParams :token :value
   2255                                                                 (value &as &WorkDoneProgress :kind)))
   2256   "PARAMS contains the progress data.
   2257 WORKSPACE is the workspace that contains the progress token."
   2258   (add-to-list 'global-mode-string '(t (:eval (lsp--progress-status))))
   2259   (pcase kind
   2260     ("begin" (lsp-workspace-set-work-done-token token value workspace))
   2261     ("report" (lsp-workspace-set-work-done-token token value workspace))
   2262     ("end" (lsp-workspace-rem-work-done-token token workspace)))
   2263   (force-mode-line-update))
   2264 
   2265 (lsp-defun lsp-on-progress-legacy (workspace (&ProgressParams :token :value
   2266                                                               (value &as &WorkDoneProgress :kind)))
   2267   "PARAMS contains the progress data.
   2268 WORKSPACE is the workspace that contains the progress token."
   2269   (pcase kind
   2270     ("begin"
   2271      (-let* (((&WorkDoneProgressBegin :title :percentage?) value)
   2272              (reporter
   2273               (if lsp-progress-via-spinner
   2274                   (let* ((spinner-strings (alist-get (lsp-progress-spinner-type) spinner-types))
   2275                          ;; Set message as a tooltip for the spinner strings
   2276                          (propertized-strings
   2277                           (seq-map (lambda (string) (propertize string 'help-echo title))
   2278                                    spinner-strings))
   2279                          (spinner-type (vconcat propertized-strings)))
   2280                     ;; The progress relates to the server as a whole,
   2281                     ;; display it on all buffers.
   2282                     (mapcar (lambda (buffer)
   2283                               (lsp-with-current-buffer buffer
   2284                                 (spinner-start spinner-type))
   2285                               buffer)
   2286                             (lsp--workspace-buffers workspace)))
   2287                 (if percentage?
   2288                     (make-progress-reporter title 0 100 percentage?)
   2289                   ;; No percentage, just progress
   2290                   (make-progress-reporter title nil nil)))))
   2291        (lsp-workspace-set-work-done-token token reporter workspace)))
   2292     ("report"
   2293      (when-let* ((reporter (lsp-workspace-get-work-done-token token workspace)))
   2294        (unless lsp-progress-via-spinner
   2295          (progress-reporter-update reporter (lsp:work-done-progress-report-percentage? value)))))
   2296 
   2297     ("end"
   2298      (when-let* ((reporter (lsp-workspace-get-work-done-token token workspace)))
   2299        (if lsp-progress-via-spinner
   2300            (mapc (lambda (buffer)
   2301                    (when (lsp-buffer-live-p buffer)
   2302                      (lsp-with-current-buffer buffer
   2303                        (spinner-stop))))
   2304                  reporter)
   2305          (progress-reporter-done reporter))
   2306        (lsp-workspace-rem-work-done-token token workspace)))))
   2307 
   2308 
   2309 ;; diagnostics
   2310 
   2311 (defvar lsp-diagnostic-filter nil
   2312   "A a function which will be called with
   2313   `&PublishDiagnosticsParams' and `workspace' which can be used
   2314   to filter out the diagnostics. The function should return
   2315   `&PublishDiagnosticsParams'.
   2316 
   2317 Common usecase are:
   2318 1. Filter the diagnostics for a particular language server.
   2319 2. Filter out the diagnostics under specific level.")
   2320 
   2321 (defvar lsp-diagnostic-stats (ht))
   2322 
   2323 (defun lsp-diagnostics (&optional current-workspace?)
   2324   "Return the diagnostics from all workspaces."
   2325   (or (pcase (if current-workspace?
   2326                  (lsp-workspaces)
   2327                (lsp--session-workspaces (lsp-session)))
   2328         (`() ())
   2329         (`(,workspace) (lsp--workspace-diagnostics workspace))
   2330         (`,workspaces (let ((result (make-hash-table :test 'equal)))
   2331                         (mapc (lambda (workspace)
   2332                                 (->> workspace
   2333                                      (lsp--workspace-diagnostics)
   2334                                      (maphash (lambda (file-name diagnostics)
   2335                                                 (puthash file-name
   2336                                                          (append (gethash file-name result) diagnostics)
   2337                                                          result)))))
   2338                               workspaces)
   2339                         result)))
   2340       (ht)))
   2341 
   2342 (defun lsp-diagnostics-stats-for (path)
   2343   "Get diagnostics statistics for PATH.
   2344 The result format is vector [_ errors warnings infos hints] or nil."
   2345   (gethash (lsp--fix-path-casing path) lsp-diagnostic-stats))
   2346 
   2347 (defun lsp-diagnostics--request-pull-diagnostics (workspace)
   2348   "Request new diagnostics for the current file within WORKSPACE.
   2349 This is only executed if the server supports pull diagnostics."
   2350   (when (lsp-feature? "textDocument/diagnostic")
   2351     (let ((path (lsp--fix-path-casing (buffer-file-name))))
   2352       (lsp-request-async "textDocument/diagnostic"
   2353                          (list :textDocument (lsp--text-document-identifier))
   2354                          (-lambda ((&DocumentDiagnosticReport :kind :items?))
   2355                            (lsp-diagnostics--apply-pull-diagnostics workspace path kind items?))
   2356                          :mode 'tick))))
   2357 
   2358 (defun lsp-diagnostics--update-path (path new-stats)
   2359   (let ((new-stats (copy-sequence new-stats))
   2360         (path (lsp--fix-path-casing (directory-file-name path))))
   2361     (if-let* ((old-data (gethash path lsp-diagnostic-stats)))
   2362         (dotimes (idx 5)
   2363           (cl-callf + (aref old-data idx)
   2364             (aref new-stats idx)))
   2365       (puthash path new-stats lsp-diagnostic-stats))))
   2366 
   2367 (defun lsp-diagnostics--convert-and-update-path-stats (workspace path diagnostics)
   2368   (let ((path (lsp--fix-path-casing path))
   2369         (new-stats (make-vector 5 0)))
   2370     (mapc (-lambda ((&Diagnostic :severity?))
   2371             (cl-incf (aref new-stats (or severity? 1))))
   2372           diagnostics)
   2373     (when-let* ((old-diags (gethash path (lsp--workspace-diagnostics workspace))))
   2374       (mapc (-lambda ((&Diagnostic :severity?))
   2375               (cl-decf (aref new-stats (or severity? 1))))
   2376             old-diags))
   2377     (lsp-diagnostics--update-path path new-stats)
   2378     (while (not (string= path (setf path (file-name-directory
   2379                                           (directory-file-name path)))))
   2380       (lsp-diagnostics--update-path path new-stats))))
   2381 
   2382 (lsp-defun lsp--on-diagnostics-update-stats (workspace
   2383                                              (&PublishDiagnosticsParams :uri :diagnostics))
   2384   (lsp-diagnostics--convert-and-update-path-stats workspace (lsp--uri-to-path uri) diagnostics))
   2385 
   2386 (defun lsp-diagnostics--apply-pull-diagnostics (workspace path kind diagnostics?)
   2387   "Update WORKSPACE diagnostics at PATH with DIAGNOSTICS?.
   2388 Depends on KIND being a \\='full\\=' update."
   2389   (cond
   2390    ((equal kind "full")
   2391     ;; TODO support `lsp-diagnostic-filter'
   2392     ;; (the params types differ from the published diagnostics response)
   2393     (lsp-diagnostics--convert-and-update-path-stats workspace path diagnostics?)
   2394     (-let* ((lsp--virtual-buffer-mappings (ht))
   2395             (workspace-diagnostics (lsp--workspace-diagnostics workspace)))
   2396       (if (seq-empty-p diagnostics?)
   2397           (remhash path workspace-diagnostics)
   2398         (puthash path (append diagnostics? nil) workspace-diagnostics))
   2399       (run-hooks 'lsp-diagnostics-updated-hook)))
   2400     ((equal kind "unchanged") t)
   2401     (t (lsp--error "Unknown pull diagnostic result kind '%s'" kind))))
   2402 
   2403 (defun lsp--on-diagnostics (workspace params)
   2404   "Callback for textDocument/publishDiagnostics.
   2405 interface PublishDiagnosticsParams {
   2406     uri: string;
   2407     diagnostics: Diagnostic[];
   2408 }
   2409 PARAMS contains the diagnostics data.
   2410 WORKSPACE is the workspace that contains the diagnostics."
   2411   (when lsp-diagnostic-filter
   2412     (setf params (funcall lsp-diagnostic-filter params workspace)))
   2413 
   2414   (lsp--on-diagnostics-update-stats workspace params)
   2415 
   2416   (-let* (((&PublishDiagnosticsParams :uri :diagnostics) params)
   2417           (lsp--virtual-buffer-mappings (ht))
   2418           (file (lsp--fix-path-casing (lsp--uri-to-path uri)))
   2419           (workspace-diagnostics (lsp--workspace-diagnostics workspace)))
   2420 
   2421     (if (seq-empty-p diagnostics)
   2422         (remhash file workspace-diagnostics)
   2423       (puthash file (append diagnostics nil) workspace-diagnostics))
   2424 
   2425     (run-hooks 'lsp-diagnostics-updated-hook)))
   2426 
   2427 (defun lsp-diagnostics--workspace-cleanup (workspace)
   2428   (->> workspace
   2429        (lsp--workspace-diagnostics)
   2430        (maphash (lambda (key _)
   2431                   (lsp--on-diagnostics-update-stats
   2432                    workspace
   2433                    (lsp-make-publish-diagnostics-params
   2434                     :uri (lsp--path-to-uri key)
   2435                     :diagnostics [])))))
   2436   (clrhash (lsp--workspace-diagnostics workspace)))
   2437 
   2438 
   2439 
   2440 ;; textDocument/foldingRange support
   2441 
   2442 (cl-defstruct lsp--folding-range beg end kind children)
   2443 
   2444 (defvar-local lsp--cached-folding-ranges nil)
   2445 (defvar-local lsp--cached-nested-folding-ranges nil)
   2446 
   2447 (defun lsp--folding-range-width (range)
   2448   (- (lsp--folding-range-end range)
   2449      (lsp--folding-range-beg range)))
   2450 
   2451 (defun lsp--get-folding-ranges ()
   2452   "Get the folding ranges for the current buffer."
   2453   (unless (eq (buffer-chars-modified-tick) (car lsp--cached-folding-ranges))
   2454     (let* ((ranges (lsp-request "textDocument/foldingRange"
   2455                                 `(:textDocument ,(lsp--text-document-identifier))))
   2456            (sorted-line-col-pairs (->> ranges
   2457                                        (cl-mapcan (-lambda ((&FoldingRange :start-line
   2458                                                                            :start-character?
   2459                                                                            :end-line
   2460                                                                            :end-character?))
   2461                                                     (list (cons start-line start-character?)
   2462                                                           (cons end-line end-character?))))
   2463                                        (-sort #'lsp--line-col-comparator)))
   2464            (line-col-to-point-map (lsp--convert-line-col-to-points-batch
   2465                                    sorted-line-col-pairs)))
   2466       (setq lsp--cached-folding-ranges
   2467             (cons (buffer-chars-modified-tick)
   2468                   (--> ranges
   2469                     (seq-map (-lambda ((range &as
   2470                                               &FoldingRange :start-line
   2471                                               :start-character?
   2472                                               :end-line
   2473                                               :end-character?
   2474                                               :kind?))
   2475                                (make-lsp--folding-range
   2476                                 :beg (ht-get line-col-to-point-map
   2477                                              (cons start-line start-character?))
   2478                                 :end (ht-get line-col-to-point-map
   2479                                              (cons end-line end-character?))
   2480                                 :kind kind?))
   2481                              it)
   2482                     (seq-filter (lambda (folding-range)
   2483                                   (< (lsp--folding-range-beg folding-range)
   2484                                      (lsp--folding-range-end folding-range)))
   2485                                 it)
   2486                     (seq-into it 'list)
   2487                     (delete-dups it))))))
   2488   (cdr lsp--cached-folding-ranges))
   2489 
   2490 (defun lsp--get-nested-folding-ranges ()
   2491   "Get a list of nested folding ranges for the current buffer."
   2492   (-let [(tick . _) lsp--cached-folding-ranges]
   2493     (if (and (eq tick (buffer-chars-modified-tick))
   2494              lsp--cached-nested-folding-ranges)
   2495         lsp--cached-nested-folding-ranges
   2496       (setq lsp--cached-nested-folding-ranges
   2497             (lsp--folding-range-build-trees (lsp--get-folding-ranges))))))
   2498 
   2499 (defun lsp--folding-range-build-trees (ranges)
   2500   (setq ranges (seq-sort #'lsp--range-before-p ranges))
   2501   (let* ((dummy-node (make-lsp--folding-range
   2502                       :beg most-negative-fixnum
   2503                       :end most-positive-fixnum))
   2504          (stack (list dummy-node)))
   2505     (dolist (range ranges)
   2506       (while (not (lsp--range-inside-p range (car stack)))
   2507         (pop stack))
   2508       (push range (lsp--folding-range-children (car stack)))
   2509       (push range stack))
   2510     (lsp--folding-range-children dummy-node)))
   2511 
   2512 (defun lsp--range-inside-p (r1 r2)
   2513   "Return non-nil if folding range R1 lies inside R2"
   2514   (and (>= (lsp--folding-range-beg r1) (lsp--folding-range-beg r2))
   2515        (<= (lsp--folding-range-end r1) (lsp--folding-range-end r2))))
   2516 
   2517 (defun lsp--range-before-p (r1 r2)
   2518   "Return non-nil if folding range R1 ends before R2"
   2519   ;; Ensure r1 comes before r2
   2520   (or (< (lsp--folding-range-beg r1)
   2521          (lsp--folding-range-beg r2))
   2522       ;; If beg(r1) == beg(r2) make sure r2 ends first
   2523       (and (= (lsp--folding-range-beg r1)
   2524               (lsp--folding-range-beg r2))
   2525            (< (lsp--folding-range-end r2)
   2526               (lsp--folding-range-end r1)))))
   2527 
   2528 (defun lsp--point-inside-range-p (point range)
   2529   "Return non-nil if POINT lies inside folding range RANGE."
   2530   (and (>= point (lsp--folding-range-beg range))
   2531        (<= point (lsp--folding-range-end range))))
   2532 
   2533 (cl-defun lsp--get-current-innermost-folding-range (&optional (point (point)))
   2534   "Return the innermost folding range POINT lies in."
   2535   (seq-reduce (lambda (innermost-range curr-range)
   2536                 (if (and (lsp--point-inside-range-p point curr-range)
   2537                          (or (null innermost-range)
   2538                              (lsp--range-inside-p curr-range innermost-range)))
   2539                     curr-range
   2540                   innermost-range))
   2541               (lsp--get-folding-ranges)
   2542               nil))
   2543 
   2544 (cl-defun lsp--get-current-outermost-folding-range (&optional (point (point)))
   2545   "Return the outermost folding range POINT lies in."
   2546   (cdr (seq-reduce (-lambda ((best-pair &as outermost-width . _) curr-range)
   2547                      (let ((curr-width (lsp--folding-range-width curr-range)))
   2548                        (if (and (lsp--point-inside-range-p point curr-range)
   2549                                 (or (null best-pair)
   2550                                     (> curr-width outermost-width)))
   2551                            (cons curr-width curr-range)
   2552                          best-pair)))
   2553                    (lsp--get-folding-ranges)
   2554                    nil)))
   2555 
   2556 (defun lsp--folding-range-at-point-bounds ()
   2557   (when (and lsp-enable-folding
   2558              (lsp-feature? "textDocument/foldingRange"))
   2559     (if-let* ((range (lsp--get-current-innermost-folding-range)))
   2560         (cons (lsp--folding-range-beg range)
   2561               (lsp--folding-range-end range)))))
   2562 (put 'lsp--folding-range 'bounds-of-thing-at-point
   2563      #'lsp--folding-range-at-point-bounds)
   2564 
   2565 (defun lsp--get-nearest-folding-range (&optional backward)
   2566   (let ((point (point))
   2567         (found nil))
   2568     (while (not
   2569             (or found
   2570                 (if backward
   2571                     (<= point (point-min))
   2572                   (>= point (point-max)))))
   2573       (if backward (cl-decf point) (cl-incf point))
   2574       (setq found (lsp--get-current-innermost-folding-range point)))
   2575     found))
   2576 
   2577 (defun lsp--folding-range-at-point-forward-op (n)
   2578   (when (and lsp-enable-folding
   2579              (not (zerop n))
   2580              (lsp-feature? "textDocument/foldingRange"))
   2581     (cl-block break
   2582       (dotimes (_ (abs n))
   2583         (if-let* ((range (lsp--get-nearest-folding-range (< n 0))))
   2584             (goto-char (if (< n 0)
   2585                            (lsp--folding-range-beg range)
   2586                          (lsp--folding-range-end range)))
   2587           (cl-return-from break))))))
   2588 (put 'lsp--folding-range 'forward-op
   2589      #'lsp--folding-range-at-point-forward-op)
   2590 
   2591 (defun lsp--folding-range-at-point-beginning-op ()
   2592   (goto-char (car (lsp--folding-range-at-point-bounds))))
   2593 (put 'lsp--folding-range 'beginning-op
   2594      #'lsp--folding-range-at-point-beginning-op)
   2595 
   2596 (defun lsp--folding-range-at-point-end-op ()
   2597   (goto-char (cdr (lsp--folding-range-at-point-bounds))))
   2598 (put 'lsp--folding-range 'end-op
   2599      #'lsp--folding-range-at-point-end-op)
   2600 
   2601 (defun lsp--range-at-point-bounds ()
   2602   (or (lsp--folding-range-at-point-bounds)
   2603       (when-let* ((range (and
   2604                          (lsp-feature? "textDocument/hover")
   2605                          (->> (lsp--text-document-position-params)
   2606                               (lsp-request "textDocument/hover")
   2607                               (lsp:hover-range?)))))
   2608         (lsp--range-to-region range))))
   2609 
   2610 ;; A more general purpose "thing", useful for applications like focus.el
   2611 (put 'lsp--range 'bounds-of-thing-at-point
   2612      #'lsp--range-at-point-bounds)
   2613 
   2614 (defun lsp--log-io-p (method)
   2615   "Return non nil if should log for METHOD."
   2616   (and lsp-log-io
   2617        (or (not lsp-log-io-allowlist-methods)
   2618            (member method lsp-log-io-allowlist-methods))))
   2619 
   2620 
   2621 ;; toggles
   2622 
   2623 (defun lsp-toggle-trace-io ()
   2624   "Toggle client-server protocol logging."
   2625   (interactive)
   2626   (setq lsp-log-io (not lsp-log-io))
   2627   (lsp--info "Server logging %s." (if lsp-log-io "enabled" "disabled")))
   2628 
   2629 (defun lsp-toggle-signature-auto-activate ()
   2630   "Toggle signature auto activate."
   2631   (interactive)
   2632   (setq lsp-signature-auto-activate
   2633         (unless lsp-signature-auto-activate '(:on-trigger-char)))
   2634   (lsp--info "Signature autoactivate %s." (if lsp-signature-auto-activate "enabled" "disabled"))
   2635   (lsp--update-signature-help-hook))
   2636 
   2637 (defun lsp-toggle-on-type-formatting ()
   2638   "Toggle on type formatting."
   2639   (interactive)
   2640   (setq lsp-enable-on-type-formatting (not lsp-enable-on-type-formatting))
   2641   (lsp--info "On type formatting is %s." (if lsp-enable-on-type-formatting "enabled" "disabled"))
   2642   (lsp--update-on-type-formatting-hook))
   2643 
   2644 (defun lsp-toggle-symbol-highlight ()
   2645   "Toggle symbol highlighting."
   2646   (interactive)
   2647   (setq lsp-enable-symbol-highlighting (not lsp-enable-symbol-highlighting))
   2648 
   2649   (cond
   2650    ((and lsp-enable-symbol-highlighting
   2651          (lsp-feature? "textDocument/documentHighlight"))
   2652     (add-hook 'lsp-on-idle-hook #'lsp--document-highlight nil t)
   2653     (lsp--info "Symbol highlighting enabled in current buffer."))
   2654    ((not lsp-enable-symbol-highlighting)
   2655     (remove-hook 'lsp-on-idle-hook #'lsp--document-highlight t)
   2656     (lsp--remove-overlays 'lsp-highlight)
   2657     (lsp--info "Symbol highlighting disabled in current buffer."))))
   2658 
   2659 
   2660 ;; keybindings
   2661 (defvar lsp--binding-descriptions nil
   2662   "List of key binding/short description pair.")
   2663 
   2664 (defmacro lsp-define-conditional-key (keymap key def desc cond &rest bindings)
   2665   "In KEYMAP, define key sequence KEY as DEF conditionally.
   2666 This is like `define-key', except the definition disappears
   2667 whenever COND evaluates to nil.
   2668 DESC is the short-description for the binding.
   2669 BINDINGS is a list of (key def desc cond)."
   2670   (declare (indent defun)
   2671            (debug (form form form form form &rest sexp)))
   2672   (->> (cl-list* key def desc cond bindings)
   2673        (-partition 4)
   2674        (-mapcat (-lambda ((key def desc cond))
   2675                   `((define-key ,keymap ,key
   2676                       '(menu-item
   2677                         ,(format "maybe-%s" def)
   2678                         ,def
   2679                         :filter
   2680                         (lambda (item)
   2681                           (when (with-current-buffer (or (when (buffer-live-p lsp--describe-buffer)
   2682                                                            lsp--describe-buffer)
   2683                                                          (current-buffer))
   2684                                   ,cond)
   2685                             item))))
   2686                     (when (stringp ,key)
   2687                       (setq lsp--binding-descriptions
   2688                             (append lsp--binding-descriptions '(,key ,desc)))))))
   2689        macroexp-progn))
   2690 
   2691 (defvar lsp--describe-buffer nil)
   2692 
   2693 (defun lsp-describe-buffer-bindings-advice (fn buffer &optional prefix menus)
   2694   (let ((lsp--describe-buffer buffer))
   2695     (funcall fn buffer prefix menus)))
   2696 
   2697 (advice-add 'describe-buffer-bindings
   2698             :around
   2699             #'lsp-describe-buffer-bindings-advice)
   2700 
   2701 (defun lsp--prepend-prefix (mappings)
   2702   (->> mappings
   2703        (-partition 2)
   2704        (-mapcat (-lambda ((key description))
   2705                   (list (concat lsp-keymap-prefix " " key)
   2706                         description)))))
   2707 
   2708 (defvar lsp-command-map
   2709   (-doto (make-sparse-keymap)
   2710     (lsp-define-conditional-key
   2711       ;; workspaces
   2712       "wD" lsp-disconnect "disconnect" (lsp-workspaces)
   2713       "wd" lsp-describe-session "describe session" t
   2714       "wq" lsp-workspace-shutdown "shutdown server" (lsp-workspaces)
   2715       "wr" lsp-workspace-restart "restart server" (lsp-workspaces)
   2716       "ws" lsp "start server" t
   2717 
   2718       ;; formatting
   2719       "==" lsp-format-buffer "format buffer" (or (lsp-feature? "textDocument/rangeFormatting")
   2720                                                  (lsp-feature? "textDocument/formatting"))
   2721       "=r" lsp-format-region "format region" (lsp-feature? "textDocument/rangeFormatting")
   2722 
   2723       ;; folders
   2724       "Fa" lsp-workspace-folders-add "add folder" t
   2725       "Fb" lsp-workspace-blocklist-remove "un-blocklist folder" t
   2726       "Fr" lsp-workspace-folders-remove "remove folder" t
   2727 
   2728       ;; toggles
   2729       "TD" lsp-modeline-diagnostics-mode "toggle modeline diagnostics" (lsp-feature?
   2730                                                                         "textDocument/publishDiagnostics")
   2731       "TL" lsp-toggle-trace-io "toggle log io" t
   2732       "TS" lsp-ui-sideline-mode "toggle sideline" (featurep 'lsp-ui-sideline)
   2733       "TT" lsp-treemacs-sync-mode "toggle treemacs integration" (featurep 'lsp-treemacs)
   2734       "Ta" lsp-modeline-code-actions-mode "toggle modeline code actions" (lsp-feature?
   2735                                                                           "textDocument/codeAction")
   2736       "Tb" lsp-headerline-breadcrumb-mode "toggle breadcrumb" (lsp-feature?
   2737                                                                "textDocument/documentSymbol")
   2738       "Td" lsp-ui-doc-mode "toggle documentation popup" (featurep 'lsp-ui-doc)
   2739       "Tf" lsp-toggle-on-type-formatting "toggle on type formatting" (lsp-feature?
   2740                                                                       "textDocument/onTypeFormatting")
   2741       "Th" lsp-toggle-symbol-highlight "toggle highlighting" (lsp-feature? "textDocument/documentHighlight")
   2742       "Tl" lsp-lens-mode "toggle lenses" (lsp-feature? "textDocument/codeLens")
   2743       "Ts" lsp-toggle-signature-auto-activate "toggle signature" (lsp-feature? "textDocument/signatureHelp")
   2744 
   2745       ;; goto
   2746       "ga" xref-find-apropos "find symbol in workspace" (lsp-feature? "workspace/symbol")
   2747       "gd" lsp-find-declaration "find declarations" (lsp-feature? "textDocument/declaration")
   2748       "ge" lsp-treemacs-errors-list "show errors" (fboundp 'lsp-treemacs-errors-list)
   2749       "gg" lsp-find-definition "find definitions" (lsp-feature? "textDocument/definition")
   2750       "gh" lsp-treemacs-call-hierarchy "call hierarchy" (and (lsp-feature? "callHierarchy/incomingCalls")
   2751                                                              (fboundp 'lsp-treemacs-call-hierarchy))
   2752       "gi" lsp-find-implementation "find implementations" (lsp-feature? "textDocument/implementation")
   2753       "gr" lsp-find-references "find references" (lsp-feature? "textDocument/references")
   2754       "gt" lsp-find-type-definition "find type definition" (lsp-feature? "textDocument/typeDefinition")
   2755 
   2756       ;; help
   2757       "hg" lsp-ui-doc-glance "glance symbol" (and (featurep 'lsp-ui-doc)
   2758                                                   (lsp-feature? "textDocument/hover"))
   2759       "hh" lsp-describe-thing-at-point "describe symbol at point" (lsp-feature? "textDocument/hover")
   2760       "hs" lsp-signature-activate "signature help" (lsp-feature? "textDocument/signatureHelp")
   2761 
   2762       ;; refactoring
   2763       "ro" lsp-organize-imports "organize imports" (lsp-feature? "textDocument/codeAction")
   2764       "rr" lsp-rename "rename" (lsp-feature? "textDocument/rename")
   2765 
   2766       ;; actions
   2767       "aa" lsp-execute-code-action "code actions" (lsp-feature? "textDocument/codeAction")
   2768       "ah" lsp-document-highlight "highlight symbol" (lsp-feature? "textDocument/documentHighlight")
   2769       "al" lsp-avy-lens "lens" (and (bound-and-true-p lsp-lens-mode) (featurep 'avy))
   2770 
   2771       ;; peeks
   2772       "Gg" lsp-ui-peek-find-definitions "peek definitions" (and (lsp-feature? "textDocument/definition")
   2773                                                                 (fboundp 'lsp-ui-peek-find-definitions))
   2774       "Gi" lsp-ui-peek-find-implementation "peek implementations" (and
   2775                                                                    (fboundp 'lsp-ui-peek-find-implementation)
   2776                                                                    (lsp-feature? "textDocument/implementation"))
   2777       "Gr" lsp-ui-peek-find-references "peek references" (and (fboundp 'lsp-ui-peek-find-references)
   2778                                                               (lsp-feature? "textDocument/references"))
   2779       "Gs" lsp-ui-peek-find-workspace-symbol "peek workspace symbol" (and (fboundp
   2780                                                                            'lsp-ui-peek-find-workspace-symbol)
   2781                                                                           (lsp-feature? "workspace/symbol")))))
   2782 
   2783 
   2784 ;; which-key integration
   2785 
   2786 (declare-function which-key-add-major-mode-key-based-replacements "ext:which-key")
   2787 (declare-function which-key-add-key-based-replacements "ext:which-key")
   2788 
   2789 (defun lsp-enable-which-key-integration (&optional all-modes)
   2790   "Adds descriptions for `lsp-mode-map' to `which-key-mode' for the current
   2791 active `major-mode', or for all major modes when ALL-MODES is t."
   2792   (cl-flet ((which-key-fn (if all-modes
   2793                               'which-key-add-key-based-replacements
   2794                             (apply-partially 'which-key-add-major-mode-key-based-replacements major-mode))))
   2795     (apply
   2796      #'which-key-fn
   2797      (lsp--prepend-prefix
   2798       (cl-list*
   2799        ""    "lsp"
   2800        "w"   "workspaces"
   2801        "F"   "folders"
   2802        "="   "formatting"
   2803        "T"   "toggle"
   2804        "g"   "goto"
   2805        "h"   "help"
   2806        "r"   "refactor"
   2807        "a"   "code actions"
   2808        "G"   "peek"
   2809        lsp--binding-descriptions)))))
   2810 
   2811 
   2812 ;; Globbing syntax
   2813 
   2814 ;; We port VSCode's glob-to-regexp code
   2815 ;; (https://github.com/Microsoft/vscode/blob/466da1c9013c624140f6d1473b23a870abc82d44/src/vs/base/common/glob.ts)
   2816 ;; since the LSP globbing syntax seems to be the same as that of
   2817 ;; VSCode.
   2818 
   2819 (defconst lsp-globstar "**"
   2820   "Globstar pattern.")
   2821 
   2822 (defconst lsp-glob-split ?/
   2823   "The character by which we split path components in a glob
   2824 pattern.")
   2825 
   2826 (defconst lsp-path-regexp "[/\\\\]"
   2827   "Forward or backslash to be used as a path separator in
   2828 computed regexps.")
   2829 
   2830 (defconst lsp-non-path-regexp "[^/\\\\]"
   2831   "A regexp matching anything other than a slash.")
   2832 
   2833 (defconst lsp-globstar-regexp
   2834   (format "\\(?:%s\\|%s+%s\\|%s%s+\\)*?"
   2835           lsp-path-regexp
   2836           lsp-non-path-regexp lsp-path-regexp
   2837           lsp-path-regexp lsp-non-path-regexp)
   2838   "Globstar in regexp form.")
   2839 
   2840 (defun lsp-split-glob-pattern (pattern split-char)
   2841   "Split PATTERN at SPLIT-CHAR while respecting braces and brackets."
   2842   (when pattern
   2843     (let ((segments nil)
   2844           (in-braces nil)
   2845           (in-brackets nil)
   2846           (current-segment ""))
   2847       (dolist (char (string-to-list pattern))
   2848         (cl-block 'exit-point
   2849           (if (eq char split-char)
   2850               (when (and (null in-braces)
   2851                          (null in-brackets))
   2852                 (push current-segment segments)
   2853                 (setq current-segment "")
   2854                 (cl-return-from 'exit-point))
   2855             (pcase char
   2856               (?{
   2857                (setq in-braces t))
   2858               (?}
   2859                (setq in-braces nil))
   2860               (?\[
   2861                (setq in-brackets t))
   2862               (?\]
   2863                (setq in-brackets nil))))
   2864           (setq current-segment (concat current-segment
   2865                                         (char-to-string char)))))
   2866       (unless (string-empty-p current-segment)
   2867         (push current-segment segments))
   2868       (nreverse segments))))
   2869 
   2870 (defun lsp--glob-to-regexp (pattern)
   2871   "Helper function to convert a PATTERN from LSP's glob syntax to
   2872 an Elisp regexp."
   2873   (if (string-empty-p pattern)
   2874       ""
   2875     (let ((current-regexp "")
   2876           (glob-segments (lsp-split-glob-pattern pattern lsp-glob-split)))
   2877       (if (-all? (lambda (segment) (eq segment lsp-globstar))
   2878                  glob-segments)
   2879           ".*"
   2880         (let ((prev-segment-was-globstar nil))
   2881           (seq-do-indexed
   2882            (lambda (segment index)
   2883              (if (string-equal segment lsp-globstar)
   2884                  (unless prev-segment-was-globstar
   2885                    (setq current-regexp (concat current-regexp
   2886                                                 lsp-globstar-regexp))
   2887                    (setq prev-segment-was-globstar t))
   2888                (let ((in-braces nil)
   2889                      (brace-val "")
   2890                      (in-brackets nil)
   2891                      (bracket-val ""))
   2892                  (dolist (char (string-to-list segment))
   2893                    (cond
   2894                     ((and (not (char-equal char ?\}))
   2895                           in-braces)
   2896                      (setq brace-val (concat brace-val
   2897                                              (char-to-string char))))
   2898                     ((and in-brackets
   2899                           (or (not (char-equal char ?\]))
   2900                               (string-empty-p bracket-val)))
   2901                      (let ((curr (cond
   2902                                   ((char-equal char ?-)
   2903                                    "-")
   2904                                   ;; NOTE: ?\^ and ?^ are different characters
   2905                                   ((and (memq char '(?^ ?!))
   2906                                         (string-empty-p bracket-val))
   2907                                    "^")
   2908                                   ((char-equal char lsp-glob-split)
   2909                                    "")
   2910                                   (t
   2911                                    (regexp-quote (char-to-string char))))))
   2912                        (setq bracket-val (concat bracket-val curr))))
   2913                     (t
   2914                      (cl-case char
   2915                        (?{
   2916                         (setq in-braces t))
   2917                        (?\[
   2918                         (setq in-brackets t))
   2919                        (?}
   2920                         (let* ((choices (lsp-split-glob-pattern brace-val ?\,))
   2921                                (brace-regexp (concat "\\(?:"
   2922                                                      (mapconcat #'lsp--glob-to-regexp choices "\\|")
   2923                                                      "\\)")))
   2924                           (setq current-regexp (concat current-regexp
   2925                                                        brace-regexp))
   2926                           (setq in-braces nil)
   2927                           (setq brace-val "")))
   2928                        (?\]
   2929                         (setq current-regexp
   2930                               (concat current-regexp
   2931                                       "[" bracket-val "]"))
   2932                         (setq in-brackets nil)
   2933                         (setq bracket-val ""))
   2934                        (??
   2935                         (setq current-regexp
   2936                               (concat current-regexp
   2937                                       lsp-non-path-regexp)))
   2938                        (?*
   2939                         (setq current-regexp
   2940                               (concat current-regexp
   2941                                       lsp-non-path-regexp "*?")))
   2942                        (t
   2943                         (setq current-regexp
   2944                               (concat current-regexp
   2945                                       (regexp-quote (char-to-string char)))))))))
   2946                  (when (and (< index (1- (length glob-segments)))
   2947                             (or (not (string-equal (nth (1+ index) glob-segments)
   2948                                                    lsp-globstar))
   2949                                 (< (+ index 2)
   2950                                    (length glob-segments))))
   2951                    (setq current-regexp
   2952                          (concat current-regexp
   2953                                  lsp-path-regexp)))
   2954                  (setq prev-segment-was-globstar nil))))
   2955            glob-segments)
   2956           current-regexp)))))
   2957 
   2958 ;; See https://github.com/emacs-lsp/lsp-mode/issues/2365
   2959 (defun lsp-glob-unbrace-at-top-level (glob-pattern)
   2960   "If GLOB-PATTERN does not start with a brace, return a singleton list
   2961 containing GLOB-PATTERN.
   2962 
   2963 If GLOB-PATTERN does start with a brace, return a list of the
   2964 comma-separated globs within the top-level braces."
   2965   (if (not (string-prefix-p "{" glob-pattern))
   2966       (list glob-pattern)
   2967     (lsp-split-glob-pattern (substring glob-pattern 1 -1) ?\,)))
   2968 
   2969 (defun lsp-glob-convert-to-wrapped-regexp (glob-pattern)
   2970   "Convert GLOB-PATTERN to a regexp wrapped with the beginning-
   2971 and end-of-string meta-characters."
   2972   (concat "\\`" (lsp--glob-to-regexp (string-trim glob-pattern)) "\\'"))
   2973 
   2974 (defun lsp-glob-to-regexps (glob-pattern)
   2975   "Convert a GLOB-PATTERN to a list of Elisp regexps."
   2976   (when-let*
   2977       ((glob-pattern (cond ((hash-table-p glob-pattern)
   2978                             (ht-get glob-pattern "pattern"))
   2979                            ((stringp glob-pattern) glob-pattern)
   2980                            (t (error "Unknown glob-pattern type: %s" glob-pattern))))
   2981        (trimmed-pattern (string-trim glob-pattern))
   2982        (top-level-unbraced-patterns (lsp-glob-unbrace-at-top-level trimmed-pattern)))
   2983     (seq-map #'lsp-glob-convert-to-wrapped-regexp
   2984              top-level-unbraced-patterns)))
   2985 
   2986 
   2987 
   2988 (defvar lsp-mode-menu)
   2989 
   2990 (defun lsp-mouse-click (event)
   2991   (interactive "e")
   2992   (let* ((ec (event-start event))
   2993          (choice (x-popup-menu event lsp-mode-menu))
   2994          (action (lookup-key lsp-mode-menu (apply 'vector choice))))
   2995 
   2996     (select-window (posn-window ec))
   2997 
   2998     (unless (and (region-active-p) (eq action 'lsp-execute-code-action))
   2999       (goto-char (posn-point ec)))
   3000     (run-with-idle-timer
   3001      0.001 nil
   3002      (lambda ()
   3003        (cl-labels ((check (value) (not (null value))))
   3004          (when choice
   3005            (call-interactively action)))))))
   3006 
   3007 (defvar lsp-mode-map
   3008   (let ((map (make-sparse-keymap)))
   3009     (define-key map (kbd "C-<down-mouse-1>") #'lsp-find-definition-mouse)
   3010     (define-key map (kbd "C-<mouse-1>") #'ignore)
   3011     (define-key map (kbd "<mouse-3>") #'lsp-mouse-click)
   3012     (define-key map (kbd "C-S-SPC") #'lsp-signature-activate)
   3013     (when lsp-keymap-prefix
   3014       (define-key map (kbd lsp-keymap-prefix) lsp-command-map))
   3015     map)
   3016   "Keymap for `lsp-mode'.")
   3017 
   3018 (define-minor-mode lsp-mode "Mode for LSP interaction."
   3019   :keymap lsp-mode-map
   3020   :lighter
   3021   (" LSP["
   3022    (lsp--buffer-workspaces
   3023     (:eval (mapconcat #'lsp--workspace-print lsp--buffer-workspaces "]["))
   3024     (:propertize "Disconnected" face warning))
   3025    "]")
   3026   :group 'lsp-mode
   3027   (when (and lsp-mode (not lsp--buffer-workspaces) (not lsp--buffer-deferred))
   3028     ;; fire up `lsp' when someone calls `lsp-mode' instead of `lsp'
   3029     (lsp)))
   3030 
   3031 (defvar lsp-mode-menu
   3032   (easy-menu-create-menu
   3033    nil
   3034    `(["Go to definition" lsp-find-definition
   3035       :active (lsp-feature? "textDocument/definition")]
   3036      ["Find references" lsp-find-references
   3037       :active (lsp-feature? "textDocument/references")]
   3038      ["Find implementations" lsp-find-implementation
   3039       :active (lsp-feature? "textDocument/implementation")]
   3040      ["Find declarations" lsp-find-declaration
   3041       :active (lsp-feature? "textDocument/declaration")]
   3042      ["Go to type declaration" lsp-find-type-definition
   3043       :active (lsp-feature? "textDocument/typeDefinition")]
   3044      "--"
   3045      ["Describe" lsp-describe-thing-at-point]
   3046      ["Code action" lsp-execute-code-action]
   3047      ["Format" lsp-format-buffer]
   3048      ["Highlight references" lsp-document-highlight]
   3049      ["Type Hierarchy" lsp-java-type-hierarchy
   3050       :visible (lsp-can-execute-command? "java.navigate.resolveTypeHierarchy")]
   3051      ["Type Hierarchy" lsp-treemacs-type-hierarchy
   3052       :visible (and (not (lsp-can-execute-command? "java.navigate.resolveTypeHierarchy"))
   3053                     (functionp 'lsp-treemacs-type-hierarchy)
   3054                     (lsp-feature? "textDocument/typeHierarchy"))]
   3055      ["Call Hierarchy" lsp-treemacs-call-hierarchy
   3056       :visible (and (functionp 'lsp-treemacs-call-hierarchy)
   3057                     (lsp-feature? "textDocument/callHierarchy"))]
   3058      ["Rename" lsp-rename
   3059       :active (lsp-feature? "textDocument/rename")]
   3060      "--"
   3061      ("Session"
   3062       ["View logs" lsp-workspace-show-log]
   3063       ["Describe" lsp-describe-session]
   3064       ["Shutdown" lsp-shutdown-workspace]
   3065       ["Restart" lsp-restart-workspace])
   3066      ("Workspace Folders"
   3067       ["Add" lsp-workspace-folders-add]
   3068       ["Remove" lsp-workspace-folders-remove]
   3069       ["Open" lsp-workspace-folders-open])
   3070      ("Toggle features"
   3071       ["Lenses" lsp-lens-mode]
   3072       ["Headerline breadcrumb" lsp-headerline-breadcrumb-mode]
   3073       ["Modeline code actions" lsp-modeline-code-actions-mode]
   3074       ["Modeline diagnostics" lsp-modeline-diagnostics-mode])
   3075      "---"
   3076      ("Debug"
   3077       :active (bound-and-true-p dap-ui-mode)
   3078       :filter ,(lambda (_)
   3079                  (and (boundp 'dap-ui-menu-items)
   3080                       (nthcdr 3 dap-ui-menu-items))))))
   3081   "Menu for lsp-mode.")
   3082 
   3083 (defalias 'make-lsp-client 'make-lsp--client)
   3084 
   3085 (cl-defstruct lsp--registered-capability
   3086   (id "")
   3087   (method " ")
   3088   (options nil))
   3089 
   3090 ;; A ‘lsp--workspace’ object represents exactly one language server process.
   3091 (cl-defstruct lsp--workspace
   3092   ;; the `ewoc' object for displaying I/O to and from the server
   3093   (ewoc nil)
   3094 
   3095   ;; ‘server-capabilities’ is a hash table of the language server capabilities.
   3096   ;; It is the hash table representation of a LSP ServerCapabilities structure;
   3097   ;; cf. https://microsoft.github.io/language-server-protocol/specification#initialize.
   3098   (server-capabilities nil)
   3099 
   3100   ;; ‘registered-server-capabilities’ is a list of hash tables that represent
   3101   ;; dynamically-registered Registration objects.  See
   3102   ;; https://microsoft.github.io/language-server-protocol/specification#client_registerCapability.
   3103   (registered-server-capabilities nil)
   3104 
   3105   ;; ‘root’ is a directory name or a directory file name for the workspace
   3106   ;; root.  ‘lsp-mode’ passes this directory to the ‘initialize’ method of the
   3107   ;; language server; see
   3108   ;; https://microsoft.github.io/language-server-protocol/specification#initialize.
   3109   (root nil)
   3110 
   3111   ;; ‘client’ is the ‘lsp--client’ object associated with this workspace.
   3112   (client nil)
   3113 
   3114   ;; ‘host-root’ contains the host root info as derived from `file-remote-p'. It
   3115   ;; used to derive the file path in `lsp--uri-to-path' when using tramp
   3116   ;; connection.
   3117   (host-root nil)
   3118 
   3119   ;; ‘proc’ is a process object; it may represent a regular process, a pipe, or
   3120   ;; a network connection.  ‘lsp-mode’ communicates with ‘proc’ using the
   3121   ;; language server protocol.  ‘proc’ corresponds to the COMMUNICATION-PROCESS
   3122   ;; element of the return value of the client’s ‘get-root’ field, which see.
   3123   (proc nil)
   3124 
   3125   ;; ‘proc’ is a process object; it must represent a regular process, not a
   3126   ;; pipe or network process.  It represents the actual server process that
   3127   ;; corresponds to this workspace.  ‘cmd-proc’ corresponds to the
   3128   ;; COMMAND-PROCESS element of the return value of the client’s ‘get-root’
   3129   ;; field, which see.
   3130   (cmd-proc nil)
   3131 
   3132   ;; ‘buffers’ is a list of buffers associated with this workspace.
   3133   (buffers nil)
   3134 
   3135   ;; if semantic tokens is enabled, `semantic-tokens-faces' contains
   3136   ;; one face (or nil) for each token type supported by the language server.
   3137   (semantic-tokens-faces nil)
   3138 
   3139   ;; If semantic highlighting is enabled, `semantic-tokens-modifier-faces'
   3140   ;; contains one face (or nil) for each modifier type supported by the language
   3141   ;; server
   3142   (semantic-tokens-modifier-faces nil)
   3143 
   3144   ;; Extra client capabilities provided by third-party packages using
   3145   ;; `lsp-register-client-capabilities'. It's value is an alist of (PACKAGE-NAME
   3146   ;; . CAPS), where PACKAGE-NAME is a symbol of the third-party package name,
   3147   ;; and CAPS is either a plist of the client capabilities, or a function that
   3148   ;; takes no argument and returns a plist of the client capabilities or nil.
   3149   (extra-client-capabilities nil)
   3150 
   3151   ;; Workspace status
   3152   (status nil)
   3153 
   3154   ;; ‘metadata’ is a generic storage for workspace specific data. It is
   3155   ;; accessed via `lsp-workspace-set-metadata' and `lsp-workspace-set-metadata'
   3156   (metadata (make-hash-table :test 'equal))
   3157 
   3158   ;; contains all the file notification watches that have been created for the
   3159   ;; current workspace in format filePath->file notification handle.
   3160   (watches (make-hash-table :test 'equal))
   3161 
   3162   ;; list of workspace folders
   3163   (workspace-folders nil)
   3164 
   3165   ;; ‘last-id’ the last request id for the current workspace.
   3166   (last-id 0)
   3167 
   3168   ;; ‘status-string’ allows extensions to specify custom status string based on
   3169   ;; the Language Server specific messages.
   3170   (status-string nil)
   3171 
   3172   ;; ‘shutdown-action’ flag used to mark that workspace should not be restarted (e.g. it
   3173   ;; was stopped).
   3174   shutdown-action
   3175 
   3176   ;; ‘diagnostics’ a hashmap with workspace diagnostics.
   3177   (diagnostics (make-hash-table :test 'equal))
   3178 
   3179   ;; contains all the workDone progress tokens that have been created
   3180   ;; for the current workspace.
   3181   (work-done-tokens (make-hash-table :test 'equal)))
   3182 
   3183 
   3184 (cl-defstruct lsp-session
   3185   ;; contains the folders that are part of the current session
   3186   folders
   3187   ;; contains the folders that must not be imported in the current workspace.
   3188   folders-blocklist
   3189   ;; contains the list of folders that must be imported in a project in case of
   3190   ;; multi root LSP server.
   3191   (server-id->folders (make-hash-table :test 'equal))
   3192   ;; folder to list of the servers that are associated with the folder.
   3193   (folder->servers (make-hash-table :test 'equal))
   3194   ;; ‘metadata’ is a generic storage for workspace specific data. It is
   3195   ;; accessed via `lsp-workspace-set-metadata' and `lsp-workspace-set-metadata'
   3196   (metadata (make-hash-table :test 'equal)))
   3197 
   3198 (defun lsp-workspace-status (status-string &optional workspace)
   3199   "Set current workspace status to STATUS-STRING.
   3200 If WORKSPACE is not specified defaults to lsp--cur-workspace."
   3201   (let ((status-string (when status-string (replace-regexp-in-string "%" "%%" status-string))))
   3202     (setf (lsp--workspace-status-string (or workspace lsp--cur-workspace)) status-string)))
   3203 
   3204 (defun lsp-session-set-metadata (key value &optional _workspace)
   3205   "Associate KEY with VALUE in the WORKSPACE metadata.
   3206 If WORKSPACE is not provided current workspace will be used."
   3207   (puthash key value (lsp-session-metadata (lsp-session))))
   3208 
   3209 (defalias 'lsp-workspace-set-metadata 'lsp-session-set-metadata)
   3210 
   3211 (defun lsp-session-get-metadata (key &optional _workspace)
   3212   "Lookup KEY in WORKSPACE metadata.
   3213 If WORKSPACE is not provided current workspace will be used."
   3214   (gethash key (lsp-session-metadata (lsp-session))))
   3215 
   3216 (defalias 'lsp-workspace-get-metadata 'lsp-session-get-metadata)
   3217 
   3218 (defun lsp-workspace-set-work-done-token (token value workspace)
   3219   "Associate TOKEN with VALUE in the WORKSPACE work-done-tokens."
   3220   (puthash token value (lsp--workspace-work-done-tokens workspace)))
   3221 
   3222 (defun lsp-workspace-get-work-done-token (token workspace)
   3223   "Lookup TOKEN in the WORKSPACE work-done-tokens."
   3224   (gethash token (lsp--workspace-work-done-tokens workspace)))
   3225 
   3226 (defun lsp-workspace-rem-work-done-token (token workspace)
   3227   "Remove TOKEN from the WORKSPACE work-done-tokens."
   3228   (remhash token (lsp--workspace-work-done-tokens workspace)))
   3229 
   3230 
   3231 (defun lsp--make-notification (method &optional params)
   3232   "Create notification body for method METHOD and parameters PARAMS."
   3233   (list :jsonrpc "2.0" :method method :params params))
   3234 
   3235 (defalias 'lsp--make-request 'lsp--make-notification)
   3236 (defalias 'lsp-make-request 'lsp--make-notification)
   3237 
   3238 (defun lsp--make-response (id result)
   3239   "Create response for REQUEST with RESULT."
   3240   `(:jsonrpc "2.0" :id ,id :result ,result))
   3241 
   3242 (defun lsp-make-notification (method &optional params)
   3243   "Create notification body for method METHOD and parameters PARAMS."
   3244   (lsp--make-notification method params))
   3245 
   3246 (defmacro lsp--json-serialize (params)
   3247   (if (progn
   3248         (require 'json)
   3249         (fboundp 'json-serialize))
   3250       `(json-serialize ,params
   3251                        :null-object nil
   3252                        :false-object :json-false)
   3253     `(let ((json-false :json-false))
   3254        (json-encode ,params))))
   3255 
   3256 (defun lsp--make-message (params)
   3257   "Create a LSP message from PARAMS, after encoding it to a JSON string."
   3258   (let ((body (lsp--json-serialize params)))
   3259     (concat "Content-Length: "
   3260             (number-to-string (1+ (string-bytes body)))
   3261             "\r\n\r\n"
   3262             body
   3263             "\n")))
   3264 
   3265 (cl-defstruct lsp--log-entry timestamp process-time type method id body)
   3266 
   3267 (defun lsp--make-log-entry (method id body type &optional process-time)
   3268   "Create an outgoing log object from BODY with method METHOD and id ID.
   3269 If ID is non-nil, then the body is assumed to be a notification.
   3270 TYPE can either be `incoming' or `outgoing'"
   3271   (cl-assert (memq type '(incoming-req outgoing-req incoming-notif
   3272                                        outgoing-notif incoming-resp
   3273                                        outgoing-resp)))
   3274   (make-lsp--log-entry
   3275    :timestamp (format-time-string "%I:%M:%S %p")
   3276    :process-time process-time
   3277    :method method
   3278    :id id
   3279    :type type
   3280    :body body))
   3281 
   3282 (defun lsp--log-font-lock-json (body)
   3283   "Font lock JSON BODY."
   3284   (with-temp-buffer
   3285     (insert body)
   3286     ;; We set the temp buffer file-name extension to .json and call `set-auto-mode'
   3287     ;; so the users configured json mode is used which could be
   3288     ;; `json-mode', `json-ts-mode', `jsonian-mode', etc.
   3289     (let ((buffer-file-name "lsp-log.json"))
   3290       (delay-mode-hooks
   3291         (set-auto-mode)
   3292         (if (fboundp 'font-lock-ensure)
   3293             (font-lock-ensure)
   3294           (with-no-warnings
   3295             (font-lock-fontify-buffer)))))
   3296     (buffer-string)))
   3297 
   3298 (defun lsp--log-entry-pp (entry)
   3299   (cl-assert (lsp--log-entry-p entry))
   3300   (pcase-let (((cl-struct lsp--log-entry timestamp method id type process-time
   3301                           body)
   3302                entry)
   3303               (json-false :json-false)
   3304               (json-encoding-pretty-print t)
   3305               (str nil))
   3306     (setq str
   3307           (concat (format "[Trace - %s] " timestamp)
   3308                   (pcase type
   3309                     ('incoming-req (format "Received request '%s - (%s)." method id))
   3310                     ('outgoing-req (format "Sending request '%s - (%s)'." method id))
   3311 
   3312                     ('incoming-notif (format "Received notification '%s'." method))
   3313                     ('outgoing-notif (format "Sending notification '%s'." method))
   3314 
   3315                     ('incoming-resp (format "Received response '%s - (%s)' in %dms."
   3316                                             method id process-time))
   3317                     ('outgoing-resp
   3318                      (format
   3319                       "Sending response '%s - (%s)'. Processing request took %dms"
   3320                       method id process-time)))
   3321                   "\n"
   3322                   (if (memq type '(incoming-resp ougoing-resp))
   3323                       "Result: "
   3324                     "Params: ")
   3325                   (lsp--log-font-lock-json (json-encode body))
   3326                   "\n\n\n"))
   3327     (setq str (propertize str 'mouse-face 'highlight 'read-only t))
   3328     (insert str)))
   3329 
   3330 (defvar-local lsp--log-io-ewoc nil)
   3331 
   3332 (defun lsp--get-create-io-ewoc (workspace)
   3333   (if (and (lsp--workspace-ewoc workspace)
   3334            (buffer-live-p (ewoc-buffer (lsp--workspace-ewoc workspace))))
   3335       (lsp--workspace-ewoc workspace)
   3336     (with-current-buffer (lsp--get-log-buffer-create workspace)
   3337       (unless (eq 'lsp-log-io-mode major-mode) (lsp-log-io-mode))
   3338       (setq-local window-point-insertion-type t)
   3339       (setq lsp--log-io-ewoc (ewoc-create #'lsp--log-entry-pp nil nil t))
   3340       (setf (lsp--workspace-ewoc workspace) lsp--log-io-ewoc))
   3341     (lsp--workspace-ewoc workspace)))
   3342 
   3343 (defun lsp--ewoc-count (ewoc)
   3344   (let* ((count 0)
   3345          (count-fn (lambda (_) (setq count (1+ count)))))
   3346     (ewoc-map count-fn ewoc)
   3347     count))
   3348 
   3349 (defun lsp--log-entry-new (entry workspace)
   3350   (let* ((ewoc (lsp--get-create-io-ewoc workspace))
   3351          (count (and (not (eq lsp-io-messages-max t)) (lsp--ewoc-count ewoc)))
   3352          (node (if (or (eq lsp-io-messages-max t)
   3353                        (>= lsp-io-messages-max count))
   3354                    nil
   3355                  (ewoc-nth ewoc (1- lsp-io-messages-max))))
   3356          (prev nil)
   3357          (inhibit-read-only t))
   3358     (while node
   3359       (setq prev (ewoc-prev ewoc node))
   3360       (ewoc-delete ewoc node)
   3361       (setq node prev))
   3362     (ewoc-enter-last ewoc entry)))
   3363 
   3364 (defun lsp--send-notification (body)
   3365   "Send BODY as a notification to the language server."
   3366   (lsp-foreach-workspace
   3367    (when (lsp--log-io-p (plist-get body :method))
   3368      (lsp--log-entry-new (lsp--make-log-entry
   3369                           (plist-get body :method)
   3370                           nil (plist-get body :params) 'outgoing-notif)
   3371                          lsp--cur-workspace))
   3372    (lsp--send-no-wait body
   3373                       (lsp--workspace-proc lsp--cur-workspace))))
   3374 
   3375 (defalias 'lsp-send-notification 'lsp--send-notification)
   3376 
   3377 (defun lsp-notify (method params)
   3378   "Send notification METHOD with PARAMS."
   3379   (lsp--send-notification (lsp--make-notification method params)))
   3380 
   3381 (defun lsp--cur-workspace-check ()
   3382   "Check whether buffer lsp workspace(s) are set."
   3383   (cl-assert (lsp-workspaces) nil
   3384              "No language server(s) is associated with this buffer."))
   3385 
   3386 (defun lsp--send-request (body &optional no-wait no-merge)
   3387   "Send BODY as a request to the language server, get the response.
   3388 If NO-WAIT is non-nil, don't synchronously wait for a response.
   3389 If NO-MERGE is non-nil, don't merge the results but return an
   3390 alist mapping workspace->result."
   3391   (lsp-request (plist-get body :method)
   3392                (plist-get body :params)
   3393                :no-wait no-wait
   3394                :no-merge no-merge))
   3395 
   3396 (defalias 'lsp-send-request 'lsp--send-request
   3397   "Send BODY as a request to the language server and return the response
   3398 synchronously.
   3399 \n(fn BODY)")
   3400 
   3401 (cl-defun lsp-request (method params &key no-wait no-merge)
   3402   "Send request METHOD with PARAMS.
   3403 If NO-MERGE is non-nil, don't merge the results but return alist
   3404 workspace->result.
   3405 If NO-WAIT is non-nil send the request as notification."
   3406   (if no-wait
   3407       (lsp-notify method params)
   3408     (let* ((send-time (float-time))
   3409            ;; max time by which we must get a response
   3410            (expected-time
   3411             (and
   3412              lsp-response-timeout
   3413              (+ send-time lsp-response-timeout)))
   3414            resp-result resp-error done?)
   3415       (unwind-protect
   3416           (progn
   3417             (lsp-request-async method params
   3418                                (lambda (res) (setf resp-result (or res :finished)) (throw 'lsp-done '_))
   3419                                :error-handler (lambda (err) (setf resp-error err) (throw 'lsp-done '_))
   3420                                :no-merge no-merge
   3421                                :mode 'detached
   3422                                :cancel-token :sync-request)
   3423             (while (not (or resp-error resp-result))
   3424               (if (functionp 'json-rpc-connection)
   3425                   (catch 'lsp-done (sit-for 0.01))
   3426                 (catch 'lsp-done
   3427                   (accept-process-output
   3428                    nil
   3429                    (if expected-time (- expected-time send-time) 1))))
   3430               (setq send-time (float-time))
   3431               (when (and expected-time (< expected-time send-time))
   3432                 (error "Timeout while waiting for response.  Method: %s" method)))
   3433             (setq done? t)
   3434             (cond
   3435              ((eq resp-result :finished) nil)
   3436              (resp-result resp-result)
   3437              ((lsp-json-error? resp-error) (error (lsp:json-error-message resp-error)))
   3438              ((lsp-json-error? (cl-first resp-error))
   3439               (error (lsp:json-error-message (cl-first resp-error))))))
   3440         (unless done?
   3441           (lsp-cancel-request-by-token :sync-request))))))
   3442 
   3443 (cl-defun lsp-request-while-no-input (method params)
   3444   "Send request METHOD with PARAMS and waits until there is no input.
   3445 Return same value as `lsp--while-no-input' and respecting `non-essential'."
   3446   (if (or non-essential (not lsp-request-while-no-input-may-block))
   3447       (let* ((send-time (float-time))
   3448              ;; max time by which we must get a response
   3449              (expected-time
   3450               (and
   3451                lsp-response-timeout
   3452                (+ send-time lsp-response-timeout)))
   3453              resp-result resp-error done?)
   3454         (unwind-protect
   3455             (progn
   3456               (lsp-request-async method params
   3457                                  (lambda (res) (setf resp-result (or res :finished)) (throw 'lsp-done '_))
   3458                                  :error-handler (lambda (err) (setf resp-error err) (throw 'lsp-done '_))
   3459                                  :mode 'detached
   3460                                  :cancel-token :sync-request)
   3461               (while (not (or resp-error resp-result (input-pending-p)))
   3462                 (catch 'lsp-done
   3463                   (sit-for
   3464                    (if expected-time (- expected-time send-time) 1)))
   3465                 (setq send-time (float-time))
   3466                 (when (and expected-time (< expected-time send-time))
   3467                   (error "Timeout while waiting for response.  Method: %s" method)))
   3468               (setq done? (or resp-error resp-result))
   3469               (cond
   3470                ((eq resp-result :finished) nil)
   3471                (resp-result resp-result)
   3472                ((lsp-json-error? resp-error) (error (lsp:json-error-message resp-error)))
   3473                ((lsp-json-error? (cl-first resp-error))
   3474                 (error (lsp:json-error-message (cl-first resp-error))))))
   3475           (unless done?
   3476             (lsp-cancel-request-by-token :sync-request))
   3477           (when (and (input-pending-p) lsp--throw-on-input)
   3478             (throw 'input :interrupted))))
   3479     (lsp-request method params)))
   3480 
   3481 (defvar lsp--cancelable-requests (ht))
   3482 
   3483 (cl-defun lsp-request-async (method params callback
   3484                                     &key mode error-handler cancel-handler no-merge cancel-token)
   3485   "Send METHOD with PARAMS as a request to the language server.
   3486 Call CALLBACK with the response received from the server
   3487 asynchronously.
   3488 MODE determines when the callback will be called depending on the
   3489 condition of the original buffer.  It could be:
   3490 - `detached' which means that the callback will be executed no
   3491 matter what has happened to the buffer.
   3492 - `alive' - the callback will be executed only if the buffer from
   3493 which the call was executed is still alive.
   3494 - `current' the callback will be executed only if the original buffer
   3495 is still selected.
   3496 - `tick' - the callback will be executed only if the buffer was not modified.
   3497 - `unchanged' - the callback will be executed only if the buffer hasn't
   3498 changed and if the buffer is not modified.
   3499 
   3500 ERROR-HANDLER will be called in case the request has failed.
   3501 CANCEL-HANDLER will be called in case the request is being canceled.
   3502 If NO-MERGE is non-nil, don't merge the results but return alist
   3503 workspace->result.
   3504 CANCEL-TOKEN is the token that can be used to cancel request."
   3505   (lsp--send-request-async `(:jsonrpc "2.0" :method ,method :params ,params)
   3506                            callback mode error-handler cancel-handler no-merge cancel-token))
   3507 
   3508 (defun lsp--create-request-cancel (id workspaces hook buf method cancel-callback)
   3509   (lambda (&rest _)
   3510     (unless (and (equal 'post-command-hook hook)
   3511                  (equal (current-buffer) buf))
   3512       (lsp--request-cleanup-hooks id)
   3513       (with-lsp-workspaces workspaces
   3514         (lsp--cancel-request id)
   3515         (when cancel-callback (funcall cancel-callback)))
   3516       (lsp-log "Cancelling %s(%s) in hook %s" method id hook))))
   3517 
   3518 (defun lsp--create-async-callback
   3519     (callback method no-merge workspaces)
   3520   "Create async handler expecting COUNT results, merge them and call CALLBACK.
   3521 MODE determines when the callback will be called depending on the
   3522 condition of the original buffer. METHOD is the invoked method.
   3523 If NO-MERGE is non-nil, don't merge the results but return alist
   3524 workspace->result. ID is the request id."
   3525   (let (results errors)
   3526     (lambda (result)
   3527       (push (cons lsp--cur-workspace result)
   3528             (if (eq result :error) errors results))
   3529       (when (and (not (eq (length errors) (length workspaces)))
   3530                  (eq (+ (length errors) (length results)) (length workspaces)))
   3531         (funcall callback
   3532                  (if no-merge
   3533                      results
   3534                    (lsp--merge-results (-map #'cl-rest results) method)))))))
   3535 
   3536 (defcustom lsp-default-create-error-handler-fn nil
   3537   "Default error handler customization.
   3538 Handler should give METHOD as argument and return function of one argument
   3539 ERROR."
   3540   :type 'function
   3541   :group 'lsp-mode
   3542   :package-version '(lsp-mode . "9.0.0"))
   3543 
   3544 (defun lsp--create-default-error-handler (method)
   3545   "Default error handler.
   3546 METHOD is the executed method."
   3547   (if lsp-default-create-error-handler-fn
   3548       (funcall lsp-default-create-error-handler-fn method)
   3549     (lambda (error)
   3550       (lsp--warn "%s" (or (lsp--error-string error)
   3551                           (format "%s Request has failed" method))))))
   3552 
   3553 (defvar lsp--request-cleanup-hooks (ht))
   3554 
   3555 (defun lsp--request-cleanup-hooks (request-id)
   3556   (when-let* ((cleanup-function (gethash request-id lsp--request-cleanup-hooks)))
   3557     (funcall cleanup-function)
   3558     (remhash request-id lsp--request-cleanup-hooks)))
   3559 
   3560 (defun lsp-cancel-request-by-token (cancel-token)
   3561   "Cancel request using CANCEL-TOKEN."
   3562   (-when-let ((request-id . workspaces) (gethash cancel-token lsp--cancelable-requests))
   3563     (with-lsp-workspaces workspaces
   3564       (lsp--cancel-request request-id))
   3565     (remhash cancel-token lsp--cancelable-requests)
   3566     (lsp--request-cleanup-hooks request-id)))
   3567 
   3568 (defun lsp--send-request-async (body callback
   3569                                      &optional mode error-callback cancel-callback
   3570                                      no-merge cancel-token)
   3571   "Send BODY as a request to the language server.
   3572 Call CALLBACK with the response received from the server
   3573 asynchronously.
   3574 MODE determines when the callback will be called depending on the
   3575 condition of the original buffer.  It could be:
   3576 - `detached' which means that the callback will be executed no
   3577 matter what has happened to the buffer.
   3578 - `alive' - the callback will be executed only if the buffer from
   3579 which the call was executed is still alive.
   3580 - `current' the callback will be executed only if the original buffer
   3581 is still selected.
   3582 - `tick' - the callback will be executed only if the buffer was not modified.
   3583 - `unchanged' - the callback will be executed only if the buffer hasn't
   3584 changed and if the buffer is not modified.
   3585 
   3586 ERROR-CALLBACK will be called in case the request has failed.
   3587 CANCEL-CALLBACK will be called in case the request is being canceled.
   3588 If NO-MERGE is non-nil, don't merge the results but return alist
   3589 workspace->result.
   3590 CANCEL-TOKEN is the token that can be used to cancel request."
   3591   (when cancel-token
   3592     (lsp-cancel-request-by-token cancel-token))
   3593 
   3594   (if-let* ((target-workspaces (lsp--find-workspaces-for body)))
   3595       (let* ((start-time (current-time))
   3596              (method (plist-get body :method))
   3597              (id (cl-incf lsp-last-id))
   3598              (buf (current-buffer))
   3599              (cancel-callback (when cancel-callback
   3600                                 (pcase mode
   3601                                   ((or 'alive 'tick 'unchanged)
   3602                                    (lambda ()
   3603                                      (with-current-buffer buf
   3604                                        (funcall cancel-callback))))
   3605                                   (_ cancel-callback))))
   3606              ;; calculate what are the (hook . local) pairs which will cancel
   3607              ;; the request
   3608              (hooks (pcase mode
   3609                       ('alive     '((kill-buffer-hook . t)))
   3610                       ('tick      '((kill-buffer-hook . t) (after-change-functions . t)))
   3611                       ('unchanged '((after-change-functions . t) (post-command-hook . nil)))
   3612                       ('current   '((post-command-hook . nil)))))
   3613              ;; note: lambdas in emacs can be compared but we should make sure
   3614              ;; that all of the captured arguments are the same - in our case
   3615              ;; `lsp--create-request-cancel' will return the same lambda when
   3616              ;; called with the same params.
   3617              (cleanup-hooks
   3618               (lambda () (mapc
   3619                           (-lambda ((hook . local))
   3620                             (if local
   3621                                 (when (buffer-live-p buf)
   3622                                   (with-current-buffer buf
   3623                                     (remove-hook hook
   3624                                                  (lsp--create-request-cancel
   3625                                                   id target-workspaces hook buf method cancel-callback)
   3626                                                  t)))
   3627                               (remove-hook hook (lsp--create-request-cancel
   3628                                                  id target-workspaces hook buf method cancel-callback))))
   3629                           hooks)
   3630                 (remhash cancel-token lsp--cancelable-requests)))
   3631              (callback (pcase mode
   3632                          ((or 'alive 'tick 'unchanged) (lambda (&rest args)
   3633                                                          (with-current-buffer buf
   3634                                                            (apply callback args))))
   3635                          (_ callback)))
   3636              (callback (lsp--create-async-callback callback
   3637                                                    method
   3638                                                    no-merge
   3639                                                    target-workspaces))
   3640              (callback (lambda (result)
   3641                          (lsp--request-cleanup-hooks id)
   3642                          (funcall callback result)))
   3643              (error-callback (lsp--create-async-callback
   3644                               (or error-callback
   3645                                   (lsp--create-default-error-handler method))
   3646                               method
   3647                               nil
   3648                               target-workspaces))
   3649              (error-callback (lambda (error)
   3650                                (funcall callback :error)
   3651                                (lsp--request-cleanup-hooks id)
   3652                                (funcall error-callback error)))
   3653              (body (plist-put body :id id)))
   3654 
   3655         ;; cancel request in any of the hooks
   3656         (mapc (-lambda ((hook . local))
   3657                 (add-hook hook
   3658                           (lsp--create-request-cancel
   3659                            id target-workspaces hook buf method cancel-callback)
   3660                           nil local))
   3661               hooks)
   3662         (puthash id cleanup-hooks lsp--request-cleanup-hooks)
   3663 
   3664         (setq lsp--last-active-workspaces target-workspaces)
   3665 
   3666         (when cancel-token
   3667           (puthash cancel-token (cons id target-workspaces) lsp--cancelable-requests))
   3668 
   3669         (seq-doseq (workspace target-workspaces)
   3670           (when (lsp--log-io-p method)
   3671             (lsp--log-entry-new (lsp--make-log-entry method id
   3672                                                      (plist-get body :params)
   3673                                                      'outgoing-req)
   3674                                 workspace))
   3675           (puthash id
   3676                    (list callback error-callback method start-time (current-time))
   3677                    (-> workspace
   3678                        (lsp--workspace-client)
   3679                        (lsp--client-response-handlers)))
   3680           (lsp--send-no-wait body (lsp--workspace-proc workspace)))
   3681         body)
   3682     (error "The connected server(s) does not support method %s.
   3683 To find out what capabilities support your server use `M-x lsp-describe-session'
   3684 and expand the capabilities section"
   3685            (plist-get body :method))))
   3686 
   3687 ;; deprecated, use lsp-request-async.
   3688 (defalias 'lsp-send-request-async 'lsp--send-request-async)
   3689 (make-obsolete 'lsp-send-request-async 'lsp-request-async "lsp-mode 7.0.1")
   3690 
   3691 ;; Clean up the entire state of lsp mode when Emacs is killed, to get rid of any
   3692 ;; pending language servers.
   3693 (add-hook 'kill-emacs-hook #'lsp--global-teardown)
   3694 
   3695 (defun lsp--global-teardown ()
   3696   "Unload working workspaces."
   3697   (lsp-foreach-workspace (lsp--shutdown-workspace)))
   3698 
   3699 (defun lsp--shutdown-workspace (&optional restart)
   3700   "Shut down the language server process for ‘lsp--cur-workspace’."
   3701   (with-demoted-errors "LSP error: %S"
   3702     (let ((lsp-response-timeout 0.5))
   3703       (condition-case err
   3704           (lsp-request "shutdown" nil)
   3705         (error (lsp--error "%s" err))))
   3706     (lsp-notify "exit" nil))
   3707   (setf (lsp--workspace-shutdown-action lsp--cur-workspace) (or (and restart 'restart) 'shutdown))
   3708   (lsp--uninitialize-workspace))
   3709 
   3710 (defcustom lsp-inlay-hint-enable nil
   3711   "If non-nil it will enable inlay hints."
   3712   :type 'boolean
   3713   :group 'lsp-mode
   3714   :package-version '(lsp-mode . "9.0.0"))
   3715 
   3716 (defun lsp--uninitialize-workspace ()
   3717   "Cleanup buffer state.
   3718 When a workspace is shut down, by request or from just
   3719 disappearing, unset all the variables related to it."
   3720   (-let [(&lsp-wks 'cmd-proc 'buffers) lsp--cur-workspace]
   3721     (lsp-process-kill cmd-proc)
   3722     (mapc (lambda (buf)
   3723             (when (lsp-buffer-live-p buf)
   3724               (lsp-with-current-buffer buf
   3725                                        (lsp-managed-mode -1))))
   3726           buffers)
   3727     (lsp-diagnostics--workspace-cleanup lsp--cur-workspace)))
   3728 
   3729 (defun lsp--client-capabilities (&optional custom-capabilities)
   3730   "Return the client capabilities appending CUSTOM-CAPABILITIES."
   3731   (append
   3732    `((general . ((positionEncodings . ["utf-32", "utf-16"])))
   3733      (workspace . ((workspaceEdit . ((documentChanges . t)
   3734                                      (resourceOperations . ["create" "rename" "delete"])))
   3735                    (applyEdit . t)
   3736                    (symbol . ((symbolKind . ((valueSet . ,(apply 'vector (number-sequence 1 26)))))))
   3737                    (executeCommand . ((dynamicRegistration . :json-false)))
   3738                    ,@(when lsp-enable-file-watchers '((didChangeWatchedFiles . ((dynamicRegistration . t)))))
   3739                    (workspaceFolders . t)
   3740                    (configuration . t)
   3741                    ,@(when lsp-semantic-tokens-enable
   3742                        `((semanticTokens . ((refreshSupport . ,(or (and (boundp 'lsp-semantic-tokens-honor-refresh-requests)
   3743                                                                         lsp-semantic-tokens-honor-refresh-requests)
   3744                                                                    :json-false))))))
   3745                    ,@(when lsp-lens-enable '((codeLens . ((refreshSupport . t)))))
   3746                    ,@(when lsp-inlay-hint-enable '((inlayHint . ((refreshSupport . :json-false)))))
   3747                    (diagnostics . ((refreshSupport . :json-false)))
   3748                    (fileOperations . ((didCreate . :json-false)
   3749                                       (willCreate . :json-false)
   3750                                       (didRename . t)
   3751                                       (willRename . t)
   3752                                       (didDelete . :json-false)
   3753                                       (willDelete . :json-false)))))
   3754      (textDocument . ((declaration . ((dynamicRegistration . t)
   3755                                       (linkSupport . t)))
   3756                       (definition . ((dynamicRegistration . t)
   3757                                      (linkSupport . t)))
   3758                       (references . ((dynamicRegistration . t)))
   3759                       (implementation . ((dynamicRegistration . t)
   3760                                          (linkSupport . t)))
   3761                       (typeDefinition . ((dynamicRegistration . t)
   3762                                          (linkSupport . t)))
   3763                       (synchronization . ((willSave . t) (didSave . t) (willSaveWaitUntil . t)))
   3764                       (documentSymbol . ((symbolKind . ((valueSet . ,(apply 'vector (number-sequence 1 26)))))
   3765                                          (hierarchicalDocumentSymbolSupport . t)))
   3766                       (formatting . ((dynamicRegistration . t)))
   3767                       (rangeFormatting . ((dynamicRegistration . t)))
   3768                       (onTypeFormatting . ((dynamicRegistration . t)))
   3769                       ,@(when (and lsp-semantic-tokens-enable
   3770                                    (functionp 'lsp--semantic-tokens-capabilities))
   3771                           (lsp--semantic-tokens-capabilities))
   3772                       (rename . ((dynamicRegistration . t) (prepareSupport . t)))
   3773                       (codeAction . ((dynamicRegistration . t)
   3774                                      (isPreferredSupport . t)
   3775                                      (codeActionLiteralSupport . ((codeActionKind . ((valueSet . [""
   3776                                                                                                   "quickfix"
   3777                                                                                                   "refactor"
   3778                                                                                                   "refactor.extract"
   3779                                                                                                   "refactor.inline"
   3780                                                                                                   "refactor.rewrite"
   3781                                                                                                   "source"
   3782                                                                                                   "source.organizeImports"])))))
   3783                                      (resolveSupport . ((properties . ["edit" "command"])))
   3784                                      (dataSupport . t)))
   3785                       (completion . ((completionItem . ((snippetSupport . ,(cond
   3786                                                                             ((and lsp-enable-snippet (not (fboundp 'yas-minor-mode)))
   3787                                                                              (lsp--warn (concat
   3788                                                                                          "Yasnippet is not installed, but `lsp-enable-snippet' is set to `t'. "
   3789                                                                                          "You must either install yasnippet, or disable snippet support."))
   3790                                                                              :json-false)
   3791                                                                             (lsp-enable-snippet t)
   3792                                                                             (t :json-false)))
   3793                                                         (documentationFormat . ["markdown" "plaintext"])
   3794                                                         ;; Remove this after jdtls support resolveSupport
   3795                                                         (resolveAdditionalTextEditsSupport . t)
   3796                                                         (insertReplaceSupport . t)
   3797                                                         (deprecatedSupport . t)
   3798                                                         (resolveSupport
   3799                                                          . ((properties . ["documentation"
   3800                                                                            "detail"
   3801                                                                            "additionalTextEdits"
   3802                                                                            "command"
   3803                                                                            "insertTextFormat"
   3804                                                                            "insertTextMode"])))
   3805                                                         (insertTextModeSupport . ((valueSet . [1 2])))))
   3806                                      (contextSupport . t)
   3807                                      (dynamicRegistration . t)))
   3808                       (signatureHelp . ((signatureInformation . ((parameterInformation . ((labelOffsetSupport . t)))))
   3809                                         (dynamicRegistration . t)))
   3810                       (documentLink . ((dynamicRegistration . t)
   3811                                        (tooltipSupport . t)))
   3812                       (hover . ((contentFormat . ["markdown" "plaintext"])
   3813                                 (dynamicRegistration . t)))
   3814                       ,@(when lsp-enable-folding
   3815                           `((foldingRange . ((dynamicRegistration . t)
   3816                                              ,@(when lsp-folding-range-limit
   3817                                                  `((rangeLimit . ,lsp-folding-range-limit)))
   3818                                              ,@(when lsp-folding-line-folding-only
   3819                                                  `((lineFoldingOnly . t)))))))
   3820                       (selectionRange . ((dynamicRegistration . t)))
   3821                       (callHierarchy . ((dynamicRegistration . :json-false)))
   3822                       (typeHierarchy . ((dynamicRegistration . t)))
   3823                       (publishDiagnostics . ((relatedInformation . t)
   3824                                              (tagSupport . ((valueSet . [1 2])))
   3825                                              (versionSupport . t)))
   3826                       (diagnostic . ((dynamicRegistration . :json-false)
   3827                                      (relatedDocumentSupport . :json-false)))
   3828                       (linkedEditingRange . ((dynamicRegistration . t)))))
   3829      (window . ((workDoneProgress . t)
   3830                 (showDocument . ((support . t))))))
   3831    custom-capabilities))
   3832 
   3833 (defun lsp-find-roots-for-workspace (workspace session)
   3834   "Get all roots for the WORKSPACE."
   3835   (-filter #'identity (ht-map (lambda (folder workspaces)
   3836                                 (when (-contains? workspaces workspace)
   3837                                   folder))
   3838                               (lsp-session-folder->servers session))))
   3839 
   3840 (defun lsp-session-watches (&optional session)
   3841   "Get watches created for SESSION."
   3842   (or (gethash "__watches" (lsp-session-metadata (or session (lsp-session))))
   3843       (-let [res (make-hash-table :test 'equal)]
   3844         (puthash "__watches" res (lsp-session-metadata (or session (lsp-session))))
   3845         res)))
   3846 
   3847 (defun lsp--file-process-event (session root-folder event)
   3848   "Process file event."
   3849   (let* ((changed-file (cl-third event))
   3850          (rel-changed-file (f-relative changed-file root-folder))
   3851          (event-numeric-kind (alist-get (cl-second event) lsp--file-change-type))
   3852          (bit-position (1- event-numeric-kind))
   3853          (watch-bit (ash 1 bit-position)))
   3854     (->>
   3855      session
   3856      lsp-session-folder->servers
   3857      (gethash root-folder)
   3858      (seq-do (lambda (workspace)
   3859                (when (->>
   3860                       workspace
   3861                       lsp--workspace-registered-server-capabilities
   3862                       (-any?
   3863                        (lambda (capability)
   3864                          (and
   3865                           (equal (lsp--registered-capability-method capability)
   3866                                  "workspace/didChangeWatchedFiles")
   3867                           (->>
   3868                            capability
   3869                            lsp--registered-capability-options
   3870                            (lsp:did-change-watched-files-registration-options-watchers)
   3871                            (seq-find
   3872                             (-lambda ((fs-watcher &as &FileSystemWatcher :glob-pattern :kind? :_cachedRegexp cached-regexp))
   3873                               (when (or (null kind?)
   3874                                         (> (logand kind? watch-bit) 0))
   3875                                 (-let [regexes (or cached-regexp
   3876                                                    (let ((regexp (lsp-glob-to-regexps glob-pattern)))
   3877                                                      (lsp-put fs-watcher :_cachedRegexp regexp)
   3878                                                      regexp))]
   3879                                   (-any? (lambda (re)
   3880                                            (or (string-match re changed-file)
   3881                                                (string-match re rel-changed-file)))
   3882                                          regexes))))))))))
   3883                  (with-lsp-workspace workspace
   3884                    (lsp-notify
   3885                     "workspace/didChangeWatchedFiles"
   3886                     `((changes . [((type . ,event-numeric-kind)
   3887                                    (uri . ,(lsp--path-to-uri changed-file)))]))))))))))
   3888 
   3889 (lsp-defun lsp--server-register-capability ((&Registration :method :id :register-options?))
   3890   "Register capability REG."
   3891   (when (and lsp-enable-file-watchers
   3892              (equal method "workspace/didChangeWatchedFiles"))
   3893     (-let* ((created-watches (lsp-session-watches (lsp-session)))
   3894             (root-folders (cl-set-difference
   3895                            (lsp-find-roots-for-workspace lsp--cur-workspace (lsp-session))
   3896                            (ht-keys created-watches))))
   3897       ;; create watch for each root folder without such
   3898       (dolist (folder root-folders)
   3899         (let* ((watch (make-lsp-watch :root-directory folder))
   3900                (ignored-things (lsp--get-ignored-regexes-for-workspace-root folder))
   3901                (ignored-files-regex-list (car ignored-things))
   3902                (ignored-directories-regex-list (cadr ignored-things)))
   3903           (puthash folder watch created-watches)
   3904           (lsp-watch-root-folder (file-truename folder)
   3905                                  (-partial #'lsp--file-process-event (lsp-session) folder)
   3906                                  ignored-files-regex-list
   3907                                  ignored-directories-regex-list
   3908                                  watch
   3909                                  t)))))
   3910 
   3911   (push
   3912    (make-lsp--registered-capability :id id :method method :options register-options?)
   3913    (lsp--workspace-registered-server-capabilities lsp--cur-workspace)))
   3914 
   3915 (defmacro lsp--with-workspace-temp-buffer (workspace-root &rest body)
   3916   "With a temp-buffer under `WORKSPACE-ROOT' and evaluate `BODY', useful to
   3917 access dir-local variables."
   3918   (declare (indent 1) (debug t))
   3919   `(with-temp-buffer
   3920      ;; Set the buffer's name to something under the root so that we can hack the local variables
   3921      ;; This file doesn't need to exist and will not be created due to this.
   3922      (setq-local buffer-file-name (expand-file-name "lsp-mode-temp" (expand-file-name ,workspace-root)))
   3923      (hack-local-variables)
   3924      (prog1 ,@body
   3925        (setq-local buffer-file-name nil))))
   3926 
   3927 (defun lsp--get-ignored-regexes-for-workspace-root (workspace-root)
   3928   "Return a list of the form
   3929 (lsp-file-watch-ignored-files lsp-file-watch-ignored-directories) for the given
   3930 WORKSPACE-ROOT."
   3931   ;; The intent of this function is to provide per-root workspace-level customization of the
   3932   ;; lsp-file-watch-ignored-directories and lsp-file-watch-ignored-files variables.
   3933   (lsp--with-workspace-temp-buffer workspace-root
   3934     (list lsp-file-watch-ignored-files (lsp-file-watch-ignored-directories))))
   3935 
   3936 
   3937 (defun lsp--cleanup-hanging-watches ()
   3938   "Cleanup watches in case there are no more workspaces that are interested
   3939 in that particular folder."
   3940   (let* ((session (lsp-session))
   3941          (watches (lsp-session-watches session)))
   3942     (dolist (watched-folder (ht-keys watches))
   3943       (when (-none? (lambda (workspace)
   3944                       (with-lsp-workspace workspace
   3945                         (lsp--registered-capability "workspace/didChangeWatchedFiles")))
   3946                     (gethash watched-folder (lsp-session-folder->servers (lsp-session))))
   3947         (lsp-log "Cleaning up watches for folder %s. There is no workspace watching this folder..." watched-folder)
   3948         (lsp-kill-watch (gethash watched-folder watches))
   3949         (remhash watched-folder watches)))))
   3950 
   3951 (lsp-defun lsp--server-unregister-capability ((&Unregistration :id :method))
   3952   "Unregister capability UNREG."
   3953   (setf (lsp--workspace-registered-server-capabilities lsp--cur-workspace)
   3954         (seq-remove (lambda (e) (equal (lsp--registered-capability-id e) id))
   3955                     (lsp--workspace-registered-server-capabilities lsp--cur-workspace)))
   3956   (when (equal method "workspace/didChangeWatchedFiles")
   3957     (lsp--cleanup-hanging-watches)))
   3958 
   3959 (defun lsp--server-capabilities ()
   3960   "Return the capabilities of the language server associated with the buffer."
   3961   (->> (lsp-workspaces)
   3962        (-keep #'lsp--workspace-server-capabilities)
   3963        (apply #'lsp-merge)))
   3964 
   3965 (defun lsp--send-open-close-p ()
   3966   "Return whether open and close notifications should be sent to the server."
   3967   (let ((sync (lsp:server-capabilities-text-document-sync? (lsp--server-capabilities))))
   3968     (or (memq sync '(1 2))
   3969         (lsp:text-document-sync-options-open-close? sync))))
   3970 
   3971 (defun lsp--send-will-save-p ()
   3972   "Return whether willSave notifications should be sent to the server."
   3973   (-> (lsp--server-capabilities)
   3974       (lsp:server-capabilities-text-document-sync?)
   3975       (lsp:text-document-sync-options-will-save?)))
   3976 
   3977 (defun lsp--send-will-save-wait-until-p ()
   3978   "Return whether willSaveWaitUntil notifications should be sent to the server."
   3979   (-> (lsp--server-capabilities)
   3980       (lsp:server-capabilities-text-document-sync?)
   3981       (lsp:text-document-sync-options-will-save-wait-until?)))
   3982 
   3983 (defun lsp--send-did-save-p ()
   3984   "Return whether didSave notifications should be sent to the server."
   3985   (let ((sync (lsp:server-capabilities-text-document-sync? (lsp--server-capabilities))))
   3986     (or (memq sync '(1 2))
   3987         (lsp:text-document-sync-options-save? sync))))
   3988 
   3989 (defun lsp--save-include-text-p ()
   3990   "Return whether save notifications should include the text document's contents."
   3991   (->> (lsp--server-capabilities)
   3992        (lsp:server-capabilities-text-document-sync?)
   3993        (lsp:text-document-sync-options-save?)
   3994        (lsp:text-document-save-registration-options-include-text?)))
   3995 
   3996 (defun lsp--send-will-rename-files-p (path)
   3997   "Return whether willRenameFiles request should be sent to the server.
   3998 If any filters, checks if it applies for PATH."
   3999   (let* ((will-rename (-> (lsp--server-capabilities)
   4000                           (lsp:server-capabilities-workspace?)
   4001                           (lsp:workspace-server-capabilities-file-operations?)
   4002                           (lsp:workspace-file-operations-will-rename?)))
   4003          (filters (seq-into (lsp:file-operation-registration-options-filters will-rename) 'list)))
   4004     (and will-rename
   4005          (or (seq-empty-p filters)
   4006              (-any? (-lambda ((&FileOperationFilter :scheme? :pattern (&FileOperationPattern :glob)))
   4007                       (-let [regexes (lsp-glob-to-regexps glob)]
   4008                         (and (or (not scheme?)
   4009                                  (string-prefix-p scheme? (lsp--path-to-uri path)))
   4010                              (-any? (lambda (re)
   4011                                       (string-match re path))
   4012                                     regexes))))
   4013                     filters)))))
   4014 
   4015 (defun lsp--send-did-rename-files-p ()
   4016   "Return whether didRenameFiles notification should be sent to the server."
   4017   (-> (lsp--server-capabilities)
   4018       (lsp:server-capabilities-workspace?)
   4019       (lsp:workspace-server-capabilities-file-operations?)
   4020       (lsp:workspace-file-operations-did-rename?)))
   4021 
   4022 (declare-function project-roots "ext:project" (project) t)
   4023 (declare-function project-root "ext:project" (project) t)
   4024 
   4025 (defun lsp--suggest-project-root ()
   4026   "Get project root."
   4027   (or
   4028    (when (fboundp 'projectile-project-root)
   4029      (condition-case nil
   4030          (projectile-project-root)
   4031        (error nil)))
   4032    (when (fboundp 'project-current)
   4033      (when-let* ((project (project-current)))
   4034        (if (fboundp 'project-root)
   4035            (project-root project)
   4036          (car (with-no-warnings
   4037                 (project-roots project))))))
   4038    default-directory))
   4039 
   4040 (defun lsp--read-from-file (file)
   4041   "Read FILE content."
   4042   (when (file-exists-p file)
   4043     (cl-first (read-from-string (f-read-text file 'utf-8)))))
   4044 
   4045 (defun lsp--persist (file-name to-persist)
   4046   "Persist TO-PERSIST in FILE-NAME.
   4047 
   4048 This function creates the parent directories if they don't exist
   4049 yet."
   4050   (let ((print-length nil)
   4051         (print-level nil))
   4052     ;; Create all parent directories:
   4053     (make-directory (f-parent file-name) t)
   4054     (f-write-text (prin1-to-string to-persist) 'utf-8 file-name)))
   4055 
   4056 (defun lsp-workspace-folders-add (project-root)
   4057   "Add PROJECT-ROOT to the list of workspace folders."
   4058   (interactive
   4059    (list (read-directory-name "Select folder to add: "
   4060                               (or (lsp--suggest-project-root) default-directory) nil t)))
   4061   (cl-pushnew (lsp-f-canonical project-root)
   4062               (lsp-session-folders (lsp-session)) :test 'equal)
   4063   (lsp--persist-session (lsp-session))
   4064 
   4065   (run-hook-with-args 'lsp-workspace-folders-changed-functions (list project-root) nil))
   4066 
   4067 (defun lsp-workspace-folders-remove (project-root)
   4068   "Remove PROJECT-ROOT from the list of workspace folders."
   4069   (interactive (list (completing-read "Select folder to remove: "
   4070                                       (lsp-session-folders (lsp-session))
   4071                                       nil t nil nil
   4072                                       (lsp-find-session-folder (lsp-session) default-directory))))
   4073 
   4074   (setq project-root (lsp-f-canonical project-root))
   4075 
   4076   ;; send remove folder to each multiroot workspace associated with the folder
   4077   (dolist (wks (->> (lsp-session)
   4078                     (lsp-session-folder->servers)
   4079                     (gethash project-root)
   4080                     (--filter (lsp--client-multi-root (lsp--workspace-client it)))))
   4081     (with-lsp-workspace wks
   4082       (lsp-notify "workspace/didChangeWorkspaceFolders"
   4083                   (lsp-make-did-change-workspace-folders-params
   4084                    :event (lsp-make-workspace-folders-change-event
   4085                            :removed (vector (lsp-make-workspace-folder
   4086                                              :uri (lsp--path-to-uri project-root)
   4087                                              :name (f-filename project-root)))
   4088                            :added [])))))
   4089 
   4090   ;; turn off servers in the removed directory
   4091   (let* ((session (lsp-session))
   4092          (folder->servers (lsp-session-folder->servers session))
   4093          (server-id->folders (lsp-session-server-id->folders session))
   4094          (workspaces (gethash project-root folder->servers)))
   4095 
   4096     (remhash project-root folder->servers)
   4097 
   4098     ;; turn off the servers without root folders
   4099     (dolist (workspace workspaces)
   4100       (when (--none? (-contains? it workspace) (ht-values folder->servers))
   4101         (lsp--info "Shutdown %s since folder %s is removed..."
   4102                    (lsp--workspace-print workspace) project-root)
   4103         (with-lsp-workspace workspace (lsp--shutdown-workspace))))
   4104 
   4105     (setf (lsp-session-folders session)
   4106           (-remove-item project-root (lsp-session-folders session)))
   4107 
   4108     (ht-aeach (puthash key
   4109                        (-remove-item project-root value)
   4110                        server-id->folders)
   4111               server-id->folders)
   4112     (lsp--persist-session (lsp-session)))
   4113 
   4114   (run-hook-with-args 'lsp-workspace-folders-changed-functions nil (list project-root)))
   4115 
   4116 (defun lsp-workspace-blocklist-remove (project-root)
   4117   "Remove PROJECT-ROOT from the workspace blocklist."
   4118   (interactive (list (completing-read "Select folder to remove:"
   4119                                       (lsp-session-folders-blocklist (lsp-session))
   4120                                       nil t)))
   4121   (setf (lsp-session-folders-blocklist (lsp-session))
   4122         (delete project-root
   4123                 (lsp-session-folders-blocklist (lsp-session))))
   4124   (lsp--persist-session (lsp-session)))
   4125 
   4126 (define-obsolete-function-alias 'lsp-workspace-folders-switch
   4127   'lsp-workspace-folders-open "lsp-mode 6.1")
   4128 
   4129 (defun lsp-workspace-folders-open (project-root)
   4130   "Open the directory located at PROJECT-ROOT"
   4131   (interactive (list (completing-read "Open folder: "
   4132                                       (lsp-session-folders (lsp-session))
   4133                                       nil t)))
   4134   (find-file project-root))
   4135 
   4136 (defun lsp--maybe-enable-signature-help (trigger-characters)
   4137   (let ((ch last-command-event))
   4138     (when (cl-find ch trigger-characters :key #'string-to-char)
   4139       (lsp-signature-activate))))
   4140 
   4141 (defun lsp--on-type-formatting-handler-create ()
   4142   (when-let* ((provider (lsp--capability-for-method "textDocument/onTypeFormatting" )))
   4143     (-let [(&DocumentOnTypeFormattingOptions :more-trigger-character?
   4144                                              :first-trigger-character) provider]
   4145       (lambda ()
   4146         (lsp--on-type-formatting first-trigger-character
   4147                                  more-trigger-character?)))))
   4148 
   4149 (defun lsp--update-on-type-formatting-hook (&optional cleanup?)
   4150   (let ((on-type-formatting-handler (lsp--on-type-formatting-handler-create)))
   4151     (cond
   4152      ((and lsp-enable-on-type-formatting on-type-formatting-handler (not cleanup?))
   4153       (add-hook 'post-self-insert-hook on-type-formatting-handler nil t))
   4154      ((or cleanup?
   4155           (not lsp-enable-on-type-formatting))
   4156       (remove-hook 'post-self-insert-hook on-type-formatting-handler t)))))
   4157 
   4158 (defun lsp--signature-help-handler-create ()
   4159   (-when-let ((&SignatureHelpOptions? :trigger-characters?)
   4160               (lsp--capability-for-method "textDocument/signatureHelp"))
   4161     (lambda ()
   4162       (lsp--maybe-enable-signature-help trigger-characters?))))
   4163 
   4164 (defun lsp--update-signature-help-hook (&optional cleanup?)
   4165   (let ((signature-help-handler (lsp--signature-help-handler-create)))
   4166     (cond
   4167      ((and (or (equal lsp-signature-auto-activate t)
   4168                (memq :on-trigger-char lsp-signature-auto-activate))
   4169            signature-help-handler
   4170            (not cleanup?))
   4171       (add-hook 'post-self-insert-hook signature-help-handler nil t))
   4172 
   4173      ((or cleanup?
   4174           (not (or (equal lsp-signature-auto-activate t)
   4175                    (memq :on-trigger-char lsp-signature-auto-activate))))
   4176       (remove-hook 'post-self-insert-hook signature-help-handler t)))))
   4177 
   4178 (defun lsp--after-set-visited-file-name ()
   4179   (lsp-disconnect)
   4180   (lsp))
   4181 
   4182 ;; TODO remove those eldoc workarounds when dropping support for Emacs 27
   4183 ;; https://github.com/emacs-lsp/lsp-mode/issues/3295#issuecomment-1308994099
   4184 (defvar eldoc-documentation-default) ; CI
   4185 (when (< emacs-major-version 28)
   4186   (unless (boundp 'eldoc-documentation-functions)
   4187     (load "eldoc" nil 'nomessage))
   4188   (when (memq (default-value 'eldoc-documentation-function) '(nil ignore))
   4189     ;; actually `eldoc-documentation-strategy', but CI was failing
   4190     (setq-default eldoc-documentation-function 'eldoc-documentation-default)))
   4191 
   4192 (define-minor-mode lsp-managed-mode
   4193   "Mode for source buffers managed by lsp-mode."
   4194   :lighter nil
   4195   (cond
   4196    (lsp-managed-mode
   4197     (when (lsp-feature? "textDocument/hover")
   4198       (add-hook 'eldoc-documentation-functions #'lsp-eldoc-function nil t)
   4199       (eldoc-mode 1))
   4200 
   4201     (add-hook 'after-change-functions #'lsp-on-change nil t)
   4202     (add-hook 'after-revert-hook #'lsp-on-revert nil t)
   4203     (add-hook 'after-save-hook #'lsp-on-save nil t)
   4204     (add-hook 'auto-save-hook #'lsp--on-auto-save nil t)
   4205     (add-hook 'before-change-functions #'lsp-before-change nil t)
   4206     (add-hook 'before-save-hook #'lsp--before-save nil t)
   4207     (add-hook 'kill-buffer-hook #'lsp--text-document-did-close nil t)
   4208     (add-hook 'post-command-hook #'lsp--post-command nil t)
   4209 
   4210     (lsp--update-on-type-formatting-hook)
   4211     (lsp--update-signature-help-hook)
   4212 
   4213     (when lsp-enable-xref
   4214       (add-hook 'xref-backend-functions #'lsp--xref-backend nil t))
   4215 
   4216     (lsp-configure-buffer)
   4217 
   4218     ;; make sure we turn off lsp-mode in case major mode changes, because major
   4219     ;; mode change will wipe the buffer locals.
   4220     (add-hook 'change-major-mode-hook #'lsp-disconnect nil t)
   4221     (add-hook 'after-set-visited-file-name-hook #'lsp--after-set-visited-file-name nil t)
   4222 
   4223     (let ((buffer (lsp-current-buffer)))
   4224       (run-with-idle-timer
   4225        0.0 nil
   4226        (lambda ()
   4227          (when (lsp-buffer-live-p buffer)
   4228            (lsp-with-current-buffer buffer
   4229              (lsp--on-change-debounce buffer)
   4230              (lsp--on-idle buffer)))))))
   4231    (t
   4232     (lsp-unconfig-buffer)
   4233 
   4234     (remove-hook 'eldoc-documentation-functions #'lsp-eldoc-function t)
   4235     (remove-hook 'post-command-hook #'lsp--post-command t)
   4236     (remove-hook 'after-change-functions #'lsp-on-change t)
   4237     (remove-hook 'after-revert-hook #'lsp-on-revert t)
   4238     (remove-hook 'after-save-hook #'lsp-on-save t)
   4239     (remove-hook 'auto-save-hook #'lsp--on-auto-save t)
   4240     (remove-hook 'before-change-functions #'lsp-before-change t)
   4241     (remove-hook 'before-save-hook #'lsp--before-save t)
   4242     (remove-hook 'kill-buffer-hook #'lsp--text-document-did-close t)
   4243 
   4244     (lsp--update-on-type-formatting-hook :cleanup)
   4245     (lsp--update-signature-help-hook :cleanup)
   4246 
   4247     (when lsp--on-idle-timer
   4248       (cancel-timer lsp--on-idle-timer)
   4249       (setq lsp--on-idle-timer nil))
   4250 
   4251     (remove-hook 'lsp-on-idle-hook #'lsp--document-links t)
   4252     (remove-hook 'lsp-on-idle-hook #'lsp--document-highlight t)
   4253 
   4254     (lsp--remove-overlays 'lsp-highlight)
   4255     (lsp--remove-overlays 'lsp-links)
   4256 
   4257     (remove-hook 'xref-backend-functions #'lsp--xref-backend t)
   4258     (remove-hook 'change-major-mode-hook #'lsp-disconnect t)
   4259     (remove-hook 'after-set-visited-file-name-hook #'lsp--after-set-visited-file-name t)
   4260     (setq-local lsp-buffer-uri nil))))
   4261 
   4262 (defun lsp-configure-buffer ()
   4263   "Configure LSP features for current buffer."
   4264   ;; make sure the core is running in the context of all available workspaces
   4265   ;; to avoid misconfiguration in case we are running in `with-lsp-workspace' context
   4266   (let ((lsp--buffer-workspaces (cond
   4267                                  (lsp--buffer-workspaces)
   4268                                  (lsp--cur-workspace (list lsp--cur-workspace))))
   4269         lsp--cur-workspace)
   4270     (when lsp-auto-configure
   4271       (lsp--auto-configure)
   4272 
   4273       (when (and lsp-enable-text-document-color
   4274                  (lsp-feature? "textDocument/documentColor"))
   4275         (add-hook 'lsp-on-change-hook #'lsp--document-color nil t))
   4276 
   4277       (when (and lsp-enable-imenu
   4278                  (lsp-feature? "textDocument/documentSymbol"))
   4279         (lsp-enable-imenu))
   4280 
   4281       (when (and lsp-enable-indentation
   4282                  (lsp-feature? "textDocument/rangeFormatting"))
   4283         (add-function :override (local 'indent-region-function) #'lsp-format-region))
   4284 
   4285       (when (and lsp-enable-symbol-highlighting
   4286                  (lsp-feature? "textDocument/documentHighlight"))
   4287         (add-hook 'lsp-on-idle-hook #'lsp--document-highlight nil t))
   4288 
   4289       (when (and lsp-enable-links
   4290                  (lsp-feature? "textDocument/documentLink"))
   4291         (add-hook 'lsp-on-idle-hook #'lsp--document-links nil t))
   4292 
   4293       (when (and lsp-inlay-hint-enable
   4294                  (lsp-feature? "textDocument/inlayHint"))
   4295         (lsp-inlay-hints-mode))
   4296 
   4297       (when (and lsp-enable-dap-auto-configure
   4298                  (functionp 'dap-mode))
   4299         (dap-auto-configure-mode 1)))
   4300     (run-hooks 'lsp-configure-hook)))
   4301 
   4302 (defun lsp-unconfig-buffer ()
   4303   "Unconfigure LSP features for buffer."
   4304   (lsp--remove-overlays 'lsp-color)
   4305 
   4306   (when (advice-function-member-p 'lsp--imenu-create-index imenu-create-index-function)
   4307     (remove-function (local 'imenu-create-index-function) #'lsp--imenu-create-index)
   4308     (setq-local imenu-menubar-modified-tick 0)
   4309     (setq-local imenu--index-alist nil)
   4310     (imenu--cleanup))
   4311 
   4312   (remove-function (local 'indent-region-function) #'lsp-format-region)
   4313 
   4314   (remove-hook 'lsp-on-change-hook #'lsp--document-color t)
   4315   (remove-hook 'lsp-on-idle-hook #'lsp--document-highlight t)
   4316   (remove-hook 'lsp-on-idle-hook #'lsp--document-links t)
   4317 
   4318   (when (and lsp-enable-dap-auto-configure
   4319              (functionp 'dap-mode))
   4320     (dap-auto-configure-mode -1))
   4321 
   4322   (run-hooks 'lsp-unconfigure-hook))
   4323 
   4324 (defun lsp--buffer-content ()
   4325   (lsp-save-restriction-and-excursion
   4326     (or (lsp-virtual-buffer-call :buffer-string)
   4327         (buffer-substring-no-properties (point-min)
   4328                                         (point-max)))))
   4329 
   4330 (defun lsp--text-document-did-open ()
   4331   "`document/didOpen' event."
   4332   (run-hooks 'lsp-before-open-hook)
   4333   (when (and lsp-auto-touch-files
   4334              (not (f-exists? (lsp--uri-to-path (lsp--buffer-uri)))))
   4335     (lsp--info "Saving file '%s' because it is not present on the disk." (lsp--buffer-uri))
   4336     (save-buffer))
   4337 
   4338   (setq lsp--cur-version (or lsp--cur-version 0))
   4339   (cl-pushnew (lsp-current-buffer) (lsp--workspace-buffers lsp--cur-workspace))
   4340   (lsp-notify
   4341    "textDocument/didOpen"
   4342    (list :textDocument
   4343          (list :uri (lsp--buffer-uri)
   4344                :languageId (lsp-buffer-language)
   4345                :version lsp--cur-version
   4346                :text (lsp--buffer-content))))
   4347 
   4348   (lsp-managed-mode 1)
   4349 
   4350   (lsp-diagnostics--request-pull-diagnostics lsp--cur-workspace)
   4351 
   4352   (run-hooks 'lsp-after-open-hook)
   4353   (when-let* ((client (-some-> lsp--cur-workspace (lsp--workspace-client))))
   4354     (-some-> (lsp--client-after-open-fn client)
   4355       (funcall))
   4356     (-some-> (format "lsp-%s-after-open-hook" (lsp--client-server-id client))
   4357       (intern-soft)
   4358       (run-hooks))))
   4359 
   4360 (defun lsp--text-document-identifier ()
   4361   "Make TextDocumentIdentifier."
   4362   (list :uri (lsp--buffer-uri)))
   4363 
   4364 (defun lsp--versioned-text-document-identifier ()
   4365   "Make VersionedTextDocumentIdentifier."
   4366   (plist-put (lsp--text-document-identifier) :version lsp--cur-version))
   4367 
   4368 (defun lsp--cur-line (&optional point)
   4369   (1- (line-number-at-pos point)))
   4370 
   4371 (defun lsp--cur-position ()
   4372   "Make a Position object for the current point."
   4373   (or (lsp-virtual-buffer-call :cur-position)
   4374       (lsp-save-restriction-and-excursion
   4375         (list :line (lsp--cur-line)
   4376               :character (- (point) (line-beginning-position))))))
   4377 
   4378 (defun lsp--point-to-position (point)
   4379   "Convert POINT to Position."
   4380   (lsp-save-restriction-and-excursion
   4381     (goto-char point)
   4382     (lsp--cur-position)))
   4383 
   4384 (defun lsp--range (start end)
   4385   "Make Range body from START and END."
   4386   ;; make sure start and end are Position objects
   4387   (list :start start :end end))
   4388 
   4389 (defun lsp--region-to-range (start end)
   4390   "Make Range object for the current region."
   4391   (lsp--range (lsp--point-to-position start)
   4392               (lsp--point-to-position end)))
   4393 
   4394 (defun lsp--region-or-line ()
   4395   "The active region or the current line."
   4396   (if (use-region-p)
   4397       (lsp--region-to-range (region-beginning) (region-end))
   4398     (lsp--region-to-range (line-beginning-position) (line-end-position))))
   4399 
   4400 (defun lsp--check-document-changes-version (document-changes)
   4401   "Verify that DOCUMENT-CHANGES have the proper version."
   4402   (unless (seq-every-p
   4403            (-lambda ((&TextDocumentEdit :text-document))
   4404              (or
   4405               (not text-document)
   4406               (let* ((filename (-> text-document
   4407                                    lsp:versioned-text-document-identifier-uri
   4408                                    lsp--uri-to-path))
   4409                      (version (lsp:versioned-text-document-identifier-version? text-document)))
   4410                 (with-current-buffer (find-file-noselect filename)
   4411                   (or (null version) (zerop version) (= -1 version)
   4412                       (equal version lsp--cur-version))))))
   4413            document-changes)
   4414     (error "Document changes cannot be applied due to different document version")))
   4415 
   4416 (defun lsp--apply-workspace-edit (workspace-edit &optional operation)
   4417   "Apply the WorkspaceEdit object WORKSPACE-EDIT.
   4418 OPERATION is symbol representing the source of this text edit."
   4419   (-let (((&WorkspaceEdit :document-changes? :changes?) workspace-edit))
   4420     (if-let* ((document-changes (seq-reverse document-changes?)))
   4421         (progn
   4422           (lsp--check-document-changes-version document-changes)
   4423           (->> document-changes
   4424                (seq-filter (-lambda ((&CreateFile :kind)) (equal kind "create")))
   4425                (seq-do (lambda (change) (lsp--apply-text-document-edit change operation))))
   4426           (->> document-changes
   4427                (seq-filter (-lambda ((&CreateFile :kind))
   4428                              (and (or (not kind) (equal kind "edit"))
   4429                                   (not (equal kind "create")))))
   4430                (seq-do (lambda (change) (lsp--apply-text-document-edit change operation))))
   4431           (->> document-changes
   4432                (seq-filter (-lambda ((&CreateFile :kind))
   4433                              (and (not (or (not kind) (equal kind "edit")))
   4434                                   (not (equal kind "create")))))
   4435                (seq-do (lambda (change) (lsp--apply-text-document-edit change operation)))))
   4436       (lsp-map
   4437        (lambda (uri text-edits)
   4438          (with-current-buffer (-> uri lsp--uri-to-path find-file-noselect)
   4439            (lsp--apply-text-edits text-edits operation)))
   4440        changes?))))
   4441 
   4442 (defmacro lsp-with-filename (file &rest body)
   4443   "Execute BODY with FILE as a context.
   4444 Need to handle the case when FILE indicates virtual buffer."
   4445   (declare (indent 1) (debug t))
   4446   `(if-let* ((lsp--virtual-buffer (get-text-property 0 'lsp-virtual-buffer ,file)))
   4447        (lsp-with-current-buffer lsp--virtual-buffer
   4448          ,@body)
   4449      ,@body))
   4450 
   4451 (defun lsp--apply-text-document-edit (edit &optional operation)
   4452   "Apply the TextDocumentEdit object EDIT.
   4453 OPERATION is symbol representing the source of this text edit.
   4454 If the file is not being visited by any buffer, it is opened with
   4455 `find-file-noselect'.
   4456 Because lsp-mode does not store previous document versions, the edit is only
   4457 applied if the version of the textDocument matches the version of the
   4458 corresponding file.
   4459 
   4460 interface TextDocumentEdit {
   4461   textDocument: VersionedTextDocumentIdentifier;
   4462   edits: TextEdit[];
   4463 }"
   4464   (pcase (lsp:edit-kind edit)
   4465     ("create" (-let* (((&CreateFile :uri :options?) edit)
   4466                       (file-name (lsp--uri-to-path uri)))
   4467                 (mkdir (f-dirname file-name) t)
   4468                 (f-touch file-name)
   4469                 (when (lsp:create-file-options-overwrite? options?)
   4470                   (f-write-text "" nil file-name))
   4471                 (find-file-noselect file-name)))
   4472     ("delete" (-let (((&DeleteFile :uri :options? (&DeleteFileOptions? :recursive?)) edit))
   4473                 (f-delete (lsp--uri-to-path uri) recursive?)))
   4474     ("rename" (-let* (((&RenameFile :old-uri :new-uri :options? (&RenameFileOptions? :overwrite?)) edit)
   4475                       (old-file-name (lsp--uri-to-path old-uri))
   4476                       (new-file-name (lsp--uri-to-path new-uri))
   4477                       (buf (find-buffer-visiting old-file-name)))
   4478                 (when buf
   4479                   (lsp-with-current-buffer buf
   4480                     (save-buffer)
   4481                     (lsp--text-document-did-close)))
   4482                 (mkdir (f-dirname new-file-name) t)
   4483                 (rename-file old-file-name new-file-name overwrite?)
   4484                 (when buf
   4485                   (lsp-with-current-buffer buf
   4486                     (set-buffer-modified-p nil)
   4487                     (setq lsp-buffer-uri nil)
   4488                     (set-visited-file-name new-file-name)
   4489                     (lsp)))))
   4490     (_ (let ((file-name (->> edit
   4491                              (lsp:text-document-edit-text-document)
   4492                              (lsp:versioned-text-document-identifier-uri)
   4493                              (lsp--uri-to-path))))
   4494          (lsp-with-current-buffer (find-buffer-visiting file-name)
   4495            (lsp-with-filename file-name
   4496              (lsp--apply-text-edits (lsp:text-document-edit-edits edit) operation)))))))
   4497 
   4498 (lsp-defun lsp--position-compare ((&Position :line left-line
   4499                                              :character left-character)
   4500                                   (&Position :line right-line
   4501                                              :character right-character))
   4502   "Return t if position LEFT is greater than RIGHT."
   4503   (if (= left-line right-line)
   4504       (> left-character right-character)
   4505     (> left-line right-line)))
   4506 
   4507 (lsp-defun lsp-point-in-range? (position (&Range :start :end))
   4508   "Returns if POINT is in RANGE."
   4509   (not (or (lsp--position-compare start position)
   4510            (lsp--position-compare position end))))
   4511 
   4512 (lsp-defun lsp--position-equal ((&Position :line left-line
   4513                                            :character left-character)
   4514                                 (&Position :line right-line
   4515                                            :character right-character))
   4516   "Return whether LEFT and RIGHT positions are equal."
   4517   (and (= left-line right-line)
   4518        (= left-character right-character)))
   4519 
   4520 (lsp-defun lsp--text-edit-sort-predicate ((&TextEdit :range (&Range :start left-start :end left-end))
   4521                                           (&TextEdit :range (&Range :start right-start :end right-end)))
   4522   (if (lsp--position-equal left-start right-start)
   4523       (lsp--position-compare left-end right-end)
   4524     (lsp--position-compare left-start right-start)))
   4525 
   4526 (lsp-defun lsp--apply-text-edit ((edit &as &TextEdit :range (&RangeToPoint :start :end) :new-text))
   4527   "Apply the edits described in the TextEdit object in TEXT-EDIT."
   4528   (setq new-text (s-replace "\r" "" (or new-text "")))
   4529   (lsp:set-text-edit-new-text edit new-text)
   4530   (goto-char start)
   4531   (delete-region start end)
   4532   (insert new-text))
   4533 
   4534 ;; WORKAROUND: typescript-language might send -1 when applying code actions.
   4535 ;; see https://github.com/emacs-lsp/lsp-mode/issues/1582
   4536 (lsp-defun lsp--fix-point ((point &as &Position :character :line))
   4537   (-doto point
   4538     (lsp:set-position-line (max 0 line))
   4539     (lsp:set-position-character (max 0 character))))
   4540 
   4541 (lsp-defun lsp--apply-text-edit-replace-buffer-contents ((edit &as
   4542                                                                &TextEdit
   4543                                                                :range (&Range :start :end)
   4544                                                                :new-text))
   4545   "Apply the edits described in the TextEdit object in TEXT-EDIT.
   4546 The method uses `replace-buffer-contents'."
   4547   (setq new-text (s-replace "\r" "" (or new-text "")))
   4548   (lsp:set-text-edit-new-text edit new-text)
   4549   (-let* ((source (current-buffer))
   4550           ((beg . end) (lsp--range-to-region (lsp-make-range :start (lsp--fix-point start)
   4551                                                              :end (lsp--fix-point end)))))
   4552     (with-temp-buffer
   4553       (insert new-text)
   4554       (let ((temp (current-buffer)))
   4555         (with-current-buffer source
   4556           (save-excursion
   4557             (save-restriction
   4558               (narrow-to-region beg end)
   4559 
   4560               ;; On emacs versions < 26.2,
   4561               ;; `replace-buffer-contents' is buggy - it calls
   4562               ;; change functions with invalid arguments - so we
   4563               ;; manually call the change functions here.
   4564               ;;
   4565               ;; See emacs bugs #32237, #32278:
   4566               ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32237
   4567               ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=32278
   4568               (let ((inhibit-modification-hooks t)
   4569                     (length (- end beg)))
   4570                 (run-hook-with-args 'before-change-functions
   4571                                     beg end)
   4572                 (replace-buffer-contents temp)
   4573                 (run-hook-with-args 'after-change-functions
   4574                                     beg (+ beg (length new-text))
   4575                                     length)))))))))
   4576 
   4577 (defun lsp--to-yasnippet-snippet (snippet)
   4578   "Convert LSP SNIPPET to yasnippet snippet."
   4579   ;; LSP snippet doesn't escape "{" and "`", but yasnippet requires escaping it.
   4580   (replace-regexp-in-string (rx (or bos (not (any "$" "\\"))) (group (or "{" "`")))
   4581                             (rx "\\" (backref 1))
   4582                             snippet
   4583                             nil nil 1))
   4584 
   4585 (defvar-local lsp-enable-relative-indentation nil
   4586   "Enable relative indentation when insert texts, snippets ...
   4587 from language server.")
   4588 
   4589 (defun lsp--expand-snippet (snippet &optional start end expand-env)
   4590   "Wrapper of `yas-expand-snippet' with all of it arguments.
   4591 The snippet will be convert to LSP style and indent according to
   4592 LSP server result."
   4593   (require 'yasnippet nil t)
   4594   (let* ((inhibit-field-text-motion t)
   4595          (yas-wrap-around-region nil)
   4596          (yas-indent-line 'none)
   4597          (yas-also-auto-indent-first-line nil))
   4598     (yas-expand-snippet
   4599      (lsp--to-yasnippet-snippet snippet)
   4600      start end expand-env)))
   4601 
   4602 (defun lsp--indent-lines (start end &optional insert-text-mode?)
   4603   "Indent from START to END based on INSERT-TEXT-MODE? value.
   4604 - When INSERT-TEXT-MODE? is provided
   4605   - if it's `lsp/insert-text-mode-as-it', do no editor indentation.
   4606   - if it's `lsp/insert-text-mode-adjust-indentation', adjust leading
   4607     whitespaces to match the line where text is inserted.
   4608 - When it's not provided, using `indent-line-function' for each line."
   4609   (save-excursion
   4610     (goto-char end)
   4611     (let* ((end-line (line-number-at-pos))
   4612            (offset (save-excursion
   4613                      (goto-char start)
   4614                      (current-indentation)))
   4615            (indent-line-function
   4616             (cond ((equal insert-text-mode? lsp/insert-text-mode-as-it)
   4617                    #'ignore)
   4618                   ((or (equal insert-text-mode? lsp/insert-text-mode-adjust-indentation)
   4619                        lsp-enable-relative-indentation
   4620                        ;; Indenting snippets is extremely slow in `org-mode' buffers
   4621                        ;; since it has to calculate indentation based on SRC block
   4622                        ;; position.  Thus we use relative indentation as default.
   4623                        (derived-mode-p 'org-mode))
   4624                    (lambda () (save-excursion
   4625                                 (beginning-of-line)
   4626                                 (indent-to-column offset))))
   4627                   (t indent-line-function))))
   4628       (goto-char start)
   4629       (forward-line)
   4630       (while (and (not (eobp))
   4631                   (<= (line-number-at-pos) end-line))
   4632         (funcall indent-line-function)
   4633         (forward-line)))))
   4634 
   4635 (defun lsp--apply-text-edits (edits &optional operation)
   4636   "Apply the EDITS described in the TextEdit[] object.
   4637 OPERATION is symbol representing the source of this text edit."
   4638   (unless (seq-empty-p edits)
   4639     (atomic-change-group
   4640       (run-hooks 'lsp-before-apply-edits-hook)
   4641       (let* ((change-group (prepare-change-group))
   4642              (howmany (length edits))
   4643              (message (format "Applying %s edits to `%s' ..." howmany (current-buffer)))
   4644              (_ (lsp--info message))
   4645              (reporter (make-progress-reporter message 0 howmany))
   4646              (done 0)
   4647              (apply-edit (if (not lsp--virtual-buffer)
   4648                              #'lsp--apply-text-edit-replace-buffer-contents
   4649                            #'lsp--apply-text-edit)))
   4650         (unwind-protect
   4651             (->> edits
   4652                  ;; We sort text edits so as to apply edits that modify latter
   4653                  ;; parts of the document first. Furthermore, because the LSP
   4654                  ;; spec dictates that: "If multiple inserts have the same
   4655                  ;; position, the order in the array defines which edit to
   4656                  ;; apply first."  We reverse the initial list and sort stably
   4657                  ;; to make sure the order among edits with the same position
   4658                  ;; is preserved.
   4659                  (nreverse)
   4660                  (seq-sort #'lsp--text-edit-sort-predicate)
   4661                  (mapc (lambda (edit)
   4662                          (progress-reporter-update reporter (cl-incf done))
   4663                          (funcall apply-edit edit)
   4664                          (when (lsp:snippet-text-edit-insert-text-format? edit)
   4665                            (-when-let ((&SnippetTextEdit :range (&RangeToPoint :start)
   4666                                                          :insert-text-format? :new-text) edit)
   4667                              (when (eq insert-text-format? lsp/insert-text-format-snippet)
   4668                                ;; No `save-excursion' needed since expand snippet will change point anyway
   4669                                (goto-char (+ start (length new-text)))
   4670                                (lsp--indent-lines start (point))
   4671                                (lsp--expand-snippet new-text start (point)))))
   4672                          (run-hook-with-args 'lsp-after-apply-edits-hook operation))))
   4673           (undo-amalgamate-change-group change-group)
   4674           (progress-reporter-done reporter))))))
   4675 
   4676 (defun lsp--create-apply-text-edits-handlers ()
   4677   "Create (handler cleanup-fn) for applying text edits in async request.
   4678 Only works when mode is `tick or `alive."
   4679   (let* (first-edited
   4680          (func (lambda (start &rest _)
   4681                  (setq first-edited (if first-edited
   4682                                         (min start first-edited)
   4683                                       start)))))
   4684     (add-hook 'before-change-functions func nil t)
   4685     (list
   4686      (lambda (edits)
   4687        (if (and first-edited
   4688                 (seq-find (-lambda ((&TextEdit :range (&RangeToPoint :end)))
   4689                             ;; Text edit region is overlapped
   4690                             (> end first-edited))
   4691                           edits))
   4692            (lsp--warn "TextEdits will not be applied since document has been modified before of them.")
   4693          (lsp--apply-text-edits edits 'completion-cleanup)))
   4694      (lambda ()
   4695        (remove-hook 'before-change-functions func t)))))
   4696 
   4697 (defun lsp--capability (cap &optional capabilities)
   4698   "Get the value of capability CAP.  If CAPABILITIES is non-nil, use them instead."
   4699   (when (stringp cap)
   4700     (setq cap (intern (concat ":" cap))))
   4701 
   4702   (lsp-get (or capabilities
   4703                (lsp--server-capabilities))
   4704            cap))
   4705 
   4706 (defun lsp--registered-capability (method)
   4707   "Check whether there is workspace providing METHOD."
   4708   (->> (lsp-workspaces)
   4709        (--keep (seq-find (lambda (reg)
   4710                            (equal (lsp--registered-capability-method reg) method))
   4711                          (lsp--workspace-registered-server-capabilities it)))
   4712        cl-first))
   4713 
   4714 (defun lsp--capability-for-method (method)
   4715   "Get the value of capability for METHOD."
   4716   (-let* ((reqs (cdr (assoc method lsp-method-requirements)))
   4717           ((&plist :capability) reqs))
   4718     (or (and capability (lsp--capability capability))
   4719         (-some-> (lsp--registered-capability method)
   4720           (lsp--registered-capability-options)))))
   4721 
   4722 (defvar-local lsp--before-change-vals nil
   4723   "Store the positions from the `lsp-before-change' function call, for
   4724 validation and use in the `lsp-on-change' function.")
   4725 
   4726 (defun lsp--text-document-content-change-event (start end length)
   4727   "Make a TextDocumentContentChangeEvent body for START to END, of length LENGTH."
   4728   ;; So (47 54 0) means add    7 chars starting at pos 47
   4729   ;; must become
   4730   ;;   {"range":{"start":{"line":5,"character":6}
   4731   ;;             ,"end" :{"line":5,"character":6}}
   4732   ;;             ,"rangeLength":0
   4733   ;;             ,"text":"\nbb = 5"}
   4734   ;;
   4735   ;; And (47 47 7) means delete 7 chars starting at pos 47
   4736   ;; must become
   4737   ;;   {"range":{"start":{"line":6,"character":0}
   4738   ;;            ,"end"  :{"line":7,"character":0}}
   4739   ;;            ,"rangeLength":7
   4740   ;;            ,"text":""}
   4741   ;;
   4742   ;; (208 221 3) means delete 3 chars starting at pos 208, and replace them with
   4743   ;; 13 chars. So it must become
   4744   ;;   {"range":{"start":{"line":5,"character":8}
   4745   ;;             ,"end" :{"line":5,"character":11}}
   4746   ;;             ,"rangeLength":3
   4747   ;;             ,"text":"new-chars-xxx"}
   4748   ;;
   4749 
   4750   ;; Adding text:
   4751   ;;   lsp-before-change:(start,end)=(33,33)
   4752   ;;   lsp-on-change:(start,end,length)=(33,34,0)
   4753   ;;
   4754   ;; Changing text:
   4755   ;;   lsp-before-change:(start,end)=(208,211)
   4756   ;;   lsp-on-change:(start,end,length)=(208,221,3)
   4757   ;;
   4758   ;; Deleting text:
   4759   ;;   lsp-before-change:(start,end)=(19,27)
   4760   ;;   lsp-on-change:(start,end,length)=(19,19,8)
   4761   (if (zerop length)
   4762       ;; Adding something only, work from start only
   4763       `( :range ,(lsp--range
   4764                   (lsp--point-to-position start)
   4765                   (lsp--point-to-position start))
   4766          :rangeLength 0
   4767          :text ,(buffer-substring-no-properties start end))
   4768 
   4769     (if (eq start end)
   4770         ;; Deleting something only
   4771         (if (lsp--bracketed-change-p start length)
   4772             ;; The before-change value is bracketed, use it
   4773             `( :range ,(lsp--range
   4774                         (lsp--point-to-position start)
   4775                         (plist-get lsp--before-change-vals :end-pos))
   4776                :rangeLength ,length
   4777                :text "")
   4778           ;; If the change is not bracketed, send a full change event instead.
   4779           (lsp--full-change-event))
   4780 
   4781       ;; Deleting some things, adding others
   4782       (if (lsp--bracketed-change-p start length)
   4783           ;; The before-change value is valid, use it
   4784           `( :range ,(lsp--range
   4785                       (lsp--point-to-position start)
   4786                       (plist-get lsp--before-change-vals :end-pos))
   4787              :rangeLength ,length
   4788              :text ,(buffer-substring-no-properties start end))
   4789         (lsp--full-change-event)))))
   4790 
   4791 (defun lsp--bracketed-change-p (start length)
   4792   "If the before and after positions are the same, and the length
   4793 is the size of the start range, we are probably good."
   4794   (-let [(&plist :end before-end :start before-start) lsp--before-change-vals]
   4795     (and (eq start before-start)
   4796          (eq length (- before-end before-start)))))
   4797 
   4798 (defun lsp--full-change-event ()
   4799   `(:text ,(lsp--buffer-content)))
   4800 
   4801 (defun lsp-before-change (start end)
   4802   "Executed before a file is changed.
   4803 Added to `before-change-functions'."
   4804   ;; Note:
   4805   ;;
   4806   ;; This variable holds a list of functions to call when Emacs is about to
   4807   ;; modify a buffer. Each function gets two arguments, the beginning and end of
   4808   ;; the region that is about to change, represented as integers. The buffer
   4809   ;; that is about to change is always the current buffer when the function is
   4810   ;; called.
   4811   ;;
   4812   ;; WARNING:
   4813   ;;
   4814   ;; Do not expect the before-change hooks and the after-change hooks be called
   4815   ;; in balanced pairs around each buffer change. Also don't expect the
   4816   ;; before-change hooks to be called for every chunk of text Emacs is about to
   4817   ;; delete. These hooks are provided on the assumption that Lisp programs will
   4818   ;; use either before- or the after-change hooks, but not both, and the
   4819   ;; boundaries of the region where the changes happen might include more than
   4820   ;; just the actual changed text, or even lump together several changes done
   4821   ;; piecemeal.
   4822   (save-match-data
   4823     (lsp-save-restriction-and-excursion
   4824       (setq lsp--before-change-vals
   4825             (list :start start
   4826                   :end end
   4827                   :end-pos (lsp--point-to-position end))))))
   4828 
   4829 (defun lsp--flush-delayed-changes ()
   4830   (let ((inhibit-quit t))
   4831     (when lsp--delay-timer
   4832       (cancel-timer lsp--delay-timer))
   4833     (mapc (-lambda ((workspace buffer document change))
   4834             (with-current-buffer buffer
   4835               (with-lsp-workspace workspace
   4836                 (lsp-notify "textDocument/didChange"
   4837                             (list :textDocument document
   4838                                   :contentChanges (vector change))))))
   4839           (prog1 (nreverse lsp--delayed-requests)
   4840             (setq lsp--delayed-requests nil)))))
   4841 
   4842 (defun lsp--workspace-sync-method (workspace)
   4843   (let ((sync (-> workspace
   4844                   (lsp--workspace-server-capabilities)
   4845                   (lsp:server-capabilities-text-document-sync?))))
   4846     (if (lsp-text-document-sync-options? sync)
   4847         (lsp:text-document-sync-options-change? sync)
   4848       sync)))
   4849 
   4850 (defun lsp-on-change (start end length &optional content-change-event-fn)
   4851   "Executed when a file is changed.
   4852 Added to `after-change-functions'."
   4853   ;; Note:
   4854   ;;
   4855   ;; Each function receives three arguments: the beginning and end of the region
   4856   ;; just changed, and the length of the text that existed before the change.
   4857   ;; All three arguments are integers. The buffer that has been changed is
   4858   ;; always the current buffer when the function is called.
   4859   ;;
   4860   ;; The length of the old text is the difference between the buffer positions
   4861   ;; before and after that text as it was before the change. As for the
   4862   ;; changed text, its length is simply the difference between the first two
   4863   ;; arguments.
   4864   ;;
   4865   ;; So (47 54 0) means add    7 chars starting at pos 47
   4866   ;; So (47 47 7) means delete 7 chars starting at pos 47
   4867   (save-match-data
   4868     (let ((inhibit-quit t)
   4869           ;; make sure that `lsp-on-change' is called in multi-workspace context
   4870           ;; see #2901
   4871           lsp--cur-workspace)
   4872       ;; A (revert-buffer) call with the 'preserve-modes parameter (eg, as done
   4873       ;; by auto-revert-mode) will cause this handler to get called with a nil
   4874       ;; buffer-file-name. We need the buffer-file-name to send notifications;
   4875       ;; so we skip handling revert-buffer-caused changes and instead handle
   4876       ;; reverts separately in lsp-on-revert
   4877       (when (not revert-buffer-in-progress-p)
   4878         (cl-incf lsp--cur-version)
   4879         (mapc
   4880          (lambda (workspace)
   4881            (pcase (or lsp-document-sync-method
   4882                       (lsp--workspace-sync-method workspace))
   4883              (1
   4884               (if lsp-debounce-full-sync-notifications
   4885                   (setq lsp--delayed-requests
   4886                         (->> lsp--delayed-requests
   4887                              (-remove (-lambda ((_ buffer))
   4888                                         (equal (current-buffer) buffer)))
   4889                              (cons (list workspace
   4890                                          (current-buffer)
   4891                                          (lsp--versioned-text-document-identifier)
   4892                                          (lsp--full-change-event)))))
   4893                 (with-lsp-workspace workspace
   4894                   (lsp-notify "textDocument/didChange"
   4895                               (list :contentChanges (vector (lsp--full-change-event))
   4896                                     :textDocument (lsp--versioned-text-document-identifier)))
   4897                   (lsp-diagnostics--request-pull-diagnostics workspace))))
   4898              (2
   4899               (with-lsp-workspace workspace
   4900                 (lsp-notify
   4901                  "textDocument/didChange"
   4902                  (list :textDocument (lsp--versioned-text-document-identifier)
   4903                        :contentChanges (vector
   4904                                         (if content-change-event-fn
   4905                                             (funcall content-change-event-fn start end length)
   4906                                           (lsp--text-document-content-change-event
   4907                                            start end length)))))
   4908                 (lsp-diagnostics--request-pull-diagnostics workspace)))))
   4909          (lsp-workspaces))
   4910         (when lsp--delay-timer (cancel-timer lsp--delay-timer))
   4911         (setq lsp--delay-timer (run-with-idle-timer
   4912                                 lsp-debounce-full-sync-notifications-interval
   4913                                 nil
   4914                                 #'lsp--flush-delayed-changes))
   4915         ;; force cleanup overlays after each change
   4916         (lsp--remove-overlays 'lsp-highlight)
   4917         (lsp--after-change (current-buffer))))))
   4918 
   4919 
   4920 
   4921 ;; facilities for on change hooks. We do not want to make lsp calls on each
   4922 ;; change event so we add debounce to avoid flooding the server with events.
   4923 ;; Additionally, we want to have a mechanism for stopping the server calls in
   4924 ;; particular cases like, e. g. when performing completion.
   4925 
   4926 (defvar lsp-inhibit-lsp-hooks nil
   4927   "Flag to control.")
   4928 
   4929 (defcustom lsp-on-change-hook nil
   4930   "Hooks to run when buffer has changed."
   4931   :type 'hook
   4932   :group 'lsp-mode)
   4933 
   4934 (defcustom lsp-idle-delay 0.500
   4935   "Debounce interval for `after-change-functions'."
   4936   :type 'number
   4937   :group 'lsp-mode)
   4938 
   4939 (defcustom lsp-on-idle-hook nil
   4940   "Hooks to run after `lsp-idle-delay'."
   4941   :type 'hook
   4942   :group 'lsp-mode)
   4943 
   4944 (defun lsp--idle-reschedule (buffer)
   4945   (when lsp--on-idle-timer
   4946     (cancel-timer lsp--on-idle-timer))
   4947 
   4948   (setq lsp--on-idle-timer (run-with-idle-timer
   4949                             lsp-idle-delay
   4950                             nil
   4951                             #'lsp--on-idle
   4952                             buffer)))
   4953 
   4954 (defun lsp--post-command ()
   4955   (lsp--cleanup-highlights-if-needed)
   4956   (lsp--idle-reschedule (current-buffer)))
   4957 
   4958 (defun lsp--on-idle (buffer)
   4959   "Start post command loop."
   4960   (when (and (buffer-live-p buffer)
   4961              (equal buffer (current-buffer))
   4962              (not lsp-inhibit-lsp-hooks)
   4963              lsp-managed-mode)
   4964     (run-hooks 'lsp-on-idle-hook)))
   4965 
   4966 (defun lsp--on-change-debounce (buffer)
   4967   (when (and (buffer-live-p buffer)
   4968              (equal buffer (current-buffer))
   4969              (not lsp-inhibit-lsp-hooks)
   4970              lsp-managed-mode)
   4971     (run-hooks 'lsp-on-change-hook)))
   4972 
   4973 
   4974 (defvar-local lsp--after-change-vals nil
   4975   "plist that stores the buffer state when `lsp--after-change' has ben activated. Since the
   4976 functions in `lsp-on-change-hook' are called with a timer, mouse
   4977 movements may have changed the position")
   4978 
   4979 (defun lsp--after-change (buffer)
   4980   "Called after most textDocument/didChange events."
   4981   (setq lsp--signature-last-index nil
   4982         lsp--signature-last nil)
   4983 
   4984   ;; cleanup diagnostics
   4985   (when lsp-diagnostic-clean-after-change
   4986     (dolist (workspace (lsp-workspaces))
   4987       (-let [diagnostics (lsp--workspace-diagnostics workspace)]
   4988         (remhash (lsp--fix-path-casing (buffer-file-name)) diagnostics))))
   4989 
   4990   (when (fboundp 'lsp--semantic-tokens-refresh-if-enabled)
   4991     (lsp--semantic-tokens-refresh-if-enabled buffer))
   4992   (when lsp--on-change-timer
   4993     (cancel-timer lsp--on-change-timer))
   4994 
   4995   (setq lsp--after-change-vals (list :point (point)
   4996                                      :buffer (current-buffer)))
   4997   (setq lsp--on-change-timer (run-with-idle-timer
   4998                               lsp-idle-delay
   4999                               nil
   5000                               #'lsp--on-change-debounce
   5001                               buffer))
   5002   (lsp--idle-reschedule buffer))
   5003 
   5004 
   5005 (defcustom lsp-trim-trailing-whitespace t
   5006   "Trim trailing whitespace on a line."
   5007   :group 'lsp-mode
   5008   :type 'boolean)
   5009 
   5010 (defcustom lsp-insert-final-newline t
   5011   "Insert a newline character at the end of the file if one does not exist."
   5012   :group 'lsp-mode
   5013   :type 'boolean)
   5014 
   5015 (defcustom lsp-trim-final-newlines t
   5016   "Trim all newlines after the final newline at the end of the file."
   5017   :group 'lsp-mode
   5018   :type 'boolean)
   5019 
   5020 
   5021 (defun lsp--on-type-formatting (first-trigger-characters more-trigger-characters)
   5022   "Self insert handling.
   5023 Applies on type formatting."
   5024   (let ((ch last-command-event))
   5025     (when (or (eq (string-to-char first-trigger-characters) ch)
   5026               (cl-find ch more-trigger-characters :key #'string-to-char))
   5027       (lsp-request-async "textDocument/onTypeFormatting"
   5028                          (lsp-make-document-on-type-formatting-params
   5029                           :text-document (lsp--text-document-identifier)
   5030                           :options (lsp-make-formatting-options
   5031                                     :tab-size (symbol-value (lsp--get-indent-width major-mode))
   5032                                     :insert-spaces (lsp-json-bool (not indent-tabs-mode))
   5033                                     :trim-trailing-whitespace? (lsp-json-bool lsp-trim-trailing-whitespace)
   5034                                     :insert-final-newline? (lsp-json-bool lsp-insert-final-newline)
   5035                                     :trim-final-newlines? (lsp-json-bool lsp-trim-final-newlines))
   5036                           :ch (char-to-string ch)
   5037                           :position (lsp--cur-position))
   5038                          (lambda (data) (lsp--apply-text-edits data 'format))
   5039                          :mode 'tick))))
   5040 
   5041 
   5042 ;; links
   5043 (defun lsp--document-links ()
   5044   (when (lsp-feature? "textDocument/documentLink")
   5045     (lsp-request-async
   5046      "textDocument/documentLink"
   5047      `(:textDocument ,(lsp--text-document-identifier))
   5048      (lambda (links)
   5049        (lsp--remove-overlays 'lsp-link)
   5050        (seq-do
   5051         (-lambda ((link &as &DocumentLink :range (&Range :start :end)))
   5052           (-doto (make-button (lsp--position-to-point start)
   5053                               (lsp--position-to-point end)
   5054                               'action (lsp--document-link-keymap link)
   5055                               'keymap (let ((map (make-sparse-keymap)))
   5056                                         (define-key map [M-return] 'push-button)
   5057                                         (define-key map [mouse-2] 'push-button)
   5058                                         map)
   5059                               'help-echo "mouse-2, M-RET: Visit this link")
   5060             (overlay-put 'lsp-link t)))
   5061         links))
   5062      :mode 'unchanged)))
   5063 
   5064 (defun lsp--document-link-handle-target (url)
   5065   (let* ((parsed-url (url-generic-parse-url (url-unhex-string url)))
   5066          (type (url-type parsed-url)))
   5067     (pcase type
   5068       ("file"
   5069        (xref-push-marker-stack)
   5070        (find-file (lsp--uri-to-path url))
   5071        (-when-let ((_ line column) (s-match (rx "#" (group (1+ num)) (or "," "#") (group (1+ num))) url))
   5072          (goto-char (lsp--position-to-point
   5073                      (lsp-make-position :character (1- (string-to-number column))
   5074                                         :line (1- (string-to-number line)))))))
   5075       ((or "http" "https") (browse-url url))
   5076       (type (if-let* ((handler (lsp--get-uri-handler type)))
   5077                 (funcall handler url)
   5078               (signal 'lsp-file-scheme-not-supported (list url)))))))
   5079 
   5080 (lsp-defun lsp--document-link-keymap ((link &as &DocumentLink :target?))
   5081   (if target?
   5082       (lambda (_)
   5083         (interactive)
   5084         (lsp--document-link-handle-target target?))
   5085     (lambda (_)
   5086       (interactive)
   5087       (when (lsp:document-link-registration-options-resolve-provider?
   5088              (lsp--capability-for-method "textDocument/documentLink"))
   5089         (lsp-request-async
   5090          "documentLink/resolve"
   5091          link
   5092          (-lambda ((&DocumentLink :target?))
   5093            (lsp--document-link-handle-target target?)))))))
   5094 
   5095 
   5096 
   5097 (defcustom lsp-warn-no-matched-clients t
   5098   "Whether to show messages when there are no supported clients."
   5099   :group 'lsp-mode
   5100   :type 'boolean)
   5101 
   5102 (defun lsp-buffer-language--configured-id ()
   5103   "Return nil when not registered."
   5104   (->> lsp-language-id-configuration
   5105        (-first
   5106         (-lambda ((mode-or-pattern . language))
   5107           (cond
   5108            ((and (stringp mode-or-pattern)
   5109                  (s-matches? mode-or-pattern (buffer-file-name)))
   5110             language)
   5111            ((eq mode-or-pattern major-mode) language))))
   5112        cl-rest))
   5113 
   5114 (defvar-local lsp--buffer-language nil
   5115   "Locally cached returned value of `lsp-buffer-language'.")
   5116 
   5117 (defun lsp-buffer-language ()
   5118   "Get language corresponding current buffer."
   5119   (or lsp--buffer-language
   5120       (let* ((configured-language (lsp-buffer-language--configured-id)))
   5121         (setq lsp--buffer-language
   5122               (or configured-language
   5123                   ;; ensure non-nil
   5124                   (string-remove-suffix "-mode" (symbol-name major-mode))))
   5125         (when (and lsp-warn-no-matched-clients
   5126                    (null configured-language))
   5127           (lsp-warn "Unable to calculate the languageId for buffer `%s'. \
   5128 Take a look at `lsp-language-id-configuration'. The `major-mode' is %s"
   5129                     (buffer-name)
   5130                     major-mode))
   5131         lsp--buffer-language)))
   5132 
   5133 (defun lsp-activate-on (&rest languages)
   5134   "Returns language activation function.
   5135 The function will return t when the `lsp-buffer-language' returns
   5136 one of the LANGUAGES."
   5137   (lambda (_file-name _mode)
   5138     (-contains? languages (lsp-buffer-language))))
   5139 
   5140 (defun lsp-workspace-root (&optional path)
   5141   "Find the workspace root for the current file or PATH."
   5142   (-when-let* ((file-name (or path (buffer-file-name)))
   5143                (file-name (lsp-f-canonical file-name)))
   5144     (->> (lsp-session)
   5145          (lsp-session-folders)
   5146          (--filter (and (lsp--files-same-host it file-name)
   5147                         (or (lsp-f-ancestor-of? it file-name)
   5148                             (equal it file-name))))
   5149          (--max-by (> (length it) (length other))))))
   5150 
   5151 (defun lsp-on-revert ()
   5152   "Executed when a file is reverted.
   5153 Added to `after-revert-hook'."
   5154   (let ((n (buffer-size))
   5155         (revert-buffer-in-progress-p nil))
   5156     (lsp-on-change 0 n n)))
   5157 
   5158 (defun lsp--text-document-did-close (&optional keep-workspace-alive)
   5159   "Executed when the file is closed, added to `kill-buffer-hook'.
   5160 
   5161 If KEEP-WORKSPACE-ALIVE is non-nil, do not shutdown the workspace
   5162 if it's closing the last buffer in the workspace."
   5163   (lsp-foreach-workspace
   5164    (cl-callf2 delq (lsp-current-buffer) (lsp--workspace-buffers lsp--cur-workspace))
   5165    (with-demoted-errors "Error sending didClose notification in ‘lsp--text-document-did-close’: %S"
   5166      (lsp-notify "textDocument/didClose"
   5167                  `(:textDocument ,(lsp--text-document-identifier))))
   5168    (when (and (not lsp-keep-workspace-alive)
   5169               (not keep-workspace-alive)
   5170               (not (lsp--workspace-buffers lsp--cur-workspace)))
   5171      (lsp--shutdown-workspace))))
   5172 
   5173 (defun lsp--will-save-text-document-params (reason)
   5174   (list :textDocument (lsp--text-document-identifier)
   5175         :reason reason))
   5176 
   5177 (defun lsp--before-save ()
   5178   "Before save handler."
   5179   (with-demoted-errors "Error in ‘lsp--before-save’: %S"
   5180     (let ((params (lsp--will-save-text-document-params 1)))
   5181       (when (lsp--send-will-save-p)
   5182         (lsp-notify "textDocument/willSave" params))
   5183       (when (and (lsp--send-will-save-wait-until-p) lsp-before-save-edits)
   5184         (let ((lsp-response-timeout 0.1))
   5185           (condition-case nil
   5186               (lsp--apply-text-edits
   5187                (lsp-request "textDocument/willSaveWaitUntil"
   5188                             params)
   5189                'before-save)
   5190             (error)))))))
   5191 
   5192 (defun lsp--on-auto-save ()
   5193   "Handler for auto-save."
   5194   (when (lsp--send-will-save-p)
   5195     (with-demoted-errors "Error in ‘lsp--on-auto-save’: %S"
   5196       (lsp-notify "textDocument/willSave" (lsp--will-save-text-document-params 2)))))
   5197 
   5198 (defun lsp--text-document-did-save ()
   5199   "Executed when the file is closed, added to `after-save-hook''."
   5200   (when (lsp--send-did-save-p)
   5201     (with-demoted-errors "Error on ‘lsp--text-document-did-save: %S’"
   5202       (lsp-notify "textDocument/didSave"
   5203                   `( :textDocument ,(lsp--versioned-text-document-identifier)
   5204                      ,@(when (lsp--save-include-text-p)
   5205                          (list :text (lsp--buffer-content))))))))
   5206 
   5207 (defun lsp--text-document-position-params (&optional identifier position)
   5208   "Make TextDocumentPositionParams for the current point in the current document.
   5209 If IDENTIFIER and POSITION are non-nil, they will be used as the document
   5210 identifier and the position respectively."
   5211   (list :textDocument (or identifier (lsp--text-document-identifier))
   5212         :position (or position (lsp--cur-position))))
   5213 
   5214 (defun lsp--get-buffer-diagnostics ()
   5215   "Return buffer diagnostics."
   5216   (gethash (or
   5217             (plist-get lsp--virtual-buffer :buffer-file-name)
   5218             (lsp--fix-path-casing (buffer-file-name)))
   5219            (lsp-diagnostics t)))
   5220 
   5221 (defun lsp-cur-line-diagnostics ()
   5222   "Return any diagnostics that apply to the current line."
   5223   (-let [(&plist :start (&plist :line start) :end (&plist :line end)) (lsp--region-or-line)]
   5224     (cl-coerce (-filter
   5225                 (-lambda ((&Diagnostic :range (&Range :start (&Position :line))))
   5226                   (and (>= line start) (<= line end)))
   5227                 (lsp--get-buffer-diagnostics))
   5228                'vector)))
   5229 
   5230 (lsp-defun lsp-range-overlapping?((left &as &Range :start left-start :end left-end)
   5231                                   (right &as &Range :start right-start :end right-end))
   5232   (or (lsp-point-in-range? right-start left)
   5233       (lsp-point-in-range? right-end left)
   5234       (lsp-point-in-range? left-start right)
   5235       (lsp-point-in-range? left-end right)))
   5236 
   5237 (defun lsp-make-position-1 (position)
   5238   (lsp-make-position :line (plist-get position :line)
   5239                      :character (plist-get position :character)))
   5240 
   5241 (defun lsp-cur-possition-diagnostics ()
   5242   "Return any diagnostics that apply to the current line."
   5243   (-let* ((start (if (use-region-p) (region-beginning) (point)))
   5244           (end (if (use-region-p) (region-end) (point)))
   5245           (current-range (lsp-make-range :start (lsp-make-position-1 (lsp-point-to-position start))
   5246                                          :end (lsp-make-position-1 (lsp-point-to-position end)))))
   5247     (->> (lsp--get-buffer-diagnostics)
   5248          (-filter
   5249           (-lambda ((&Diagnostic :range))
   5250             (lsp-range-overlapping? range current-range)))
   5251          (apply 'vector))))
   5252 
   5253 (defalias 'lsp--cur-line-diagnotics 'lsp-cur-line-diagnostics)
   5254 
   5255 (defun lsp--extract-line-from-buffer (pos)
   5256   "Return the line pointed to by POS (a Position object) in the current buffer."
   5257   (let* ((point (lsp--position-to-point pos))
   5258          (inhibit-field-text-motion t))
   5259     (save-excursion
   5260       (goto-char point)
   5261       (buffer-substring (line-beginning-position) (line-end-position)))))
   5262 
   5263 (lsp-defun lsp--xref-make-item (filename (&Range :start (start &as &Position :character start-char :line start-line)
   5264                                                  :end (end &as &Position :character end-char)))
   5265   "Return a xref-item from a RANGE in FILENAME."
   5266   (let* ((line (lsp--extract-line-from-buffer start))
   5267          (len (length line)))
   5268     (add-face-text-property (max (min start-char len) 0)
   5269                             (max (min end-char len) 0)
   5270                             'xref-match t line)
   5271     ;; LINE is nil when FILENAME is not being current visited by any buffer.
   5272     (xref-make-match (or line filename)
   5273                      (xref-make-file-location
   5274                       filename
   5275                       (lsp-translate-line (1+ start-line))
   5276                       (lsp-translate-column start-char))
   5277                      (- end-char start-char))))
   5278 
   5279 (defun lsp--location-uri (loc)
   5280   (if (lsp-location? loc)
   5281       (lsp:location-uri loc)
   5282     (lsp:location-link-target-uri loc)))
   5283 
   5284 (lsp-defun lsp-goto-location ((loc &as &Location :uri :range (&Range :start)))
   5285   "Go to location."
   5286   (let ((path (lsp--uri-to-path uri)))
   5287     (if (f-exists? path)
   5288         (with-current-buffer (find-file path)
   5289           (goto-char (lsp--position-to-point start)))
   5290       (error "There is no file %s" path))))
   5291 
   5292 (defun lsp--location-range (loc)
   5293   (if (lsp-location? loc)
   5294       (lsp:location-range loc)
   5295     (lsp:location-link-target-selection-range loc)))
   5296 
   5297 (defun lsp--locations-to-xref-items (locations)
   5298   "Return a list of `xref-item' given LOCATIONS, which can be of
   5299 type Location, LocationLink, Location[] or LocationLink[]."
   5300   (setq locations
   5301         (pcase locations
   5302           ((seq (or (lsp-interface Location)
   5303                     (lsp-interface LocationLink)))
   5304            (append locations nil))
   5305           ((or (lsp-interface Location)
   5306                (lsp-interface LocationLink))
   5307            (list locations))))
   5308 
   5309   (cl-labels ((get-xrefs-in-file
   5310                (file-locs)
   5311                (-let [(filename . matches) file-locs]
   5312                  (condition-case err
   5313                      (let ((visiting (find-buffer-visiting filename))
   5314                            (fn (lambda (loc)
   5315                                  (lsp-with-filename filename
   5316                                    (lsp--xref-make-item filename
   5317                                                         (lsp--location-range loc))))))
   5318                        (if visiting
   5319                            (with-current-buffer visiting
   5320                              (seq-map fn matches))
   5321                          (when (file-readable-p filename)
   5322                            (with-temp-buffer
   5323                              (insert-file-contents-literally filename)
   5324                              (seq-map fn matches)))))
   5325                    (error (lsp-warn "Failed to process xref entry for filename '%s': %s"
   5326                                     filename (error-message-string err)))
   5327                    (file-error (lsp-warn "Failed to process xref entry, file-error, '%s': %s"
   5328                                          filename (error-message-string err)))))))
   5329 
   5330     (->> locations
   5331          (seq-sort #'lsp--location-before-p)
   5332          (seq-group-by (-compose #'lsp--uri-to-path #'lsp--location-uri))
   5333          (seq-map #'get-xrefs-in-file)
   5334          (apply #'nconc))))
   5335 
   5336 (defun lsp--location-before-p (left right)
   5337   "Sort first by file, then by line, then by column."
   5338   (let ((left-uri (lsp--location-uri left))
   5339         (right-uri (lsp--location-uri right)))
   5340     (if (not (string= left-uri right-uri))
   5341         (string< left-uri right-uri)
   5342       (-let (((&Range :start left-start) (lsp--location-range left))
   5343              ((&Range :start right-start) (lsp--location-range right)))
   5344         (lsp--position-compare right-start left-start)))))
   5345 
   5346 (defun lsp--make-reference-params (&optional td-position exclude-declaration)
   5347   "Make a ReferenceParam object.
   5348 If TD-POSITION is non-nil, use it as TextDocumentPositionParams object instead.
   5349 If EXCLUDE-DECLARATION is non-nil, request the server to include declarations."
   5350   (let ((json-false :json-false))
   5351     (plist-put (or td-position (lsp--text-document-position-params))
   5352                :context `(:includeDeclaration ,(lsp-json-bool (not exclude-declaration))))))
   5353 
   5354 (defun lsp--cancel-request (id)
   5355   "Cancel request with ID in all workspaces."
   5356   (lsp-foreach-workspace
   5357    (->> lsp--cur-workspace lsp--workspace-client lsp--client-response-handlers (remhash id))
   5358    (lsp-notify "$/cancelRequest" `(:id ,id))))
   5359 
   5360 (defvar-local lsp--hover-saved-bounds nil)
   5361 
   5362 (defun lsp-eldoc-function (cb &rest _ignored)
   5363   "`lsp-mode' eldoc function to display hover info (based on `textDocument/hover')."
   5364   (if (and lsp--hover-saved-bounds
   5365            (lsp--point-in-bounds-p lsp--hover-saved-bounds))
   5366       lsp--eldoc-saved-message
   5367     (setq lsp--hover-saved-bounds nil
   5368           lsp--eldoc-saved-message nil)
   5369     (if (looking-at-p "[[:space:]\n]")
   5370         (setq lsp--eldoc-saved-message nil) ; And returns nil.
   5371       (when (and lsp-eldoc-enable-hover (lsp-feature? "textDocument/hover"))
   5372         (lsp-request-async
   5373          "textDocument/hover"
   5374          (lsp--text-document-position-params)
   5375          (-lambda ((hover &as &Hover? :range? :contents))
   5376            (setq lsp--hover-saved-bounds (when range?
   5377                                            (lsp--range-to-region range?)))
   5378            (funcall cb (setq lsp--eldoc-saved-message
   5379                              (when contents
   5380                                (lsp--render-on-hover-content
   5381                                 contents
   5382                                 lsp-eldoc-render-all)))))
   5383          :error-handler #'ignore
   5384          :mode 'tick
   5385          :cancel-token :eldoc-hover)))))
   5386 
   5387 (defun lsp--point-on-highlight? ()
   5388   (-some? (lambda (overlay)
   5389             (overlay-get overlay 'lsp-highlight))
   5390           (overlays-at (point))))
   5391 
   5392 (defun lsp--cleanup-highlights-if-needed ()
   5393   (when (and lsp-enable-symbol-highlighting
   5394              lsp--have-document-highlights
   5395              (not (lsp--point-on-highlight?)))
   5396     (lsp--remove-overlays 'lsp-highlight)
   5397     (setq lsp--have-document-highlights nil)
   5398     (lsp-cancel-request-by-token :highlights)))
   5399 
   5400 (defvar-local lsp--symbol-bounds-of-last-highlight-invocation nil
   5401   "The bounds of the symbol from which `lsp--document-highlight'
   5402   most recently requested highlights.")
   5403 
   5404 (defun lsp--document-highlight ()
   5405   (when (lsp-feature? "textDocument/documentHighlight")
   5406     (let ((curr-sym-bounds (bounds-of-thing-at-point 'symbol)))
   5407       (unless (or (looking-at-p "[[:space:]\n]")
   5408                   (not lsp-enable-symbol-highlighting)
   5409                   (and lsp--have-document-highlights
   5410                        curr-sym-bounds
   5411                        (equal curr-sym-bounds
   5412                               lsp--symbol-bounds-of-last-highlight-invocation)))
   5413         (setq lsp--symbol-bounds-of-last-highlight-invocation
   5414               curr-sym-bounds)
   5415         (lsp-request-async "textDocument/documentHighlight"
   5416                            (lsp--text-document-position-params)
   5417                            #'lsp--document-highlight-callback
   5418                            :mode 'tick
   5419                            :cancel-token :highlights)))))
   5420 
   5421 (defun lsp--help-open-link (&rest _)
   5422   "Open markdown link at point via mouse or keyboard."
   5423   (interactive "P")
   5424   (let ((buffer-list-update-hook nil))
   5425     (-let [(buffer point) (if-let* ((valid (and (listp last-input-event)
   5426                                                 (eq (car last-input-event) 'mouse-2)))
   5427                                     (event (cadr last-input-event))
   5428                                     (win (posn-window event))
   5429                                     (buffer (window-buffer win)))
   5430                               `(,buffer ,(posn-point event))
   5431                             `(,(current-buffer) ,(point)))]
   5432       (with-current-buffer buffer
   5433         (when-let* ((face (get-text-property point 'face))
   5434                     (url (or (and (eq face 'markdown-link-face)
   5435                                   (get-text-property point 'help-echo))
   5436                              (and (memq face '(markdown-url-face markdown-plain-url-face))
   5437                                   (nth 3 (markdown-link-at-pos point))))))
   5438           (lsp--document-link-handle-target url))))))
   5439 
   5440 (defvar lsp-help-mode-map
   5441   (-doto (make-sparse-keymap)
   5442     (define-key [remap markdown-follow-link-at-point] #'lsp--help-open-link))
   5443   "Keymap for `lsp-help-mode'.")
   5444 
   5445 (define-derived-mode lsp-help-mode help-mode "LspHelp"
   5446   "Major mode for displaying lsp help.")
   5447 
   5448 (defun lsp-describe-thing-at-point ()
   5449   "Display the type signature and documentation of the thing at point."
   5450   (interactive)
   5451   (let ((contents (-some->> (lsp--text-document-position-params)
   5452                     (lsp--make-request "textDocument/hover")
   5453                     (lsp--send-request)
   5454                     (lsp:hover-contents))))
   5455     (if (and contents (not (equal contents "")))
   5456         (let ((lsp-help-buf-name "*lsp-help*"))
   5457           (with-current-buffer (get-buffer-create lsp-help-buf-name)
   5458             (delay-mode-hooks
   5459               (lsp-help-mode)
   5460               (with-help-window lsp-help-buf-name
   5461                 (insert
   5462                  (mapconcat 'string-trim-right
   5463                             (split-string (lsp--render-on-hover-content contents t) "\n")
   5464                             "\n"))))
   5465             (run-mode-hooks)))
   5466       (lsp--info "No content at point."))))
   5467 
   5468 (defun lsp--point-in-bounds-p (bounds)
   5469   "Return whether the current point is within BOUNDS."
   5470   (and (<= (car bounds) (point)) (< (point) (cdr bounds))))
   5471 
   5472 (defun lsp-get-renderer (language)
   5473   "Get renderer for LANGUAGE."
   5474   (lambda (str)
   5475     (lsp--render-string str language)))
   5476 
   5477 (defun lsp--setup-markdown (mode)
   5478   "Setup the ‘markdown-mode’ in the frame.
   5479 MODE is the mode used in the parent frame."
   5480   (make-local-variable 'markdown-code-lang-modes)
   5481   (dolist (mark (alist-get mode lsp-custom-markup-modes))
   5482     (add-to-list 'markdown-code-lang-modes (cons mark mode)))
   5483   (setq-local markdown-fontify-code-blocks-natively t)
   5484   (setq-local markdown-fontify-code-block-default-mode mode)
   5485   (setq-local markdown-hide-markup t)
   5486 
   5487   ;; Render some common HTML entities.
   5488   ;; This should really happen in markdown-mode instead,
   5489   ;; but it doesn't, so we do it here for now.
   5490   (setq prettify-symbols-alist
   5491         (cl-loop for i from 0 to 255
   5492                  collect (cons (format "&#x%02X;" i) i)))
   5493   (push '("&lt;" . ?<) prettify-symbols-alist)
   5494   (push '("&gt;" . ?>) prettify-symbols-alist)
   5495   (push '("&amp;" . ?&) prettify-symbols-alist)
   5496   (push '("&nbsp;" . ? ) prettify-symbols-alist)
   5497   (setq prettify-symbols-compose-predicate
   5498         (lambda (_start _end _match) t))
   5499   (prettify-symbols-mode 1))
   5500 
   5501 (defvar lsp-help-link-keymap
   5502   (let ((map (make-sparse-keymap)))
   5503     (define-key map [mouse-2] #'lsp--help-open-link)
   5504     (define-key map "\r" #'lsp--help-open-link)
   5505     map)
   5506   "Keymap active on links in *lsp-help* mode.")
   5507 
   5508 (defun lsp--fix-markdown-links ()
   5509   (let ((inhibit-read-only t)
   5510         (inhibit-modification-hooks t)
   5511         (prop))
   5512     (save-restriction
   5513       (goto-char (point-min))
   5514       (while (setq prop (markdown-find-next-prop 'face))
   5515         (let ((end (or (next-single-property-change (car prop) 'face)
   5516                        (point-max))))
   5517           (when (memq (get-text-property (car prop) 'face)
   5518                       '(markdown-link-face
   5519                         markdown-url-face
   5520                         markdown-plain-url-face))
   5521             (add-text-properties (car prop) end
   5522                                  (list 'button t
   5523                                        'category 'lsp-help-link
   5524                                        'follow-link t
   5525                                        'keymap lsp-help-link-keymap)))
   5526           (goto-char end))))))
   5527 
   5528 (defun lsp--buffer-string-visible ()
   5529   "Return visible buffer string.
   5530 Stolen from `org-copy-visible'."
   5531   (let ((temp (generate-new-buffer " *temp*"))
   5532         (beg (point-min))
   5533         (end (point-max)))
   5534     (while (/= beg end)
   5535       (when (get-char-property beg 'invisible)
   5536         (setq beg (next-single-char-property-change beg 'invisible nil end)))
   5537       (let* ((next (next-single-char-property-change beg 'invisible nil end))
   5538              (substring (buffer-substring beg next)))
   5539         (with-current-buffer temp (insert substring))
   5540         ;; (setq result (concat result substring))
   5541         (setq beg next)))
   5542     (setq deactivate-mark t)
   5543     (prog1 (with-current-buffer temp
   5544              (s-chop-suffix "\n" (buffer-string)))
   5545       (kill-buffer temp))))
   5546 
   5547 (defvar lsp-buffer-major-mode nil
   5548   "Holds the major mode when fontification function is running.
   5549 See #2588")
   5550 
   5551 (defvar view-inhibit-help-message)
   5552 
   5553 (defun lsp--render-markdown ()
   5554   "Render markdown."
   5555 
   5556   (let ((markdown-enable-math nil))
   5557     (goto-char (point-min))
   5558     (while (re-search-forward
   5559             (rx (and "\\" (group (or "\\" "`" "*" "_" ":" "/"
   5560                                      "{" "}" "[" "]" "(" ")"
   5561                                      "#" "+" "-" "." "!" "|"))))
   5562             nil t)
   5563       (replace-match (rx (backref 1))))
   5564 
   5565     ;; markdown-mode v2.3 does not yet provide gfm-view-mode
   5566     (if (fboundp 'gfm-view-mode)
   5567         (let ((view-inhibit-help-message t))
   5568           (gfm-view-mode))
   5569       (gfm-mode))
   5570 
   5571     (lsp--setup-markdown lsp-buffer-major-mode)))
   5572 
   5573 (defvar lsp--display-inline-image-alist
   5574   '((lsp--render-markdown
   5575      (:regexp
   5576       "!\\[.*?\\](data:image/[a-zA-Z]+;base64,\\([A-Za-z0-9+/\n]+?=*?\\)\\(|[^)]+\\)?)"
   5577       :sexp
   5578       (create-image
   5579        (base64-decode-string
   5580         (buffer-substring-no-properties (match-beginning 1) (match-end 1)))
   5581        nil t))))
   5582   "Replaced string regexp and function returning image.
   5583 Each element should have the form (MODE . (PROPERTY-LIST...)).
   5584 MODE (car) is function which is defined in `lsp-language-id-configuration'.
   5585 Cdr should be list of PROPERTY-LIST.
   5586 
   5587 Each PROPERTY-LIST should have properties:
   5588 :regexp  Regexp which determines what string is relpaced to image.
   5589          You should also get information of image, by parenthesis constructs.
   5590          By default, all matched string is replaced to image, but you can
   5591          change index of replaced string by keyword :replaced-index.
   5592 
   5593 :sexp    Return image when evaluated. You can use information of regexp
   5594          by using (match-beggining N), (match-end N) or (match-substring N).
   5595 
   5596 In addition, each can have property:
   5597 :replaced-index  Determine index which is used to replace regexp to image.
   5598                  The value means first argument of `match-beginning' and
   5599                  `match-end'. If omitted, interpreted as index 0.")
   5600 
   5601 (defcustom lsp-display-inline-image t
   5602   "Showing inline image or not."
   5603   :group 'lsp-mode
   5604   :type 'boolean)
   5605 
   5606 (defcustom lsp-enable-suggest-server-download t
   5607   "When non-nil enable server downloading suggestions."
   5608   :group 'lsp-mode
   5609   :type 'boolean
   5610   :package-version '(lsp-mode . "9.0.0"))
   5611 
   5612 (defcustom lsp-auto-register-remote-clients t
   5613   "When non-nil register remote when registering the local one."
   5614   :group 'lsp-mode
   5615   :type 'boolean
   5616   :package-version '(lsp-mode . "9.0.0"))
   5617 
   5618 (defun lsp--display-inline-image (mode)
   5619   "Add image property if available."
   5620   (let ((plist-list (cdr (assq mode lsp--display-inline-image-alist))))
   5621     (when (and (display-images-p) lsp-display-inline-image)
   5622       (cl-loop
   5623        for plist in plist-list
   5624        with regexp with replaced-index
   5625        do
   5626        (setq regexp (plist-get plist :regexp))
   5627        (setq replaced-index (or (plist-get plist :replaced-index) 0))
   5628 
   5629        (font-lock-remove-keywords nil (list regexp replaced-index))
   5630        (let ((inhibit-read-only t))
   5631          (save-excursion
   5632            (goto-char (point-min))
   5633            (while (re-search-forward regexp nil t)
   5634              (set-text-properties
   5635               (match-beginning replaced-index) (match-end replaced-index)
   5636               nil)
   5637              (add-text-properties
   5638               (match-beginning replaced-index) (match-end replaced-index)
   5639               `(display ,(eval (plist-get plist :sexp)))))))))))
   5640 
   5641 (defun lsp--fontlock-with-mode (str mode)
   5642   "Fontlock STR with MODE."
   5643   (let ((lsp-buffer-major-mode major-mode))
   5644     (with-temp-buffer
   5645       (with-demoted-errors "Error during doc rendering: %s"
   5646         (insert str)
   5647         (delay-mode-hooks (funcall mode))
   5648         (cl-flet ((window-body-width () lsp-window-body-width))
   5649           ;; This can go wrong in some cases, and the fontification would
   5650           ;; not work as expected.
   5651           ;;
   5652           ;; See #2984
   5653           (ignore-errors (font-lock-ensure))
   5654           (lsp--display-inline-image mode)
   5655           (when (eq mode 'lsp--render-markdown)
   5656             (lsp--fix-markdown-links))))
   5657       (lsp--buffer-string-visible))))
   5658 
   5659 (defun lsp--render-string (str language)
   5660   "Render STR using `major-mode' corresponding to LANGUAGE.
   5661 When language is nil render as markup if `markdown-mode' is loaded."
   5662   (setq str (s-replace "\r" "" (or str "")))
   5663   (if-let* ((modes (-keep (-lambda ((mode . lang))
   5664                             (when (and (equal lang language) (functionp mode))
   5665                               mode))
   5666                           lsp-language-id-configuration))
   5667             (mode (car (or (member major-mode modes) modes))))
   5668       (lsp--fontlock-with-mode str mode)
   5669     str))
   5670 
   5671 (defun lsp--render-element (content)
   5672   "Render CONTENT element."
   5673   (let ((inhibit-message t))
   5674     (or
   5675      (pcase content
   5676        ((lsp-interface MarkedString :value :language)
   5677         (lsp--render-string value language))
   5678        ((lsp-interface MarkupContent :value :kind)
   5679         (lsp--render-string value kind))
   5680        ;; plain string
   5681        ((pred stringp) (lsp--render-string content "markdown"))
   5682        ((pred null) "")
   5683        (_ (error "Failed to handle %s" content)))
   5684      "")))
   5685 
   5686 (defun lsp--create-unique-string-fn ()
   5687   (let (elements)
   5688     (lambda (element)
   5689       (let ((count (cl-count element elements :test #'string=)))
   5690         (prog1 (if (zerop count)
   5691                    element
   5692                  (format "%s (%s)" element count))
   5693           (push element elements))))))
   5694 
   5695 (defun lsp--select-action (actions)
   5696   "Select an action to execute from ACTIONS."
   5697   (cond
   5698    ((seq-empty-p actions) (signal 'lsp-no-code-actions nil))
   5699    ((and (eq (seq-length actions) 1) lsp-auto-execute-action)
   5700     (lsp-seq-first actions))
   5701    (t (let ((completion-ignore-case t))
   5702         (lsp--completing-read "Select code action: "
   5703                               (seq-into actions 'list)
   5704                               (-compose (lsp--create-unique-string-fn)
   5705                                         #'lsp:code-action-title)
   5706                               nil t)))))
   5707 
   5708 (defun lsp--workspace-server-id (workspace)
   5709   "Return the server ID of WORKSPACE."
   5710   (-> workspace lsp--workspace-client lsp--client-server-id))
   5711 
   5712 (defun lsp--handle-rendered-for-echo-area (contents)
   5713   "Return a single line from RENDERED, appropriate for display in the echo area."
   5714   (pcase (lsp-workspaces)
   5715     (`(,workspace)
   5716      (lsp-clients-extract-signature-on-hover contents (lsp--workspace-server-id workspace)))
   5717     ;; For projects with multiple active workspaces we also default to
   5718     ;; render the first line.
   5719     (_ (lsp-clients-extract-signature-on-hover contents nil))))
   5720 
   5721 (cl-defmethod lsp-clients-extract-signature-on-hover (contents _server-id)
   5722   "Extract a representative line from CONTENTS, to show in the echo area."
   5723   (car (s-lines (s-trim (lsp--render-element contents)))))
   5724 
   5725 (defun lsp--render-on-hover-content (contents render-all)
   5726   "Render the content received from `textDocument/hover' request.
   5727 CONTENTS  - MarkedString | MarkedString[] | MarkupContent
   5728 RENDER-ALL - nil if only the signature should be rendered."
   5729   (cond
   5730    ((lsp-markup-content? contents)
   5731     ;; MarkupContent.
   5732     ;; It tends to be long and is not suitable to display fully in the echo area.
   5733     ;; Just display the first line which is typically the signature.
   5734     (if render-all
   5735         (lsp--render-element contents)
   5736       (lsp--handle-rendered-for-echo-area contents)))
   5737    ((and (stringp contents) (not (string-match-p "\n" contents)))
   5738     ;; If the contents is a single string containing a single line,
   5739     ;; render it always.
   5740     (lsp--render-element contents))
   5741    (t
   5742     ;; MarkedString -> MarkedString[]
   5743     (when (or (lsp-marked-string? contents) (stringp contents))
   5744       (setq contents (list contents)))
   5745     ;; Consider the signature consisting of the elements who have a renderable
   5746     ;; "language" property. When render-all is nil, ignore other elements.
   5747     (string-join
   5748      (seq-map
   5749       #'lsp--render-element
   5750       (if render-all
   5751           contents
   5752         ;; Only render contents that have an available renderer.
   5753         (seq-take
   5754          (seq-filter
   5755           (-andfn #'lsp-marked-string?
   5756                   (-compose #'lsp-get-renderer #'lsp:marked-string-language))
   5757           contents)
   5758          1)))
   5759      (if (bound-and-true-p page-break-lines-mode)
   5760          "\n\n"
   5761        "\n")))))
   5762 
   5763 
   5764 
   5765 (defvar lsp-signature-mode-map
   5766   (-doto (make-sparse-keymap)
   5767     (define-key (kbd "M-n") #'lsp-signature-next)
   5768     (define-key (kbd "M-p") #'lsp-signature-previous)
   5769     (define-key (kbd "M-a") #'lsp-signature-toggle-full-docs)
   5770     (define-key (kbd "C-c C-k") #'lsp-signature-stop)
   5771     (define-key (kbd "C-g") #'lsp-signature-stop))
   5772   "Keymap for `lsp-signature-mode'.")
   5773 
   5774 (define-minor-mode lsp-signature-mode
   5775   "Mode used to show signature popup."
   5776   :keymap lsp-signature-mode-map
   5777   :lighter ""
   5778   :group 'lsp-mode)
   5779 
   5780 (defun lsp-signature-stop ()
   5781   "Stop showing current signature help."
   5782   (interactive)
   5783   (lsp-cancel-request-by-token :signature)
   5784   (remove-hook 'post-command-hook #'lsp-signature)
   5785   (funcall lsp-signature-function nil)
   5786   (lsp-signature-mode -1))
   5787 
   5788 (declare-function page-break-lines--update-display-tables "ext:page-break-lines")
   5789 
   5790 (defun lsp--setup-page-break-mode-if-present ()
   5791   "Enable `page-break-lines-mode' in current buffer."
   5792   (when (fboundp 'page-break-lines-mode)
   5793     (page-break-lines-mode)
   5794     ;; force page-break-lines-mode to update the display tables.
   5795     (page-break-lines--update-display-tables)))
   5796 
   5797 (defun lsp-lv-message (message)
   5798   (add-hook 'lv-window-hook #'lsp--setup-page-break-mode-if-present)
   5799   (if message
   5800       (progn
   5801         (setq lsp--signature-last-buffer (current-buffer))
   5802         (let ((lv-force-update t))
   5803           (lv-message "%s" message)))
   5804     (lv-delete-window)
   5805     (remove-hook 'lv-window-hook #'lsp--setup-page-break-mode-if-present)))
   5806 
   5807 (declare-function posframe-show "ext:posframe")
   5808 (declare-function posframe-hide "ext:posframe")
   5809 (declare-function posframe-poshandler-point-bottom-left-corner-upward "ext:posframe")
   5810 
   5811 (defface lsp-signature-posframe
   5812   '((t :inherit tooltip))
   5813   "Background and foreground for `lsp-signature-posframe'."
   5814   :group 'lsp-mode)
   5815 
   5816 (defvar lsp-signature-posframe-params
   5817   (list :poshandler #'posframe-poshandler-point-bottom-left-corner-upward
   5818         :height 10
   5819         :width 60
   5820         :border-width 1
   5821         :min-width 60)
   5822   "Params for signature and `posframe-show'.")
   5823 
   5824 (defun lsp-signature-posframe (str)
   5825   "Use posframe to show the STR signatureHelp string."
   5826   (if str
   5827       (apply #'posframe-show
   5828              (with-current-buffer (get-buffer-create " *lsp-signature*")
   5829                (erase-buffer)
   5830                (insert str)
   5831                (visual-line-mode 1)
   5832                (lsp--setup-page-break-mode-if-present)
   5833                (current-buffer))
   5834              (append
   5835               lsp-signature-posframe-params
   5836               (list :position (point)
   5837                     :background-color (face-attribute 'lsp-signature-posframe :background nil t)
   5838                     :foreground-color (face-attribute 'lsp-signature-posframe :foreground nil t)
   5839                     :border-color (face-attribute (if (facep 'child-frame-border)
   5840                                                       'child-frame-border
   5841                                                     'internal-border)
   5842                                                   :background nil t))))
   5843     (posframe-hide " *lsp-signature*")))
   5844 
   5845 (defun lsp--handle-signature-update (signature)
   5846   (let ((message
   5847          (if (lsp-signature-help? signature)
   5848              (lsp--signature->message signature)
   5849            (mapconcat #'lsp--signature->message signature "\n"))))
   5850     (if (s-present? message)
   5851         (funcall lsp-signature-function message)
   5852       (lsp-signature-stop))))
   5853 
   5854 (defun lsp-signature-activate ()
   5855   "Activate signature help.
   5856 It will show up only if current point has signature help."
   5857   (interactive)
   5858   (setq lsp--signature-last nil
   5859         lsp--signature-last-index nil
   5860         lsp--signature-last-buffer (current-buffer))
   5861   (add-hook 'post-command-hook #'lsp-signature)
   5862   (lsp-signature-mode t))
   5863 
   5864 (defcustom lsp-signature-cycle t
   5865   "Whether `lsp-signature-next' and prev should cycle."
   5866   :type 'boolean
   5867   :group 'lsp-mode)
   5868 
   5869 (defun lsp-signature-next ()
   5870   "Show next signature."
   5871   (interactive)
   5872   (let ((nsigs (length (lsp:signature-help-signatures lsp--signature-last))))
   5873     (when (and lsp--signature-last-index
   5874                lsp--signature-last
   5875                (or lsp-signature-cycle (< (1+ lsp--signature-last-index) nsigs)))
   5876       (setq lsp--signature-last-index (% (1+ lsp--signature-last-index) nsigs))
   5877       (funcall lsp-signature-function (lsp--signature->message lsp--signature-last)))))
   5878 
   5879 (defun lsp-signature-previous ()
   5880   "Next signature."
   5881   (interactive)
   5882   (when (and lsp--signature-last-index
   5883              lsp--signature-last
   5884              (or lsp-signature-cycle (not (zerop lsp--signature-last-index))))
   5885     (setq lsp--signature-last-index (1- (if (zerop lsp--signature-last-index)
   5886                                             (length (lsp:signature-help-signatures lsp--signature-last))
   5887                                           lsp--signature-last-index)))
   5888     (funcall lsp-signature-function (lsp--signature->message lsp--signature-last))))
   5889 
   5890 (defun lsp-signature-toggle-full-docs ()
   5891   "Toggle full/partial signature documentation."
   5892   (interactive)
   5893   (let ((all? (not (numberp lsp-signature-doc-lines))))
   5894     (setq lsp-signature-doc-lines (if all?
   5895                                       (or (car-safe lsp-signature-doc-lines)
   5896                                           20)
   5897                                     (list lsp-signature-doc-lines))))
   5898   (lsp-signature-activate))
   5899 
   5900 (defface lsp-signature-highlight-function-argument
   5901   '((t :inherit eldoc-highlight-function-argument))
   5902   "The face to use to highlight function arguments in signatures."
   5903   :group 'lsp-mode)
   5904 
   5905 (defun lsp--signature->message (signature-help)
   5906   "Generate eldoc message from SIGNATURE-HELP response."
   5907   (setq lsp--signature-last signature-help)
   5908 
   5909   (when (and signature-help (not (seq-empty-p (lsp:signature-help-signatures signature-help))))
   5910     (-let* (((&SignatureHelp :active-signature?
   5911                              :active-parameter?
   5912                              :signatures) signature-help)
   5913             (active-signature? (or lsp--signature-last-index active-signature? 0))
   5914             (_ (setq lsp--signature-last-index active-signature?))
   5915             ((signature &as &SignatureInformation? :label :parameters?) (seq-elt signatures active-signature?))
   5916             (prefix (if (= (length signatures) 1)
   5917                         ""
   5918                       (concat (propertize (format " %s/%s"
   5919                                                   (1+ active-signature?)
   5920                                                   (length signatures))
   5921                                           'face 'success)
   5922                               " ")))
   5923             (method-docs (when
   5924                              (and lsp-signature-render-documentation
   5925                                   (or (not (numberp lsp-signature-doc-lines)) (< 0 lsp-signature-doc-lines)))
   5926                            (let ((docs (lsp--render-element
   5927                                         (lsp:parameter-information-documentation? signature))))
   5928                              (when (s-present? docs)
   5929                                (concat
   5930                                 "\n"
   5931                                 (if (fboundp 'page-break-lines-mode)
   5932                                     "\n"
   5933                                   "")
   5934                                 (if (and (numberp lsp-signature-doc-lines)
   5935                                          (> (length (s-lines docs)) lsp-signature-doc-lines))
   5936                                     (concat (s-join "\n" (-take lsp-signature-doc-lines (s-lines docs)))
   5937                                             (propertize "\nTruncated..." 'face 'highlight))
   5938                                   docs)))))))
   5939       (when (and active-parameter? (not (seq-empty-p parameters?)))
   5940         (-when-let* ((param (when (and (< -1 active-parameter? (length parameters?)))
   5941                               (seq-elt parameters? active-parameter?)))
   5942                      (selected-param-label (let ((label (lsp:parameter-information-label param)))
   5943                                              (if (stringp label) label (append label nil))))
   5944                      (start (if (stringp selected-param-label)
   5945                                 (s-index-of selected-param-label label)
   5946                               (cl-first selected-param-label)))
   5947                      (end (if (stringp selected-param-label)
   5948                               (+ start (length selected-param-label))
   5949                             (cl-second selected-param-label))))
   5950           (add-face-text-property start end 'lsp-signature-highlight-function-argument nil label)))
   5951       (concat prefix label method-docs))))
   5952 
   5953 (defun lsp-signature ()
   5954   "Display signature info (based on `textDocument/signatureHelp')"
   5955   (if (and lsp--signature-last-buffer
   5956            (not (equal (current-buffer) lsp--signature-last-buffer)))
   5957       (lsp-signature-stop)
   5958     (lsp-request-async "textDocument/signatureHelp"
   5959                        (lsp--text-document-position-params)
   5960                        #'lsp--handle-signature-update
   5961                        :cancel-token :signature)))
   5962 
   5963 
   5964 (defcustom lsp-overlay-document-color-char "■"
   5965   "Display the char represent the document color in overlay"
   5966   :type 'string
   5967   :group 'lsp-mode)
   5968 
   5969 ;; color presentation
   5970 (defun lsp--color-create-interactive-command (color range)
   5971   (lambda ()
   5972     (interactive)
   5973     (-let [(&ColorPresentation? :text-edit?
   5974                                 :additional-text-edits?)
   5975            (lsp--completing-read
   5976             "Select color presentation: "
   5977             (lsp-request
   5978              "textDocument/colorPresentation"
   5979              `( :textDocument ,(lsp--text-document-identifier)
   5980                 :color ,color
   5981                 :range ,range))
   5982             #'lsp:color-presentation-label
   5983             nil
   5984             t)]
   5985       (when text-edit?
   5986         (lsp--apply-text-edit text-edit?))
   5987       (when additional-text-edits?
   5988         (lsp--apply-text-edits additional-text-edits? 'color-presentation)))))
   5989 
   5990 (defun lsp--number->color (number)
   5991   (let ((result (format "%x"
   5992                         (round (* (or number 0) 255.0)))))
   5993     (if (= 1 (length result))
   5994         (concat "0" result)
   5995       result)))
   5996 
   5997 (defun lsp--document-color ()
   5998   "Document color handler."
   5999   (when (lsp-feature? "textDocument/documentColor")
   6000     (lsp-request-async
   6001      "textDocument/documentColor"
   6002      `(:textDocument ,(lsp--text-document-identifier))
   6003      (lambda (result)
   6004        (lsp--remove-overlays 'lsp-color)
   6005        (seq-do
   6006         (-lambda ((&ColorInformation :color (color &as &Color :red :green :blue)
   6007                                      :range))
   6008           (-let* (((beg . end) (lsp--range-to-region range))
   6009                   (overlay (make-overlay beg end))
   6010                   (command (lsp--color-create-interactive-command color range)))
   6011             (overlay-put overlay 'lsp-color t)
   6012             (overlay-put overlay 'evaporate t)
   6013             (overlay-put overlay
   6014                          'before-string
   6015                          (propertize
   6016                           lsp-overlay-document-color-char
   6017                           'face `((:foreground ,(format
   6018                                                  "#%s%s%s"
   6019                                                  (lsp--number->color red)
   6020                                                  (lsp--number->color green)
   6021                                                  (lsp--number->color blue))))
   6022                           'action command
   6023                           'mouse-face 'lsp-lens-mouse-face
   6024                           'local-map (-doto (make-sparse-keymap)
   6025                                        (define-key [mouse-1] command))))))
   6026         result))
   6027      :mode 'unchanged
   6028      :cancel-token :document-color-token)))
   6029 
   6030 
   6031 
   6032 (defun lsp--action-trigger-parameter-hints (_command)
   6033   "Handler for editor.action.triggerParameterHints."
   6034   (when (member :on-server-request lsp-signature-auto-activate)
   6035     (lsp-signature-activate)))
   6036 
   6037 (defun lsp--action-trigger-suggest (_command)
   6038   "Handler for editor.action.triggerSuggest."
   6039   (cond
   6040    ((and (bound-and-true-p company-mode)
   6041          (fboundp 'company-auto-begin)
   6042          (fboundp 'company-post-command))
   6043     (run-at-time 0 nil
   6044                  (lambda ()
   6045                    (let ((this-command 'company-idle-begin)
   6046                          (company-minimum-prefix-length 0))
   6047                      (company-auto-begin)
   6048                      (company-post-command)))))
   6049    (t
   6050     (completion-at-point))))
   6051 
   6052 (defconst lsp--default-action-handlers
   6053   (ht ("editor.action.triggerParameterHints" #'lsp--action-trigger-parameter-hints)
   6054       ("editor.action.triggerSuggest" #'lsp--action-trigger-suggest))
   6055   "Default action handlers.")
   6056 
   6057 (defun lsp--find-action-handler (command)
   6058   "Find action handler for particular COMMAND."
   6059   (or
   6060    (--some (-some->> it
   6061              (lsp--workspace-client)
   6062              (lsp--client-action-handlers)
   6063              (gethash command))
   6064            (lsp-workspaces))
   6065    (gethash command lsp--default-action-handlers)))
   6066 
   6067 (defun lsp--text-document-code-action-params (&optional kind)
   6068   "Code action params."
   6069   (list :textDocument (lsp--text-document-identifier)
   6070         :range (if (use-region-p)
   6071                    (lsp--region-to-range (region-beginning) (region-end))
   6072                  (lsp--region-to-range (point) (point)))
   6073         :context `( :diagnostics ,(lsp-cur-possition-diagnostics)
   6074                     ,@(when kind (list :only (vector kind))))))
   6075 
   6076 (defun lsp-code-actions-at-point (&optional kind)
   6077   "Retrieve the code actions for the active region or the current line.
   6078 It will filter by KIND if non nil."
   6079   (lsp-request "textDocument/codeAction" (lsp--text-document-code-action-params kind)))
   6080 
   6081 (defun lsp-execute-code-action-by-kind (command-kind)
   6082   "Execute code action by COMMAND-KIND."
   6083   (if-let* ((action (->> (lsp-get-or-calculate-code-actions command-kind)
   6084                         (-filter (-lambda ((&CodeAction :kind?))
   6085                                    (and kind? (s-prefix? command-kind kind?))))
   6086                         lsp--select-action)))
   6087       (lsp-execute-code-action action)
   6088     (signal 'lsp-no-code-actions '(command-kind))))
   6089 
   6090 (defalias 'lsp-get-or-calculate-code-actions 'lsp-code-actions-at-point)
   6091 
   6092 (lsp-defun lsp--execute-command ((action &as &Command :command :arguments?))
   6093   "Parse and execute a code ACTION represented as a Command LSP type."
   6094   (let ((server-id (->> (lsp-workspaces)
   6095                         (cl-first)
   6096                         (or lsp--cur-workspace)
   6097                         (lsp--workspace-client)
   6098                         (lsp--client-server-id))))
   6099     (condition-case nil
   6100         (with-no-warnings
   6101           (lsp-execute-command server-id (intern command) arguments?))
   6102       (cl-no-applicable-method
   6103        (if-let* ((action-handler (lsp--find-action-handler command)))
   6104            (funcall action-handler action)
   6105          (lsp-send-execute-command command arguments?))))))
   6106 
   6107 (lsp-defun lsp-execute-code-action ((action &as &CodeAction :command? :edit?))
   6108   "Execute code action ACTION. For example, when text under the
   6109 caret has a suggestion to apply a fix from an lsp-server, calling
   6110 this function will do so.
   6111 If ACTION is not set it will be selected from `lsp-code-actions-at-point'.
   6112 Request codeAction/resolve for more info if server supports."
   6113   (interactive (list (lsp--select-action (lsp-code-actions-at-point))))
   6114   (if (and (lsp-feature? "codeAction/resolve")
   6115            (not command?)
   6116            (not edit?))
   6117       (lsp--execute-code-action (lsp-request "codeAction/resolve" action))
   6118     (lsp--execute-code-action action)))
   6119 
   6120 (lsp-defun lsp--execute-code-action ((action &as &CodeAction :command? :edit?))
   6121   "Execute code action ACTION."
   6122   (when edit?
   6123     (lsp--apply-workspace-edit edit? 'code-action))
   6124 
   6125   (cond
   6126    ((stringp command?) (lsp--execute-command action))
   6127    ((lsp-command? command?) (progn
   6128                               (when-let* ((action-filter (->> (lsp-workspaces)
   6129                                                              (cl-first)
   6130                                                              (or lsp--cur-workspace)
   6131                                                              (lsp--workspace-client)
   6132                                                              (lsp--client-action-filter))))
   6133                                 (funcall action-filter command?))
   6134                               (lsp--execute-command command?)))))
   6135 
   6136 (lsp-defun lsp-fix-code-action-booleans ((&Command :arguments?) boolean-action-arguments)
   6137   "Patch incorrect boolean argument values in the provided `CodeAction' command
   6138 in place, based on the BOOLEAN-ACTION-ARGUMENTS list. The values
   6139 in this list can be either symbols or lists of symbols that
   6140 represent paths to boolean arguments in code actions:
   6141 
   6142 > (lsp-fix-code-action-booleans command `(:foo :bar (:some :nested :boolean)))
   6143 
   6144 When there are available code actions, the server sends
   6145 `lsp-mode' a list of possible command names and arguments as
   6146 JSON. `lsp-mode' parses all boolean false values as `nil'. As a
   6147 result code action arguments containing falsy values don't
   6148 roundtrip correctly because `lsp-mode' will end up sending null
   6149 values back to the client. This list makes it possible to
   6150 selectively transform `nil' values back into `:json-false'."
   6151   (seq-doseq (path boolean-action-arguments)
   6152     (seq-doseq (args arguments?)
   6153       (lsp--fix-nested-boolean args (if (listp path) path (list path))))))
   6154 
   6155 (defun lsp--fix-nested-boolean (structure path)
   6156   "Traverse STRUCTURE using the paths from the PATH list, changing the value to
   6157 `:json-false' if it was `nil'. PATH should be a list containing
   6158 one or more symbols, and STRUCTURE should be compatible with
   6159 `lsp-member?', `lsp-get', and `lsp-put'."
   6160   (let ((key (car path))
   6161         (rest (cdr path)))
   6162     (if (null rest)
   6163         ;; `lsp-put' returns `nil' both when the key doesn't exist and when the
   6164         ;; value is `nil', so we need to explicitly check its presence here
   6165         (when (and (lsp-member? structure key) (not (lsp-get structure key)))
   6166           (lsp-put structure key :json-false))
   6167       ;; If `key' does not exist, then we'll silently ignore it
   6168       (when-let* ((child (lsp-get structure key)))
   6169         (lsp--fix-nested-boolean child rest)))))
   6170 
   6171 (defvar lsp--formatting-indent-alist
   6172   ;; Taken from `dtrt-indent-mode'
   6173   '(
   6174     (ada-mode                   . ada-indent)                       ; Ada
   6175     (ada-ts-mode                . ada-ts-mode-indent-offset)
   6176     (c++-mode                   . c-basic-offset)                   ; C++
   6177     (c++-ts-mode                . c-ts-mode-indent-offset)
   6178     (c-mode                     . c-basic-offset)                   ; C
   6179     (c-ts-mode                  . c-ts-mode-indent-offset)
   6180     (cperl-mode                 . cperl-indent-level)               ; Perl
   6181     (crystal-mode               . crystal-indent-level)             ; Crystal (Ruby)
   6182     (csharp-mode                . c-basic-offset)                   ; C#
   6183     (csharp-tree-sitter-mode    . csharp-tree-sitter-indent-offset) ; C#
   6184     (csharp-ts-mode             . csharp-ts-mode-indent-offset)     ; C# (tree-sitter, Emacs29)
   6185     (css-mode                   . css-indent-offset)                ; CSS
   6186     (d-mode                     . c-basic-offset)                   ; D
   6187     (enh-ruby-mode              . enh-ruby-indent-level)            ; Ruby
   6188     (erlang-mode                . erlang-indent-level)              ; Erlang
   6189     (ess-mode                   . ess-indent-offset)                ; ESS (R)
   6190     (go-ts-mode                 . go-ts-mode-indent-offset)
   6191     (gpr-mode                   . gpr-indent-offset)                ; GNAT Project
   6192     (gpr-ts-mode                . gpr-ts-mode-indent-offset)
   6193     (hack-mode                  . hack-indent-offset)               ; Hack
   6194     (java-mode                  . c-basic-offset)                   ; Java
   6195     (java-ts-mode               . java-ts-mode-indent-offset)
   6196     (jde-mode                   . c-basic-offset)                   ; Java (JDE)
   6197     (js-mode                    . js-indent-level)                  ; JavaScript
   6198     (js-ts-mode                 . js-indent-level)
   6199     (js2-mode                   . js2-basic-offset)                 ; JavaScript-IDE
   6200     (js3-mode                   . js3-indent-level)                 ; JavaScript-IDE
   6201     (json-mode                  . js-indent-level)                  ; JSON
   6202     (json-ts-mode               . json-ts-mode-indent-offset)
   6203     (lua-mode                   . lua-indent-level)                 ; Lua
   6204     (lua-ts-mode                . lua-ts-indent-offset)
   6205     (nxml-mode                  . nxml-child-indent)                ; XML
   6206     (objc-mode                  . c-basic-offset)                   ; Objective C
   6207     (pascal-mode                . pascal-indent-level)              ; Pascal
   6208     (perl-mode                  . perl-indent-level)                ; Perl
   6209     (php-mode                   . c-basic-offset)                   ; PHP
   6210     (php-ts-mode                . php-ts-mode-indent-offset)        ; PHP
   6211     (powershell-mode            . powershell-indent)                ; PowerShell
   6212     (powershell-ts-mode         . powershell-ts-mode-indent-offset) ; PowerShell
   6213     (raku-mode                  . raku-indent-offset)               ; Perl6/Raku
   6214     (ruby-mode                  . ruby-indent-level)                ; Ruby
   6215     (rust-mode                  . rust-indent-offset)               ; Rust
   6216     (rust-ts-mode               . rust-ts-mode-indent-offset)
   6217     (rustic-mode                . rustic-indent-offset)             ; Rust
   6218     (scala-mode                 . scala-indent:step)                ; Scala
   6219     (sgml-mode                  . sgml-basic-offset)                ; SGML
   6220     (sh-mode                    . sh-basic-offset)                  ; Shell Script
   6221     (toml-ts-mode               . toml-ts-mode-indent-offset)
   6222     (typescript-mode            . typescript-indent-level)          ; Typescript
   6223     (typescript-ts-mode         . typescript-ts-mode-indent-offset) ; Typescript (tree-sitter, Emacs29)
   6224     (yaml-mode                  . yaml-indent-offset)               ; YAML
   6225     (yang-mode                  . c-basic-offset)                   ; YANG (yang-mode)
   6226 
   6227     (default                    . standard-indent))                 ; default fallback
   6228   "A mapping from `major-mode' to its indent variable.")
   6229 
   6230 (defun lsp--get-indent-width (mode)
   6231   "Get indentation offset for MODE."
   6232   (or (alist-get mode lsp--formatting-indent-alist)
   6233       (lsp--get-indent-width (or (get mode 'derived-mode-parent) 'default))))
   6234 
   6235 (defun lsp--make-document-formatting-params ()
   6236   "Create document formatting params."
   6237   (lsp-make-document-formatting-params
   6238    :text-document (lsp--text-document-identifier)
   6239    :options (lsp-make-formatting-options
   6240              :tab-size (symbol-value (lsp--get-indent-width major-mode))
   6241              :insert-spaces (lsp-json-bool (not indent-tabs-mode))
   6242              :trim-trailing-whitespace? (lsp-json-bool lsp-trim-trailing-whitespace)
   6243              :insert-final-newline? (lsp-json-bool lsp-insert-final-newline)
   6244              :trim-final-newlines? (lsp-json-bool lsp-trim-final-newlines))))
   6245 
   6246 (defun lsp-format-buffer ()
   6247   "Ask the server to format this document."
   6248   (interactive "*")
   6249   (cond ((lsp-feature? "textDocument/formatting")
   6250          (let ((edits (lsp-request "textDocument/formatting"
   6251                                    (lsp--make-document-formatting-params))))
   6252            (if (seq-empty-p edits)
   6253                (lsp--info "No formatting changes provided")
   6254              (lsp--apply-text-edits edits 'format))))
   6255         ((lsp-feature? "textDocument/rangeFormatting")
   6256          (save-restriction
   6257            (widen)
   6258            (lsp-format-region (point-min) (point-max))))
   6259         (t (signal 'lsp-capability-not-supported (list "documentFormattingProvider")))))
   6260 
   6261 (defun lsp-format-region (s e)
   6262   "Ask the server to format the region, or if none is selected, the current line."
   6263   (interactive "r")
   6264   (let ((edits (lsp-request
   6265                 "textDocument/rangeFormatting"
   6266                 (lsp--make-document-range-formatting-params s e))))
   6267     (if (seq-empty-p edits)
   6268         (lsp--info "No formatting changes provided")
   6269       (lsp--apply-text-edits edits 'format))))
   6270 
   6271 (defmacro lsp-make-interactive-code-action (func-name code-action-kind)
   6272   "Define an interactive function FUNC-NAME that attempts to
   6273 execute a CODE-ACTION-KIND action."
   6274   `(defun ,(intern (concat "lsp-" (symbol-name func-name))) ()
   6275      ,(format "Perform the %s code action, if available." code-action-kind)
   6276      (interactive)
   6277      ;; Even when `lsp-auto-execute-action' is nil, it still makes sense to
   6278      ;; auto-execute here: the user has specified exactly what they want.
   6279      (let ((lsp-auto-execute-action t))
   6280        (condition-case nil
   6281            (lsp-execute-code-action-by-kind ,code-action-kind)
   6282          (lsp-no-code-actions
   6283           (when (called-interactively-p 'any)
   6284             (lsp--info ,(format "%s action not available" code-action-kind))))))))
   6285 
   6286 (lsp-make-interactive-code-action organize-imports "source.organizeImports")
   6287 
   6288 (defun lsp--make-document-range-formatting-params (start end)
   6289   "Make DocumentRangeFormattingParams for selected region."
   6290   (lsp:set-document-range-formatting-params-range (lsp--make-document-formatting-params)
   6291                                                   (lsp--region-to-range start end)))
   6292 
   6293 (defconst lsp--highlight-kind-face
   6294   '((1 . lsp-face-highlight-textual)
   6295     (2 . lsp-face-highlight-read)
   6296     (3 . lsp-face-highlight-write)))
   6297 
   6298 (defun lsp--remove-overlays (name)
   6299   (save-restriction
   6300     (widen)
   6301     (remove-overlays (point-min) (point-max) name t)))
   6302 
   6303 (defun lsp-document-highlight ()
   6304   "Highlight all relevant references to the symbol under point."
   6305   (interactive)
   6306   (lsp--remove-overlays 'lsp-highlight) ;; clear any previous highlights
   6307   (setq lsp--have-document-highlights nil
   6308         lsp--symbol-bounds-of-last-highlight-invocation nil)
   6309   (let ((lsp-enable-symbol-highlighting t))
   6310     (lsp--document-highlight)))
   6311 
   6312 (defun lsp--document-highlight-callback (highlights)
   6313   "Create a callback to process the reply of a
   6314 `textDocument/documentHighlight' message for the buffer BUF.
   6315 A reference is highlighted only if it is visible in a window."
   6316   (lsp--remove-overlays 'lsp-highlight)
   6317 
   6318   (let* ((wins-visible-pos (-map (lambda (win)
   6319                                    (cons (1- (line-number-at-pos (window-start win) t))
   6320                                          (1+ (line-number-at-pos (min (window-end win)
   6321                                                                       (with-current-buffer (window-buffer win)
   6322                                                                         (buffer-end +1)))
   6323                                                                  t))))
   6324                                  (get-buffer-window-list nil nil 'visible))))
   6325     (setq lsp--have-document-highlights t)
   6326     (-map
   6327      (-lambda ((&DocumentHighlight :range (&Range :start (start &as &Position :line start-line)
   6328                                                   :end (end &as &Position :line end-line))
   6329                                    :kind?))
   6330        (-map
   6331         (-lambda ((start-window . end-window))
   6332           ;; Make the overlay only if the reference is visible
   6333           (when (and (> (1+ start-line) start-window)
   6334                      (< (1+ end-line) end-window))
   6335             (let ((start-point (lsp--position-to-point start))
   6336                   (end-point (lsp--position-to-point end)))
   6337               (when (not (and lsp-symbol-highlighting-skip-current
   6338                               (<= start-point (point) end-point)))
   6339                 (-doto (make-overlay start-point end-point)
   6340                   (overlay-put 'face (cdr (assq (or kind? 1) lsp--highlight-kind-face)))
   6341                   (overlay-put 'lsp-highlight t))))))
   6342         wins-visible-pos))
   6343      highlights)))
   6344 
   6345 (defcustom lsp-symbol-kinds
   6346   '((1 . "File")
   6347     (2 . "Module")
   6348     (3 . "Namespace")
   6349     (4 . "Package")
   6350     (5 . "Class")
   6351     (6 . "Method")
   6352     (7 . "Property")
   6353     (8 . "Field")
   6354     (9 . "Constructor")
   6355     (10 . "Enum")
   6356     (11 . "Interface")
   6357     (12 . "Function")
   6358     (13 . "Variable")
   6359     (14 . "Constant")
   6360     (15 . "String")
   6361     (16 . "Number")
   6362     (17 . "Boolean")
   6363     (18 . "Array")
   6364     (19 . "Object")
   6365     (20 . "Key")
   6366     (21 . "Null")
   6367     (22 . "Enum Member")
   6368     (23 . "Struct")
   6369     (24 . "Event")
   6370     (25 . "Operator")
   6371     (26 . "Type Parameter"))
   6372   "Alist mapping SymbolKinds to human-readable strings.
   6373 Various Symbol objects in the LSP protocol have an integral type,
   6374 specifying what they are. This alist maps such type integrals to
   6375 readable representations of them. See
   6376 `https://microsoft.github.io/language-server-protocol/specifications/specification-current/',
   6377 namespace SymbolKind."
   6378   :group 'lsp-mode
   6379   :type '(alist :key-type integer :value-type string))
   6380 (defalias 'lsp--symbol-kind 'lsp-symbol-kinds)
   6381 
   6382 (lsp-defun lsp--symbol-information-to-xref
   6383   ((&SymbolInformation :kind :name
   6384                        :location (&Location :uri :range (&Range :start
   6385                                                                 (&Position :line :character)))))
   6386   "Return a `xref-item' from SYMBOL information."
   6387   (xref-make (format "[%s] %s" (alist-get kind lsp-symbol-kinds) name)
   6388              (xref-make-file-location (lsp--uri-to-path uri)
   6389                                       line
   6390                                       character)))
   6391 
   6392 (defun lsp--get-document-symbols ()
   6393   "Get document symbols.
   6394 
   6395 If the buffer has not been modified since symbols were last
   6396 retrieved, simply return the latest result.
   6397 
   6398 Else, if the request was initiated by Imenu updating its menu-bar
   6399 entry, perform it asynchronously; i.e., give Imenu the latest
   6400 result and then force a refresh when a new one is available.
   6401 
   6402 Else (e.g., due to interactive use of `imenu' or `xref'),
   6403 perform the request synchronously."
   6404   (if (= (buffer-chars-modified-tick) lsp--document-symbols-tick)
   6405       lsp--document-symbols
   6406     (let ((method "textDocument/documentSymbol")
   6407           (params `(:textDocument ,(lsp--text-document-identifier)))
   6408           (tick (buffer-chars-modified-tick)))
   6409       (if (not lsp--document-symbols-request-async)
   6410           (prog1
   6411               (setq lsp--document-symbols (lsp-request method params))
   6412             (setq lsp--document-symbols-tick tick))
   6413         (lsp-request-async method params
   6414                            (lambda (document-symbols)
   6415                              (setq lsp--document-symbols document-symbols
   6416                                    lsp--document-symbols-tick tick)
   6417                              (lsp--imenu-refresh))
   6418                            :mode 'alive
   6419                            :cancel-token :document-symbols)
   6420         lsp--document-symbols))))
   6421 
   6422 (advice-add 'imenu-update-menubar :around
   6423             (lambda (oldfun &rest r)
   6424               (let ((lsp--document-symbols-request-async t))
   6425                 (apply oldfun r))))
   6426 
   6427 (defun lsp--document-symbols->document-symbols-hierarchy (document-symbols current-position)
   6428   "Convert DOCUMENT-SYMBOLS to symbols hierarchy on CURRENT-POSITION."
   6429   (-let (((symbol &as &DocumentSymbol? :children?)
   6430           (seq-find (-lambda ((&DocumentSymbol :range))
   6431                       (lsp-point-in-range? current-position range))
   6432                     document-symbols)))
   6433     (if children?
   6434         (cons symbol (lsp--document-symbols->document-symbols-hierarchy children? current-position))
   6435       (when symbol
   6436         (list symbol)))))
   6437 
   6438 (lsp-defun lsp--symbol-information->document-symbol ((&SymbolInformation :name :kind :location :container-name? :deprecated?))
   6439   "Convert a SymbolInformation to a DocumentInformation"
   6440   (lsp-make-document-symbol :name name
   6441                             :kind kind
   6442                             :range (lsp:location-range location)
   6443                             :children? nil
   6444                             :deprecated? deprecated?
   6445                             :selection-range (lsp:location-range location)
   6446                             :detail? container-name?))
   6447 
   6448 (defun lsp--symbols-informations->document-symbols-hierarchy (symbols-informations current-position)
   6449   "Convert SYMBOLS-INFORMATIONS to symbols hierarchy on CURRENT-POSITION."
   6450   (--> symbols-informations
   6451     (-keep (-lambda ((symbol &as &SymbolInformation :location (&Location :range)))
   6452              (when (lsp-point-in-range? current-position range)
   6453                (lsp--symbol-information->document-symbol symbol)))
   6454            it)
   6455     (sort it (-lambda ((&DocumentSymbol :range (&Range :start a-start-position :end a-end-position))
   6456                        (&DocumentSymbol :range (&Range :start b-start-position :end b-end-position)))
   6457                (and (lsp--position-compare b-start-position a-start-position)
   6458                     (lsp--position-compare a-end-position b-end-position))))))
   6459 
   6460 (defun lsp--symbols->document-symbols-hierarchy (symbols)
   6461   "Convert SYMBOLS to symbols-hierarchy."
   6462   (when-let* ((first-symbol (lsp-seq-first symbols)))
   6463     (let ((cur-position (lsp-make-position :line (plist-get (lsp--cur-position) :line)
   6464                                            :character (plist-get (lsp--cur-position) :character))))
   6465       (if (lsp-symbol-information? first-symbol)
   6466           (lsp--symbols-informations->document-symbols-hierarchy symbols cur-position)
   6467         (lsp--document-symbols->document-symbols-hierarchy symbols cur-position)))))
   6468 
   6469 (defun lsp--xref-backend () 'xref-lsp)
   6470 
   6471 (cl-defmethod xref-backend-identifier-at-point ((_backend (eql xref-lsp)))
   6472   (propertize (or (thing-at-point 'symbol) "")
   6473               'identifier-at-point t))
   6474 
   6475 (defun lsp--xref-elements-index (symbols path)
   6476   (-mapcat
   6477    (-lambda (sym)
   6478      (pcase-exhaustive sym
   6479        ((lsp-interface DocumentSymbol :name :children? :selection-range (lsp-interface Range :start))
   6480         (cons (cons (concat path name)
   6481                     (lsp--position-to-point start))
   6482               (lsp--xref-elements-index children? (concat path name " / "))))
   6483        ((lsp-interface SymbolInformation :name :location (lsp-interface Location :range (lsp-interface Range :start)))
   6484         (list (cons (concat path name)
   6485                     (lsp--position-to-point start))))))
   6486    symbols))
   6487 
   6488 (defvar-local lsp--symbols-cache nil)
   6489 
   6490 (cl-defmethod xref-backend-identifier-completion-table ((_backend (eql xref-lsp)))
   6491   (if (lsp--find-workspaces-for "textDocument/documentSymbol")
   6492       (progn
   6493         (setq lsp--symbols-cache (lsp--xref-elements-index
   6494                                   (lsp--get-document-symbols) nil))
   6495         lsp--symbols-cache)
   6496     (list (propertize (or (thing-at-point 'symbol) "")
   6497                       'identifier-at-point t))))
   6498 
   6499 (cl-defmethod xref-backend-definitions ((_backend (eql xref-lsp)) identifier)
   6500   (save-excursion
   6501     (unless (get-text-property 0 'identifier-at-point identifier)
   6502       (goto-char (cl-rest (or (assoc identifier lsp--symbols-cache)
   6503                               (user-error "Unable to find symbol %s in current document" identifier)))))
   6504     (lsp--locations-to-xref-items (lsp-request "textDocument/definition"
   6505                                                (lsp--text-document-position-params)))))
   6506 
   6507 (cl-defmethod xref-backend-references ((_backend (eql xref-lsp)) identifier)
   6508   (save-excursion
   6509     (unless (get-text-property 0 'identifier-at-point identifier)
   6510       (goto-char (cl-rest (or (assoc identifier lsp--symbols-cache)
   6511                               (user-error "Unable to find symbol %s" identifier)))))
   6512     (lsp--locations-to-xref-items (lsp-request "textDocument/references"
   6513                                                (lsp--make-reference-params nil lsp-references-exclude-declaration)))))
   6514 
   6515 (cl-defmethod xref-backend-apropos ((_backend (eql xref-lsp)) pattern)
   6516   (seq-map #'lsp--symbol-information-to-xref
   6517            (lsp-request "workspace/symbol" `(:query ,pattern))))
   6518 
   6519 (defcustom lsp-rename-use-prepare t
   6520   "Whether `lsp-rename' should do a prepareRename first.
   6521 For some language servers, textDocument/prepareRename might be
   6522 too slow, in which case this variable may be set to nil.
   6523 `lsp-rename' will then use `thing-at-point' `symbol' to determine
   6524 the symbol to rename at point."
   6525   :group 'lsp-mode
   6526   :type 'boolean)
   6527 
   6528 (defun lsp--get-symbol-to-rename ()
   6529   "Get a symbol to rename and placeholder at point.
   6530 Returns a cons ((START . END) . PLACEHOLDER?), and nil if
   6531 renaming is generally supported but cannot be done at point.
   6532 START and END are the bounds of the identifiers being renamed,
   6533 while PLACEHOLDER?, is either nil or a string suggested by the
   6534 language server as the initial input of a new-name prompt."
   6535   (unless (lsp-feature? "textDocument/rename")
   6536     (error "The connected server(s) doesn't support renaming"))
   6537   (if (and lsp-rename-use-prepare (lsp-feature? "textDocument/prepareRename"))
   6538       (when-let* ((response
   6539                   (lsp-request "textDocument/prepareRename"
   6540                                (lsp--text-document-position-params))))
   6541         (let* ((bounds (lsp--range-to-region
   6542                         (if (lsp-range? response)
   6543                             response
   6544                           (lsp:prepare-rename-result-range response))))
   6545                (placeholder
   6546                 (and (not (lsp-range? response))
   6547                      (lsp:prepare-rename-result-placeholder response))))
   6548           (cons bounds placeholder)))
   6549     (when-let* ((bounds (bounds-of-thing-at-point 'symbol)))
   6550       (cons bounds nil))))
   6551 
   6552 (defface lsp-face-rename '((t :underline t))
   6553   "Face used to highlight the identifier being renamed.
   6554 Renaming can be done using `lsp-rename'."
   6555   :group 'lsp-mode)
   6556 
   6557 (defface lsp-rename-placeholder-face '((t :inherit font-lock-variable-name-face))
   6558   "Face used to display the rename placeholder in.
   6559 When calling `lsp-rename' interactively, this will be the face of
   6560 the new name."
   6561   :group 'lsp-mode)
   6562 
   6563 (defvar lsp-rename-history '()
   6564   "History for `lsp--read-rename'.")
   6565 
   6566 (defun lsp--read-rename (at-point)
   6567   "Read a new name for a `lsp-rename' at `point' from the user.
   6568 AT-POINT shall be a structure as returned by
   6569 `lsp--get-symbol-to-rename'.
   6570 
   6571 Returns a string, which should be the new name for the identifier
   6572 at point. If renaming cannot be done at point (as determined from
   6573 AT-POINT), throw a `user-error'.
   6574 
   6575 This function is for use in `lsp-rename' only, and shall not be
   6576 relied upon."
   6577   (unless at-point
   6578     (user-error "`lsp-rename' is invalid here"))
   6579   (-let* ((((start . end) . placeholder?) at-point)
   6580           ;; Do the `buffer-substring' first to not include `lsp-face-rename'
   6581           (rename-me (buffer-substring start end))
   6582           (placeholder (or placeholder? rename-me))
   6583           (placeholder (propertize placeholder 'face 'lsp-rename-placeholder-face))
   6584 
   6585           overlay)
   6586     ;; We need unwind protect, as the user might cancel here, causing the
   6587     ;; overlay to linger.
   6588     (unwind-protect
   6589         (progn
   6590           (setq overlay (make-overlay start end))
   6591           (overlay-put overlay 'face 'lsp-face-rename)
   6592 
   6593           (read-string (format "Rename %s to: " rename-me) placeholder
   6594                        'lsp-rename-history))
   6595       (and overlay (delete-overlay overlay)))))
   6596 
   6597 (defun lsp-rename (newname)
   6598   "Rename the symbol (and all references to it) under point to NEWNAME."
   6599   (interactive (list (lsp--read-rename (lsp--get-symbol-to-rename))))
   6600   (when-let* ((edits (lsp-request "textDocument/rename"
   6601                                  `( :textDocument ,(lsp--text-document-identifier)
   6602                                     :position ,(lsp--cur-position)
   6603                                     :newName ,newname))))
   6604     (lsp--apply-workspace-edit edits 'rename)))
   6605 
   6606 (defun lsp--on-rename-file (old-func old-name new-name &optional ok-if-already-exists?)
   6607   "Advice around function `rename-file'.
   6608 Applies OLD-FUNC with OLD-NAME, NEW-NAME and OK-IF-ALREADY-EXISTS?.
   6609 
   6610 This advice sends workspace/willRenameFiles before renaming file
   6611 to check if server wants to apply any workspaceEdits after renamed."
   6612   (if (and lsp-apply-edits-after-file-operations
   6613            (lsp--send-will-rename-files-p old-name))
   6614       (let ((params (lsp-make-rename-files-params
   6615                      :files (vector (lsp-make-file-rename
   6616                                      :oldUri (lsp--path-to-uri old-name)
   6617                                      :newUri (lsp--path-to-uri new-name))))))
   6618         (when-let* ((edits (lsp-request "workspace/willRenameFiles" params)))
   6619           (lsp--apply-workspace-edit edits 'rename-file)
   6620           (funcall old-func old-name new-name ok-if-already-exists?)
   6621           (when (lsp--send-did-rename-files-p)
   6622             (lsp-notify "workspace/didRenameFiles" params))))
   6623     (funcall old-func old-name new-name ok-if-already-exists?)))
   6624 
   6625 (advice-add 'rename-file :around #'lsp--on-rename-file)
   6626 
   6627 (defcustom lsp-xref-force-references nil
   6628   "If non-nil threat everything as references(e. g. jump if only one item.)"
   6629   :group 'lsp-mode
   6630   :type 'boolean)
   6631 
   6632 (defun lsp-show-xrefs (xrefs display-action references?)
   6633   (unless (region-active-p) (push-mark nil t))
   6634   (if (boundp 'xref-show-definitions-function)
   6635       (with-no-warnings
   6636         (xref-push-marker-stack)
   6637         (funcall (if (and references? (not lsp-xref-force-references))
   6638                      xref-show-xrefs-function
   6639                    xref-show-definitions-function)
   6640                  (-const xrefs)
   6641                  `((window . ,(selected-window))
   6642                    (display-action . ,display-action)
   6643                    ,(if (and references? (not lsp-xref-force-references))
   6644                         `(auto-jump . ,xref-auto-jump-to-first-xref)
   6645                       `(auto-jump . ,xref-auto-jump-to-first-definition)))))
   6646     (xref--show-xrefs xrefs display-action)))
   6647 
   6648 (cl-defmethod seq-empty-p ((ht hash-table))
   6649   "Function `seq-empty-p' for hash-table."
   6650   (hash-table-empty-p ht))
   6651 
   6652 (cl-defun lsp-find-locations (method &optional extra &key display-action references?)
   6653   "Send request named METHOD and get cross references of the symbol under point.
   6654 EXTRA is a plist of extra parameters.
   6655 REFERENCES? t when METHOD returns references."
   6656   (let ((loc (lsp-request method
   6657                           (append (lsp--text-document-position-params) extra))))
   6658     (if (seq-empty-p loc)
   6659         (lsp--error "Not found for: %s" (or (thing-at-point 'symbol t) ""))
   6660       (lsp-show-xrefs (lsp--locations-to-xref-items loc) display-action references?))))
   6661 
   6662 (cl-defun lsp-find-declaration (&key display-action)
   6663   "Find declarations of the symbol under point."
   6664   (interactive)
   6665   (lsp-find-locations "textDocument/declaration" nil :display-action display-action))
   6666 
   6667 (cl-defun lsp-find-definition (&key display-action)
   6668   "Find definitions of the symbol under point."
   6669   (interactive)
   6670   (lsp-find-locations "textDocument/definition" nil :display-action display-action))
   6671 
   6672 (defun lsp-find-definition-mouse (click)
   6673   "Click to start `lsp-find-definition' at clicked point."
   6674   (interactive "e")
   6675   (let* ((ec (event-start click))
   6676          (p1 (posn-point ec))
   6677          (w1 (posn-window ec)))
   6678     (select-window w1)
   6679     (goto-char p1)
   6680     (lsp-find-definition)))
   6681 
   6682 (cl-defun lsp-find-implementation (&key display-action)
   6683   "Find implementations of the symbol under point."
   6684   (interactive)
   6685   (lsp-find-locations "textDocument/implementation"
   6686                       nil
   6687                       :display-action display-action
   6688                       :references? t))
   6689 
   6690 (cl-defun lsp-find-references (&optional exclude-declaration &key display-action)
   6691   "Find references of the symbol under point."
   6692   (interactive "P")
   6693   (lsp-find-locations "textDocument/references"
   6694                       (list :context `(:includeDeclaration ,(lsp-json-bool (not (or exclude-declaration lsp-references-exclude-declaration)))))
   6695                       :display-action display-action
   6696                       :references? t))
   6697 
   6698 (cl-defun lsp-find-type-definition (&key display-action)
   6699   "Find type definitions of the symbol under point."
   6700   (interactive)
   6701   (lsp-find-locations "textDocument/typeDefinition" nil :display-action display-action))
   6702 
   6703 (defalias 'lsp-find-custom #'lsp-find-locations)
   6704 (defalias 'lsp-goto-implementation #'lsp-find-implementation)
   6705 (defalias 'lsp-goto-type-definition #'lsp-find-type-definition)
   6706 
   6707 (with-eval-after-load 'evil
   6708   (evil-set-command-property 'lsp-find-definition :jump t)
   6709   (evil-set-command-property 'lsp-find-implementation :jump t)
   6710   (evil-set-command-property 'lsp-find-references :jump t)
   6711   (evil-set-command-property 'lsp-find-type-definition :jump t))
   6712 
   6713 (defun lsp--workspace-method-supported? (check-command method capability workspace)
   6714   (with-lsp-workspace workspace
   6715     (if check-command
   6716         (funcall check-command workspace)
   6717       (or
   6718        (when capability (lsp--capability capability))
   6719        (lsp--registered-capability method)
   6720        (and (not capability) (not check-command))))))
   6721 
   6722 (defun lsp-disable-method-for-server (method server-id)
   6723   "Disable METHOD for SERVER-ID."
   6724   (cl-callf
   6725       (lambda (reqs)
   6726         (-let (((&plist :check-command :capability) reqs))
   6727           (list :check-command
   6728                 (lambda (workspace)
   6729                   (unless (-> workspace
   6730                               lsp--workspace-client
   6731                               lsp--client-server-id
   6732                               (eq server-id))
   6733                     (lsp--workspace-method-supported? check-command
   6734                                                       method
   6735                                                       capability
   6736                                                       workspace))))))
   6737       (alist-get method lsp-method-requirements nil nil 'string=)))
   6738 
   6739 (defun lsp--find-workspaces-for (msg-or-method)
   6740   "Find all workspaces in the current project that can handle MSG."
   6741   (let ((method (if (stringp msg-or-method)
   6742                     msg-or-method
   6743                   (plist-get msg-or-method :method))))
   6744     (-if-let (reqs (cdr (assoc method lsp-method-requirements)))
   6745         (-let (((&plist :capability :check-command) reqs))
   6746           (-filter
   6747            (-partial #'lsp--workspace-method-supported?
   6748                      check-command method capability)
   6749            (lsp-workspaces)))
   6750       (lsp-workspaces))))
   6751 
   6752 (defun lsp-can-execute-command? (command-name)
   6753   "Returns non-nil if current language server(s) can execute COMMAND-NAME.
   6754 The command is executed via `workspace/executeCommand'"
   6755   (cl-position
   6756    command-name
   6757    (lsp:execute-command-options-commands
   6758     (lsp:server-capabilities-execute-command-provider?
   6759      (lsp--server-capabilities)))
   6760    :test #'equal))
   6761 
   6762 (defalias 'lsp-feature? 'lsp--find-workspaces-for)
   6763 
   6764 (cl-defmethod lsp-execute-command (_server _command _arguments)
   6765   "Dispatch COMMAND execution."
   6766   (signal 'cl-no-applicable-method nil))
   6767 
   6768 (defun lsp-workspace-command-execute (command &optional args)
   6769   "Execute workspace COMMAND with ARGS."
   6770   (condition-case-unless-debug err
   6771       (let ((params (if args
   6772                         (list :command command :arguments args)
   6773                       (list :command command))))
   6774         (lsp-request "workspace/executeCommand" params))
   6775     (error
   6776      (error "`workspace/executeCommand' with `%s' failed.\n\n%S"
   6777             command err))))
   6778 
   6779 (defun lsp-send-execute-command (command &optional args)
   6780   "Create and send a `workspace/executeCommand' message having command COMMAND
   6781 and optional ARGS."
   6782   (lsp-workspace-command-execute command args))
   6783 
   6784 (defalias 'lsp-point-to-position #'lsp--point-to-position)
   6785 (defalias 'lsp-text-document-identifier #'lsp--text-document-identifier)
   6786 (defalias 'lsp--send-execute-command #'lsp-send-execute-command)
   6787 (defalias 'lsp-on-open #'lsp--text-document-did-open)
   6788 (defalias 'lsp-on-save #'lsp--text-document-did-save)
   6789 
   6790 (defun lsp--set-configuration (settings)
   6791   "Set the SETTINGS for the lsp server."
   6792   (lsp-notify "workspace/didChangeConfiguration" `(:settings ,settings)))
   6793 
   6794 (defun lsp-current-buffer ()
   6795   (or lsp--virtual-buffer
   6796       (current-buffer)))
   6797 
   6798 (defun lsp-buffer-live-p (buffer-id)
   6799   (if-let* ((buffer-live (plist-get buffer-id :buffer-live?)))
   6800       (funcall buffer-live buffer-id)
   6801     (buffer-live-p buffer-id)))
   6802 
   6803 (defun lsp--on-set-visited-file-name (old-func &rest args)
   6804   "Advice around function `set-visited-file-name'.
   6805 
   6806 This advice sends textDocument/didClose for the old file and
   6807 textDocument/didOpen for the new file."
   6808   (when lsp--cur-workspace
   6809     (lsp--text-document-did-close t))
   6810   (prog1 (apply old-func args)
   6811     (when lsp--cur-workspace
   6812       (lsp--text-document-did-open))))
   6813 
   6814 (advice-add 'set-visited-file-name :around #'lsp--on-set-visited-file-name)
   6815 
   6816 (defcustom lsp-flush-delayed-changes-before-next-message t
   6817   "If non-nil send the document changes update before sending other messages.
   6818 
   6819 If nil, and `lsp-debounce-full-sync-notifications' is non-nil,
   6820  change notifications will be throttled by
   6821  `lsp-debounce-full-sync-notifications-interval' regardless of
   6822  other messages."
   6823   :group 'lsp-mode
   6824   :type 'boolean)
   6825 
   6826 (defvar lsp--not-flushing-delayed-changes t)
   6827 
   6828 (defun lsp--send-no-wait (message proc)
   6829   "Send MESSAGE to PROC without waiting for further output."
   6830 
   6831   (when (and lsp--not-flushing-delayed-changes
   6832              lsp-flush-delayed-changes-before-next-message)
   6833     (let ((lsp--not-flushing-delayed-changes nil))
   6834       (lsp--flush-delayed-changes)))
   6835   (lsp-process-send proc message))
   6836 
   6837 (define-error 'lsp-parse-error
   6838   "Error parsing message from language server" 'lsp-error)
   6839 (define-error 'lsp-unknown-message-type
   6840   "Unknown message type" '(lsp-error lsp-parse-error))
   6841 (define-error 'lsp-unknown-json-rpc-version
   6842   "Unknown JSON-RPC protocol version" '(lsp-error lsp-parse-error))
   6843 (define-error 'lsp-no-content-length
   6844   "Content-Length header missing in message" '(lsp-error lsp-parse-error))
   6845 (define-error 'lsp-invalid-header-name
   6846   "Invalid header name" '(lsp-error lsp-parse-error))
   6847 
   6848 ;;  id  method
   6849 ;;   x    x     request
   6850 ;;   x    .     response
   6851 ;;   .    x     notification
   6852 (defun lsp--get-message-type (json-data)
   6853   "Get the message type from JSON-DATA."
   6854   (if (lsp:json-message-id? json-data)
   6855       (if (lsp:json-message-error? json-data)
   6856           'response-error
   6857         (if (lsp:json-message-method? json-data)
   6858             'request
   6859           'response))
   6860     'notification))
   6861 
   6862 (defconst lsp--default-notification-handlers
   6863   (ht ("window/showMessage" #'lsp--window-show-message)
   6864       ("window/logMessage" #'lsp--window-log-message)
   6865       ("window/showInputBox" #'lsp--window-show-input-box)
   6866       ("window/showQuickPick" #'lsp--window-show-quick-pick)
   6867       ("textDocument/publishDiagnostics" #'lsp--on-diagnostics)
   6868       ("textDocument/diagnosticsEnd" #'ignore)
   6869       ("textDocument/diagnosticsBegin" #'ignore)
   6870       ("telemetry/event" #'ignore)
   6871       ("$/progress" (lambda (workspace params)
   6872                       (funcall lsp-progress-function workspace params)))))
   6873 
   6874 (lsp-defun lsp--on-notification (workspace (&JSONNotification :params :method))
   6875   "Call the appropriate handler for NOTIFICATION."
   6876   (-let ((client (lsp--workspace-client workspace)))
   6877     (when (lsp--log-io-p method)
   6878       (lsp--log-entry-new (lsp--make-log-entry method nil params 'incoming-notif)
   6879                           lsp--cur-workspace))
   6880     (if-let* ((handler (or (gethash method (lsp--client-notification-handlers client))
   6881                           (gethash method lsp--default-notification-handlers))))
   6882         (funcall handler workspace params)
   6883       (when (and method (not (string-prefix-p "$" method)))
   6884         (lsp-warn "Unknown notification: %s" method)))))
   6885 
   6886 (lsp-defun lsp--build-workspace-configuration-response ((&ConfigurationParams :items))
   6887   "Get section configuration.
   6888 PARAMS are the `workspace/configuration' request params"
   6889   (->> items
   6890        (-map (-lambda ((&ConfigurationItem :section?))
   6891                (-let* ((path-parts (split-string section? "\\."))
   6892                        (path-without-last (s-join "." (-slice path-parts 0 -1)))
   6893                        (path-parts-len (length path-parts)))
   6894                  (cond
   6895                   ((<= path-parts-len 1)
   6896                    (ht-get (lsp-configuration-section section?)
   6897                            (car-safe path-parts)
   6898                            (ht-create)))
   6899                   ((> path-parts-len 1)
   6900                    (when-let* ((section (lsp-configuration-section path-without-last))
   6901                               (keys path-parts))
   6902                      (while (and keys section)
   6903                        (setf section (ht-get section (pop keys))))
   6904                      section))))))
   6905        (apply #'vector)))
   6906 
   6907 (defun lsp--ms-since (timestamp)
   6908   "Integer number of milliseconds since TIMESTAMP.  Fractions discarded."
   6909   (floor (* 1000 (float-time (time-since timestamp)))))
   6910 
   6911 (defun lsp--send-request-response (workspace recv-time request response)
   6912   "Send the RESPONSE for REQUEST in WORKSPACE and log if needed."
   6913   (-let* (((&JSONResponse :params :method :id) request)
   6914           (process (lsp--workspace-proc workspace))
   6915           (response (lsp--make-response id response))
   6916           (req-entry (and lsp-log-io
   6917                           (lsp--make-log-entry method id params 'incoming-req)))
   6918           (resp-entry (and lsp-log-io
   6919                            (lsp--make-log-entry method id response 'outgoing-resp
   6920                                                 (lsp--ms-since recv-time)))))
   6921     ;; Send response to the server.
   6922     (when (lsp--log-io-p method)
   6923       (lsp--log-entry-new req-entry workspace)
   6924       (lsp--log-entry-new resp-entry workspace))
   6925     (lsp--send-no-wait response process)))
   6926 
   6927 (lsp-defun lsp--on-request (workspace (request &as &JSONRequest :params :method))
   6928   "Call the appropriate handler for REQUEST, and send the return value to the
   6929 server. WORKSPACE is the active workspace."
   6930   (-let* ((recv-time (current-time))
   6931           (client (lsp--workspace-client workspace))
   6932           (buffers (lsp--workspace-buffers workspace))
   6933           handler
   6934           (response (cond
   6935                      ((setq handler (gethash method (lsp--client-request-handlers client) nil))
   6936                       (funcall handler workspace params))
   6937                      ((setq handler (gethash method (lsp--client-async-request-handlers client) nil))
   6938                       (funcall handler workspace params
   6939                                (-partial #'lsp--send-request-response
   6940                                          workspace recv-time request))
   6941                       'delay-response)
   6942                      ((equal method "client/registerCapability")
   6943                       (mapc #'lsp--server-register-capability
   6944                             (lsp:registration-params-registrations params))
   6945                       (mapc (lambda (buf)
   6946                               (when (lsp-buffer-live-p buf)
   6947                                 (lsp-with-current-buffer buf
   6948                                   (lsp-unconfig-buffer)
   6949                                   (lsp-configure-buffer))))
   6950                             buffers)
   6951                       nil)
   6952                      ((equal method "window/showMessageRequest")
   6953                       (let ((choice (lsp--window-log-message-request params)))
   6954                         `(:title ,choice)))
   6955                      ((equal method "window/showDocument")
   6956                       (let ((success? (lsp--window-show-document params)))
   6957                         (lsp-make-show-document-result :success (or success?
   6958                                                                     :json-false))))
   6959                      ((equal method "client/unregisterCapability")
   6960                       (mapc #'lsp--server-unregister-capability
   6961                             (lsp:unregistration-params-unregisterations params))
   6962                       (mapc (lambda (buf)
   6963                               (when (lsp-buffer-live-p buf)
   6964                                 (lsp-with-current-buffer buf
   6965                                   (lsp-unconfig-buffer)
   6966                                   (lsp-configure-buffer))))
   6967                             buffers)
   6968                       nil)
   6969                      ((equal method "workspace/applyEdit")
   6970                       (list :applied (condition-case err
   6971                                          (prog1 t
   6972                                            (lsp--apply-workspace-edit (lsp:apply-workspace-edit-params-edit params) 'server-requested))
   6973                                        (error
   6974                                         (lsp--error "Failed to apply edits with message %s"
   6975                                                     (error-message-string err))
   6976                                         :json-false))))
   6977                      ((equal method "workspace/configuration")
   6978                       (with-lsp-workspace workspace
   6979                         (if-let* ((buf (car buffers)))
   6980                             (lsp-with-current-buffer buf
   6981                               (lsp--build-workspace-configuration-response params))
   6982                           (lsp--with-workspace-temp-buffer (lsp--workspace-root workspace)
   6983                             (lsp--build-workspace-configuration-response params)))))
   6984                      ((equal method "workspace/workspaceFolders")
   6985                       (let ((folders (or (-> workspace
   6986                                              (lsp--workspace-client)
   6987                                              (lsp--client-server-id)
   6988                                              (gethash (lsp-session-server-id->folders (lsp-session))))
   6989                                          (lsp-session-folders (lsp-session)))))
   6990                         (->> folders
   6991                              (-distinct)
   6992                              (-map (lambda (folder)
   6993                                      (list :uri (lsp--path-to-uri folder))))
   6994                              (apply #'vector))))
   6995                      ((equal method "window/workDoneProgress/create")
   6996                       nil ;; no specific reply, no processing required
   6997                       )
   6998                      ((equal method "workspace/semanticTokens/refresh")
   6999                       (when (and lsp-semantic-tokens-enable
   7000                                  (fboundp 'lsp--semantic-tokens-on-refresh))
   7001                         (lsp--semantic-tokens-on-refresh workspace))
   7002                       nil)
   7003                      ((equal method "workspace/codeLens/refresh")
   7004                       (when (and lsp-lens-enable
   7005                                  (fboundp 'lsp--lens-on-refresh))
   7006                         (lsp--lens-on-refresh workspace))
   7007                       nil)
   7008                      ((equal method "workspace/diagnostic/refresh")
   7009                       nil)
   7010                      (t (lsp-warn "Unknown request method: %s" method) nil))))
   7011     ;; Send response to the server.
   7012     (unless (eq response 'delay-response)
   7013       (lsp--send-request-response workspace recv-time request response))))
   7014 
   7015 (lsp-defun lsp--error-string ((&JSONError :message :code))
   7016   "Format ERR as a user friendly string."
   7017   (format "Error from the Language Server: %s (%s)"
   7018           message
   7019           (or (car (alist-get code lsp--errors)) "Unknown error")))
   7020 
   7021 (defun lsp--get-body-length (headers)
   7022   (let ((content-length (cdr (assoc "Content-Length" headers))))
   7023     (if content-length
   7024         (string-to-number content-length)
   7025 
   7026       ;; This usually means either the server or our parser is
   7027       ;; screwed up with a previous Content-Length
   7028       (error "No Content-Length header"))))
   7029 
   7030 (defun lsp--parse-header (s)
   7031   "Parse string S as a LSP (KEY . VAL) header."
   7032   (let ((pos (string-match "\:" s))
   7033         key val)
   7034     (unless pos
   7035       (signal 'lsp-invalid-header-name (list s)))
   7036     (setq key (substring s 0 pos)
   7037           val (s-trim-left (substring s (+ 1 pos))))
   7038     (when (equal key "Content-Length")
   7039       (cl-assert (cl-loop for c across val
   7040                           when (or (> c ?9) (< c ?0)) return nil
   7041                           finally return t)
   7042                  nil (format "Invalid Content-Length value: %s" val)))
   7043     (cons key val)))
   7044 
   7045 (defmacro lsp--read-json (str)
   7046   "Read json string STR."
   7047   (if (progn
   7048         (require 'json)
   7049         (fboundp 'json-parse-string))
   7050       `(json-parse-string ,str
   7051                           :object-type (if lsp-use-plists
   7052                                            'plist
   7053                                          'hash-table)
   7054                           :null-object nil
   7055                           :false-object nil)
   7056     `(let ((json-array-type 'vector)
   7057            (json-object-type (if lsp-use-plists
   7058                                  'plist
   7059                                'hash-table))
   7060            (json-false nil))
   7061        (json-read-from-string ,str))))
   7062 
   7063 (defmacro lsp-json-read-buffer ()
   7064   "Read json from the current buffer."
   7065   (if (progn
   7066         (require 'json)
   7067         (fboundp 'json-parse-buffer))
   7068       `(json-parse-buffer :object-type (if lsp-use-plists
   7069                                            'plist
   7070                                          'hash-table)
   7071                           :null-object nil
   7072                           :false-object nil)
   7073     `(let ((json-array-type 'vector)
   7074            (json-object-type (if lsp-use-plists
   7075                                  'plist
   7076                                'hash-table))
   7077            (json-false nil))
   7078        (json-read))))
   7079 
   7080 (defun lsp--read-json-file (file-path)
   7081   "Read json file."
   7082   (-> file-path
   7083     (f-read-text)
   7084     (lsp--read-json)))
   7085 
   7086 (defun lsp--parser-on-message (json-data workspace)
   7087   "Called when the parser P read a complete MSG from the server."
   7088   (with-demoted-errors "Error processing message %S."
   7089     (with-lsp-workspace workspace
   7090       (let* ((client (lsp--workspace-client workspace))
   7091              (id (--when-let (lsp:json-response-id json-data)
   7092                    (if (stringp it) (string-to-number it) it)))
   7093              (data (lsp:json-response-result json-data)))
   7094         (pcase (lsp--get-message-type json-data)
   7095           ('response
   7096            (cl-assert id)
   7097            (-let [(callback _ method _ before-send) (gethash id (lsp--client-response-handlers client))]
   7098              (when (lsp--log-io-p method)
   7099                (lsp--log-entry-new
   7100                 (lsp--make-log-entry method id data 'incoming-resp
   7101                                      (lsp--ms-since before-send))
   7102                 workspace))
   7103              (when callback
   7104                (remhash id (lsp--client-response-handlers client))
   7105                (funcall callback (lsp:json-response-result json-data)))))
   7106           ('response-error
   7107            (cl-assert id)
   7108            (-let [(_ callback method _ before-send) (gethash id (lsp--client-response-handlers client))]
   7109              (when (lsp--log-io-p method)
   7110                (lsp--log-entry-new
   7111                 (lsp--make-log-entry method id (lsp:json-response-error-error json-data)
   7112                                      'incoming-resp (lsp--ms-since before-send))
   7113                 workspace))
   7114              (when callback
   7115                (remhash id (lsp--client-response-handlers client))
   7116                (funcall callback (lsp:json-response-error-error json-data)))))
   7117           ('notification
   7118            (lsp--on-notification workspace json-data))
   7119           ('request (lsp--on-request workspace json-data)))))))
   7120 
   7121 (defun lsp--create-filter-function (workspace)
   7122   "Make filter for the workspace."
   7123   (let ((body-received 0)
   7124         leftovers body-length body chunk)
   7125     (lambda (_proc input)
   7126       (setf chunk (if (s-blank? leftovers)
   7127                       (encode-coding-string input 'utf-8-unix t)
   7128                     (concat leftovers (encode-coding-string input 'utf-8-unix t))))
   7129 
   7130       (let (messages)
   7131         (while (not (s-blank? chunk))
   7132           (if (not body-length)
   7133               ;; Read headers
   7134               (if-let* ((body-sep-pos (string-match-p "\r\n\r\n" chunk)))
   7135                   ;; We've got all the headers, handle them all at once:
   7136                   (setf body-length (lsp--get-body-length
   7137                                      (mapcar #'lsp--parse-header
   7138                                              (split-string
   7139                                               (substring-no-properties chunk
   7140                                                                        (or (string-match-p "Content-Length" chunk)
   7141                                                                            (error "Unable to find Content-Length header."))
   7142                                                                        body-sep-pos)
   7143                                               "\r\n")))
   7144                         body-received 0
   7145                         leftovers nil
   7146                         chunk (substring-no-properties chunk (+ body-sep-pos 4)))
   7147 
   7148                 ;; Haven't found the end of the headers yet. Save everything
   7149                 ;; for when the next chunk arrives and await further input.
   7150                 (setf leftovers chunk
   7151                       chunk nil))
   7152             (let* ((chunk-length (string-bytes chunk))
   7153                    (left-to-receive (- body-length body-received))
   7154                    (this-body (if (< left-to-receive chunk-length)
   7155                                   (prog1 (substring-no-properties chunk 0 left-to-receive)
   7156                                     (setf chunk (substring-no-properties chunk left-to-receive)))
   7157                                 (prog1 chunk
   7158                                   (setf chunk nil))))
   7159                    (body-bytes (string-bytes this-body)))
   7160               (push this-body body)
   7161               (setf body-received (+ body-received body-bytes))
   7162               (when (>= chunk-length left-to-receive)
   7163                 (condition-case err
   7164                     (with-temp-buffer
   7165                       (apply #'insert
   7166                              (nreverse
   7167                               (prog1 body
   7168                                 (setf leftovers nil
   7169                                       body-length nil
   7170                                       body-received nil
   7171                                       body nil))))
   7172                       (decode-coding-region (point-min)
   7173                                             (point-max)
   7174                                             'utf-8)
   7175                       (goto-char (point-min))
   7176                       (push (lsp-json-read-buffer) messages))
   7177 
   7178                   (error
   7179                    (lsp-warn "Failed to parse the following chunk:\n'''\n%s\n'''\nwith message %s"
   7180                              (concat leftovers input)
   7181                              err)))))))
   7182         (mapc (lambda (msg)
   7183                 (lsp--parser-on-message msg workspace))
   7184               (nreverse messages))))))
   7185 
   7186 (defvar-local lsp--line-col-to-point-hash-table nil
   7187   "Hash table with keys (line . col) and values that are either point positions
   7188 or markers.")
   7189 
   7190 (defcustom lsp-imenu-detailed-outline t
   7191   "Whether `lsp-imenu' should include signatures.
   7192 This will be ignored if the server doesn't provide the necessary
   7193 information, for example if it doesn't support DocumentSymbols."
   7194   :group 'lsp-imenu
   7195   :type 'boolean)
   7196 
   7197 (defcustom lsp-imenu-hide-parent-details t
   7198   "Whether `lsp-imenu' should hide signatures of parent nodes."
   7199   :group 'lsp-imenu
   7200   :type 'boolean)
   7201 
   7202 (defface lsp-details-face '((t :height 0.8 :inherit shadow))
   7203   "Used to display additional information throughout `lsp'.
   7204 Things like line numbers, signatures, ... are considered
   7205 additional information. Often, additional faces are defined that
   7206 inherit from this face by default, like `lsp-signature-face', and
   7207 they may be customized for finer control."
   7208   :group 'lsp-mode)
   7209 
   7210 (defface lsp-signature-face '((t :inherit lsp-details-face))
   7211   "Used to display signatures in `imenu', ...."
   7212   :group 'lsp-mode)
   7213 
   7214 (lsp-defun lsp-render-symbol ((&DocumentSymbol :name :detail? :deprecated?)
   7215                               show-detail?)
   7216   "Render INPUT0, an `&DocumentSymbol', to a string.
   7217 If SHOW-DETAIL? is set, make use of its `:detail?' field (often
   7218 the signature)."
   7219   (let ((detail (and show-detail? (s-present? detail?)
   7220                      (propertize (concat " " (s-trim-left detail?))
   7221                                  'face 'lsp-signature-face)))
   7222         (name (if deprecated?
   7223                   (propertize name 'face 'lsp-face-semhl-deprecated) name)))
   7224     (concat name detail)))
   7225 
   7226 (lsp-defun lsp-render-symbol-information ((&SymbolInformation :name :deprecated? :container-name?)
   7227                                           separator)
   7228   "Render a piece of SymbolInformation.
   7229 Handle :deprecated?. If SEPARATOR is non-nil, the
   7230 symbol's (optional) parent, SEPARATOR and the symbol itself are
   7231 concatenated."
   7232   (when (and separator container-name? (not (string-empty-p container-name?)))
   7233     (setq name (concat name separator container-name?)))
   7234   (if deprecated? (propertize name 'face 'lsp-face-semhl-deprecated) name))
   7235 
   7236 (defun lsp--symbol-to-imenu-elem (sym)
   7237   "Convert SYM to imenu element.
   7238 
   7239 SYM is a SymbolInformation message.
   7240 
   7241 Return a cons cell (full-name . start-point)."
   7242   (let ((start-point (ht-get lsp--line-col-to-point-hash-table
   7243                              (lsp--get-line-and-col sym))))
   7244     (cons (lsp-render-symbol-information
   7245            sym (and lsp-imenu-show-container-name
   7246                     lsp-imenu-container-name-separator))
   7247           start-point)))
   7248 
   7249 (lsp-defun lsp--symbol-to-hierarchical-imenu-elem ((sym &as &DocumentSymbol :children?))
   7250   "Convert SYM to hierarchical imenu elements.
   7251 
   7252 SYM is a DocumentSymbol message.
   7253 
   7254 Return cons cell (\"symbol-name (symbol-kind)\" . start-point) if
   7255 SYM doesn't have any children. Otherwise return a cons cell with
   7256 an alist
   7257 
   7258   (\"symbol-name\" . ((\"(symbol-kind)\" . start-point)
   7259                     cons-cells-from-children))"
   7260   (let ((filtered-children (lsp--imenu-filter-symbols children?))
   7261         (signature (lsp-render-symbol sym lsp-imenu-detailed-outline)))
   7262     (if (seq-empty-p filtered-children)
   7263         (cons signature
   7264               (ht-get lsp--line-col-to-point-hash-table
   7265                       (lsp--get-line-and-col sym)))
   7266       (cons signature
   7267             (lsp--imenu-create-hierarchical-index filtered-children)))))
   7268 
   7269 (lsp-defun lsp--symbol-ignore ((&SymbolInformation :kind))
   7270   "Determine if SYM is for the current document and is to be shown."
   7271   ;; It's a SymbolInformation or DocumentSymbol, which is always in the
   7272   ;; current buffer file.
   7273   (and lsp-imenu-index-symbol-kinds
   7274        (numberp kind)
   7275        (let ((clamped-kind (if (< 0 kind (length lsp/symbol-kind-lookup))
   7276                                kind
   7277                              0)))
   7278          (not (memql (aref lsp/symbol-kind-lookup clamped-kind)
   7279                      lsp-imenu-index-symbol-kinds)))))
   7280 
   7281 (lsp-defun lsp--get-symbol-type ((&SymbolInformation :kind))
   7282   "The string name of the kind of SYM."
   7283   (alist-get kind lsp-symbol-kinds "Other"))
   7284 
   7285 (defun lsp--get-line-and-col (sym)
   7286   "Obtain the line and column corresponding to SYM."
   7287   (-let* ((location (lsp:symbol-information-location sym))
   7288           (name-range (or (and location (lsp:location-range location))
   7289                           (lsp:document-symbol-selection-range sym)))
   7290           ((&Range :start (&Position :line :character)) name-range))
   7291     (cons line character)))
   7292 
   7293 (defun lsp--collect-lines-and-cols (symbols)
   7294   "Return a sorted list ((line . col) ...) of the locations of SYMBOLS."
   7295   (let ((stack (mapcar 'identity symbols))
   7296         line-col-list)
   7297     (while stack
   7298       (let ((sym (pop stack)))
   7299         (push (lsp--get-line-and-col sym) line-col-list)
   7300         (unless (seq-empty-p (lsp:document-symbol-children? sym))
   7301           (setf stack (nconc (lsp--imenu-filter-symbols (lsp:document-symbol-children? sym)) stack)))))
   7302     (-sort #'lsp--line-col-comparator line-col-list)))
   7303 
   7304 (defun lsp--convert-line-col-to-points-batch (line-col-list)
   7305   "Convert a sorted list of positions from line-column
   7306 representation to point representation."
   7307   (let ((line-col-to-point-map (ht-create))
   7308         (inhibit-field-text-motion t)
   7309         (curr-line 0))
   7310     (lsp-save-restriction-and-excursion
   7311       (goto-char (point-min))
   7312       (cl-loop for (line . col) in line-col-list do
   7313                (forward-line (- line curr-line))
   7314                (setq curr-line line)
   7315                (let ((line-end (line-end-position)))
   7316                  (if (or (not col) (> col (- line-end (point))))
   7317                      (goto-char line-end)
   7318                    (forward-char col)))
   7319                (ht-set! line-col-to-point-map (cons line col) (if imenu-use-markers
   7320                                                                   (point-marker)
   7321                                                                 (point)))))
   7322     line-col-to-point-map))
   7323 
   7324 (cl-defun lsp--line-col-comparator ((l1 . c1) (l2 . c2))
   7325   (or (< l1 l2)
   7326       (and (= l1 l2)
   7327            (cond ((and c1 c2)
   7328                   (< c1 c2))
   7329                  (c1 t)))))
   7330 
   7331 (defun lsp-imenu-create-uncategorized-index (symbols)
   7332   "Create imenu index from document SYMBOLS.
   7333 This function, unlike `lsp-imenu-create-categorized-index', does
   7334 not categorize by type, but instead returns an `imenu' index
   7335 corresponding to the symbol hierarchy returned by the server
   7336 directly."
   7337   (let* ((lsp--line-col-to-point-hash-table (-> symbols
   7338                                                 lsp--collect-lines-and-cols
   7339                                                 lsp--convert-line-col-to-points-batch)))
   7340     (if (lsp--imenu-hierarchical-p symbols)
   7341         (lsp--imenu-create-hierarchical-index symbols)
   7342       (lsp--imenu-create-non-hierarchical-index symbols))))
   7343 
   7344 (defcustom lsp-imenu-symbol-kinds
   7345   '((1 . "Files")
   7346     (2 . "Modules")
   7347     (3 . "Namespaces")
   7348     (4 . "Packages")
   7349     (5 . "Classes")
   7350     (6 . "Methods")
   7351     (7 . "Properties")
   7352     (8 . "Fields")
   7353     (9 . "Constructors")
   7354     (10 . "Enums")
   7355     (11 . "Interfaces")
   7356     (12 . "Functions")
   7357     (13 . "Variables")
   7358     (14 . "Constants")
   7359     (15 . "Strings")
   7360     (16 . "Numbers")
   7361     (17 . "Booleans")
   7362     (18 . "Arrays")
   7363     (19 . "Objects")
   7364     (20 . "Keys")
   7365     (21 . "Nulls")
   7366     (22 . "Enum Members")
   7367     (23 . "Structs")
   7368     (24 . "Events")
   7369     (25 . "Operators")
   7370     (26 . "Type Parameters"))
   7371   "`lsp-symbol-kinds', but only used by `imenu'.
   7372 A new variable is needed, as it is `imenu' convention to use
   7373 pluralized categories, which `lsp-symbol-kinds' doesn't. If the
   7374 non-pluralized names are preferred, this can be set to
   7375 `lsp-symbol-kinds'."
   7376   :type '(alist :key-type integer :value-type string))
   7377 
   7378 (defun lsp--imenu-kind->name (kind)
   7379   (alist-get kind lsp-imenu-symbol-kinds "?"))
   7380 
   7381 (defun lsp-imenu-create-top-level-categorized-index (symbols)
   7382   "Create an `imenu' index categorizing SYMBOLS by type.
   7383 Only root symbols are categorized.
   7384 
   7385 See `lsp-symbol-kinds' to customize the category naming. SYMBOLS
   7386 shall be a list of DocumentSymbols or SymbolInformation."
   7387   (mapcan
   7388    (-lambda ((type . symbols))
   7389      (let ((cat (lsp--imenu-kind->name type))
   7390            (symbols (lsp-imenu-create-uncategorized-index symbols)))
   7391        ;; If there is no :kind (this is being defensive), or we couldn't look it
   7392        ;; up, just display the symbols inline, without categories.
   7393        (if cat (list (cons cat symbols)) symbols)))
   7394    (sort (seq-group-by #'lsp:document-symbol-kind symbols)
   7395          (-lambda ((kinda) (kindb)) (< kinda kindb)))))
   7396 
   7397 (lsp-defun lsp--symbol->imenu ((sym &as &DocumentSymbol :selection-range (&RangeToPoint :start)))
   7398   "Convert an `&DocumentSymbol' to an `imenu' entry."
   7399   (cons (lsp-render-symbol sym lsp-imenu-detailed-outline) start))
   7400 
   7401 (defun lsp--imenu-create-categorized-index-1 (symbols)
   7402   "Returns an `imenu' index from SYMBOLS categorized by type.
   7403 The result looks like this: ((\"Variables\" . (...)))."
   7404   (->>
   7405    symbols
   7406    (mapcan
   7407     (-lambda ((sym &as &DocumentSymbol :kind :children?))
   7408       (if (seq-empty-p children?)
   7409           (list (list kind (lsp--symbol->imenu sym)))
   7410         (let ((parent (lsp-render-symbol sym (and lsp-imenu-detailed-outline
   7411                                                   (not lsp-imenu-hide-parent-details)))))
   7412           (cons
   7413            (list kind (lsp--symbol->imenu sym))
   7414            (mapcar (-lambda ((type .  imenu-items))
   7415                      (list type (cons parent (mapcan #'cdr imenu-items))))
   7416                    (-group-by #'car (lsp--imenu-create-categorized-index-1 children?))))))))
   7417    (-group-by #'car)
   7418    (mapcar
   7419     (-lambda ((kind . syms))
   7420       (cons kind (mapcan #'cdr syms))))))
   7421 
   7422 (defun lsp--imenu-create-categorized-index (symbols)
   7423   (let ((syms (lsp--imenu-create-categorized-index-1 symbols)))
   7424     (dolist (sym syms)
   7425       (setcar sym (lsp--imenu-kind->name (car sym))))
   7426     syms))
   7427 
   7428 (lsp-defun lsp--symbol-information->imenu ((sym &as &SymbolInformation :location (&Location :range (&RangeToPoint :start))))
   7429   (cons (lsp-render-symbol-information sym nil) start))
   7430 
   7431 (defun lsp--imenu-create-categorized-index-flat (symbols)
   7432   "Create a kind-categorized index for SymbolInformation."
   7433   (mapcar (-lambda ((kind . syms))
   7434             (cons (lsp--imenu-kind->name kind)
   7435                   (mapcan (-lambda ((parent . children))
   7436                             (let ((children (mapcar #'lsp--symbol-information->imenu children)))
   7437                               (if parent (list (cons parent children)) children)))
   7438                           (-group-by #'lsp:symbol-information-container-name? syms))))
   7439           (seq-group-by #'lsp:symbol-information-kind symbols)))
   7440 
   7441 (defun lsp-imenu-create-categorized-index (symbols)
   7442   (if (lsp--imenu-hierarchical-p symbols)
   7443       (lsp--imenu-create-categorized-index symbols)
   7444     (lsp--imenu-create-categorized-index-flat symbols)))
   7445 
   7446 (defcustom lsp-imenu-index-function #'lsp-imenu-create-uncategorized-index
   7447   "Function that should create an `imenu' index.
   7448 It will be called with a list of SymbolInformation or
   7449 DocumentSymbols, whose first level is already filtered. It shall
   7450 then return an appropriate `imenu' index (see
   7451 `imenu-create-index-function').
   7452 
   7453 Note that this interface is not stable, and subject to change any
   7454 time."
   7455   :group 'lsp-imenu
   7456   :type '(radio
   7457           (const :tag "Categorize by type"
   7458                  lsp-imenu-create-categorized-index)
   7459           (const :tag "Categorize root symbols by type"
   7460                  lsp-imenu-create-top-level-categorized-index)
   7461           (const :tag "Uncategorized, inline entries"
   7462                  lsp-imenu-create-uncategorized-index)
   7463           (function :tag "Custom function")))
   7464 
   7465 (defun lsp--imenu-create-index ()
   7466   "Create an `imenu' index based on the language server.
   7467 Respects `lsp-imenu-index-function'."
   7468   (let ((symbols (lsp--imenu-filter-symbols (lsp--get-document-symbols))))
   7469     (funcall lsp-imenu-index-function symbols)))
   7470 
   7471 (defun lsp--imenu-filter-symbols (symbols)
   7472   "Filter out unsupported symbols from SYMBOLS."
   7473   (seq-remove #'lsp--symbol-ignore symbols))
   7474 
   7475 (defun lsp--imenu-hierarchical-p (symbols)
   7476   "Determine whether any element in SYMBOLS has children."
   7477   (seq-some #'lsp-document-symbol? symbols))
   7478 
   7479 (defun lsp--imenu-create-non-hierarchical-index (symbols)
   7480   "Create imenu index for non-hierarchical SYMBOLS.
   7481 
   7482 SYMBOLS are a list of DocumentSymbol messages.
   7483 
   7484 Return a nested alist keyed by symbol names. e.g.
   7485 
   7486    ((\"SomeClass\" (\"(Class)\" . 10)
   7487                  (\"someField (Field)\" . 20)
   7488                  (\"someFunction (Function)\" . 25)
   7489                  (\"SomeSubClass\" (\"(Class)\" . 30)
   7490                                   (\"someSubField (Field)\" . 35))
   7491     (\"someFunction (Function)\" . 40))"
   7492   (seq-map (lambda (nested-alist)
   7493              (cons (car nested-alist)
   7494                    (seq-map #'lsp--symbol-to-imenu-elem (cdr nested-alist))))
   7495            (seq-group-by #'lsp--get-symbol-type symbols)))
   7496 
   7497 (defun lsp--imenu-create-hierarchical-index (symbols)
   7498   "Create imenu index for hierarchical SYMBOLS.
   7499 
   7500 SYMBOLS are a list of DocumentSymbol messages.
   7501 
   7502 Return a nested alist keyed by symbol names. e.g.
   7503 
   7504    ((\"SomeClass\" (\"(Class)\" . 10)
   7505                  (\"someField (Field)\" . 20)
   7506                  (\"someFunction (Function)\" . 25)
   7507                  (\"SomeSubClass\" (\"(Class)\" . 30)
   7508                                   (\"someSubField (Field)\" . 35))
   7509     (\"someFunction (Function)\" . 40))"
   7510   (seq-map #'lsp--symbol-to-hierarchical-imenu-elem
   7511            (seq-sort #'lsp--imenu-symbol-lessp symbols)))
   7512 
   7513 (defun lsp--imenu-symbol-lessp (sym1 sym2)
   7514   (let* ((compare-results (mapcar (lambda (method)
   7515                                     (funcall (alist-get method lsp--imenu-compare-function-alist)
   7516                                              sym1 sym2))
   7517                                   lsp-imenu-sort-methods))
   7518          (result (seq-find (lambda (result)
   7519                              (not (= result 0)))
   7520                            compare-results
   7521                            0)))
   7522     (and (numberp result) (< result 0))))
   7523 
   7524 (lsp-defun lsp--imenu-compare-kind ((&SymbolInformation :kind left)
   7525                                     (&SymbolInformation :kind right))
   7526   "Compare SYM1 and SYM2 by kind."
   7527   (- left right))
   7528 
   7529 (defun lsp--imenu-compare-line-col (sym1 sym2)
   7530   (if (lsp--line-col-comparator
   7531        (lsp--get-line-and-col sym1)
   7532        (lsp--get-line-and-col sym2))
   7533       -1
   7534     1))
   7535 
   7536 (lsp-defun lsp--imenu-compare-name ((&SymbolInformation :name name1)
   7537                                     (&SymbolInformation :name name2))
   7538   "Compare SYM1 and SYM2 by name."
   7539   (let ((result (compare-strings name1 0 (length name1) name2 0 (length name2))))
   7540     (if (numberp result) result 0)))
   7541 
   7542 (defun lsp--imenu-refresh ()
   7543   "Force Imenu to refresh itself."
   7544   (imenu--menubar-select imenu--rescan-item))
   7545 
   7546 (defun lsp-enable-imenu ()
   7547   "Use lsp-imenu for the current buffer."
   7548   (imenu--cleanup)
   7549   (add-function :override (local 'imenu-create-index-function) #'lsp--imenu-create-index)
   7550   (setq-local imenu-menubar-modified-tick -1)
   7551   (setq-local imenu--index-alist nil)
   7552   (when menu-bar-mode
   7553     (lsp--imenu-refresh)))
   7554 
   7555 (defun lsp-resolve-final-command (command &optional test?)
   7556   "Resolve final function COMMAND."
   7557   (let* ((command (lsp-resolve-value command))
   7558          (command (cl-etypecase command
   7559                     (list
   7560                      (cl-assert (seq-every-p (apply-partially #'stringp) command) nil
   7561                                 "Invalid command list")
   7562                      command)
   7563                     (string (list command)))))
   7564     (if (and (file-remote-p default-directory) (not test?))
   7565         (list shell-file-name "-c"
   7566               (string-join (cons "stty raw > /dev/null;"
   7567                                  (mapcar #'shell-quote-argument command))
   7568                            " "))
   7569       command)))
   7570 
   7571 (defun lsp-server-present? (final-command)
   7572   "Check whether FINAL-COMMAND is present."
   7573   (let ((binary-found? (executable-find (cl-first final-command) t)))
   7574     (if binary-found?
   7575         (lsp-log "Command \"%s\" is present on the path." (s-join " " final-command))
   7576       (lsp-log "Command \"%s\" is not present on the path." (s-join " " final-command)))
   7577     binary-found?))
   7578 
   7579 (defun lsp--value-to-string (value)
   7580   "Convert VALUE to a string that can be set as value in an environment
   7581 variable."
   7582   (cond
   7583    ((stringp value) value)
   7584    ((booleanp value) (if value
   7585                          "1"
   7586                        "0"))
   7587    ((and (sequencep value)
   7588          (seq-every-p #'stringp value)) (string-join value ":"))
   7589    (t (user-error "Only strings, booleans, and sequences of strings are supported as environment variables"))))
   7590 
   7591 (defun lsp--compute-process-environment (environment-fn)
   7592   "Append a list of KEY=VALUE from the alist ENVIRONMENT to `process-environment'.
   7593 Ignore non-boolean keys whose value is nil."
   7594   (let ((environment (if environment-fn
   7595                          (funcall environment-fn)
   7596                        nil)))
   7597     (-flatten (cons (cl-loop for (key . value) in environment
   7598                              if (or (eval value)
   7599                                     (eq (get value 'custom-type) 'boolean))
   7600                              collect (concat key "=" (lsp--value-to-string
   7601                                                       (eval value))))
   7602                     process-environment))))
   7603 
   7604 (defun lsp--default-directory-for-connection (&optional path)
   7605   "Return path to be used for the working directory of a LSP process.
   7606 
   7607 If `lsp-use-workspace-root-for-server-default-directory' is
   7608 non-nil, uses `lsp-workspace-root' to find the directory
   7609 corresponding to PATH, else returns `default-directory'."
   7610   (if lsp-use-workspace-root-for-server-default-directory
   7611       (lsp-workspace-root path)
   7612     default-directory))
   7613 
   7614 (defun lsp--fix-remote-cmd (program)
   7615   "Helper for `lsp-stdio-connection'.
   7616 Originally coppied from eglot."
   7617 
   7618   (if (file-remote-p default-directory)
   7619       (list shell-file-name "-c"
   7620             (string-join (cons "stty raw > /dev/null;"
   7621                                (mapcar #'shell-quote-argument program))
   7622                          " "))
   7623     program))
   7624 
   7625 (defvar tramp-use-ssh-controlmaster-options)
   7626 (defvar tramp-ssh-controlmaster-options)
   7627 
   7628 (defun lsp-stdio-connection (command &optional test-command)
   7629   "Returns a connection property list using COMMAND.
   7630 COMMAND can be: A string, denoting the command to launch the
   7631 language server. A list of strings, denoting an executable with
   7632 its command line arguments. A function, that either returns a
   7633 string or a list of strings. In all cases, the launched language
   7634 server should send and receive messages on standard I/O.
   7635 TEST-COMMAND is a function with no arguments which returns
   7636 whether the command is present or not. When not specified
   7637 `lsp-mode' will check whether the first element of the list
   7638 returned by COMMAND is available via `executable-find'"
   7639   (cl-check-type command (or string
   7640                              function
   7641                              (and list
   7642                                   (satisfies (lambda (l)
   7643                                                (seq-every-p (lambda (el)
   7644                                                               (stringp el))
   7645                                                             l))))))
   7646   (list :connect (lambda (filter sentinel name environment-fn workspace)
   7647                    (if (and (functionp 'json-rpc-connection)
   7648                             (not (file-remote-p default-directory)))
   7649                        (lsp-json-rpc-connection workspace (lsp-resolve-final-command command))
   7650                      (let ((final-command (lsp-resolve-final-command command))
   7651                            (process-name (generate-new-buffer-name name))
   7652                            (process-environment
   7653                             (lsp--compute-process-environment environment-fn)))
   7654                        (let* ((stderr-buf (get-buffer-create (format "*%s::stderr*" process-name)))
   7655                               (default-directory (lsp--default-directory-for-connection))
   7656                               (tramp-use-ssh-controlmaster-options 'suppress)
   7657                               (tramp-ssh-controlmaster-options "-o ControlMaster=no -o ControlPath=none")
   7658                               (proc (make-process
   7659                                      :name process-name
   7660                                      :connection-type 'pipe
   7661                                      :buffer (format "*%s*" process-name)
   7662                                      :coding 'no-conversion
   7663                                      :command final-command
   7664                                      :filter filter
   7665                                      :sentinel sentinel
   7666                                      :stderr stderr-buf
   7667                                      :noquery t
   7668                                      :file-handler t)))
   7669                          (set-process-query-on-exit-flag proc nil)
   7670                          (set-process-query-on-exit-flag (get-buffer-process stderr-buf) nil)
   7671                          (with-current-buffer (get-buffer stderr-buf)
   7672                            ;; Make the *NAME::stderr* buffer buffer-read-only, q to bury, etc.
   7673                            (special-mode))
   7674                          (cons proc proc)))))
   7675         :test? (or
   7676                 test-command
   7677                 (lambda ()
   7678                   (lsp-server-present? (lsp-resolve-final-command command t))))))
   7679 
   7680 (defun lsp--open-network-stream (host port name)
   7681   "Open network stream to HOST:PORT.
   7682   NAME will be passed to `open-network-stream'.
   7683   RETRY-COUNT is the number of the retries.
   7684   SLEEP-INTERVAL is the sleep interval between each retry."
   7685   (let* ((retries 0)
   7686          (sleep-interval 0.01)
   7687          (number-of-retries (/ lsp-tcp-connection-timeout sleep-interval))
   7688          connection)
   7689     (while (and (not connection) (< retries number-of-retries))
   7690       (condition-case err
   7691           (setq connection (open-network-stream name nil host port
   7692                                                 :type 'plain
   7693                                                 :coding 'no-conversion))
   7694         (file-error
   7695          (let ((inhibit-message t))
   7696            (lsp--warn "Failed to connect to %s:%s with error message %s"
   7697                       host
   7698                       port
   7699                       (error-message-string err))
   7700            (sleep-for sleep-interval)
   7701            (cl-incf retries)))))
   7702     (or connection (error "Port %s was never taken. Consider increasing `lsp-tcp-connection-timeout'." port))))
   7703 
   7704 (defun lsp--port-available (host port)
   7705   "Return non-nil if HOST and PORT are available."
   7706   (condition-case _err
   7707       (delete-process (open-network-stream "*connection-test*" nil host port :type 'plain))
   7708     (file-error t)))
   7709 
   7710 (defun lsp--find-available-port (host starting-port)
   7711   "Find available port on HOST starting from STARTING-PORT."
   7712   (let ((port starting-port))
   7713     (while (not (lsp--port-available host port))
   7714       (cl-incf port))
   7715     port))
   7716 
   7717 (defun lsp-tcp-connection (command-fn)
   7718   "Returns a connection property list similar to `lsp-stdio-connection'.
   7719 COMMAND-FN can only be a function that takes a single argument, a
   7720 port number. It should return a command for launches a language server
   7721 process listening for TCP connections on the provided port."
   7722   (cl-check-type command-fn function)
   7723   (list
   7724    :connect (lambda (filter sentinel name environment-fn _workspace)
   7725               (let* ((host "localhost")
   7726                      (port (lsp--find-available-port host (cl-incf lsp--tcp-port)))
   7727                      (command (funcall command-fn port))
   7728                      (final-command (if (consp command) command (list command)))
   7729                      (_ (unless (lsp-server-present? final-command)
   7730                           (user-error (format "Couldn't find executable %s" (cl-first final-command)))))
   7731                      (process-environment
   7732                       (lsp--compute-process-environment environment-fn))
   7733                      (proc (make-process :name name :connection-type 'pipe :coding 'no-conversion
   7734                                          :command final-command :sentinel sentinel :stderr (format "*%s::stderr*" name) :noquery t))
   7735                      (tcp-proc (lsp--open-network-stream host port (concat name "::tcp"))))
   7736 
   7737                 ;; TODO: Same :noquery issue (see above)
   7738                 (set-process-query-on-exit-flag proc nil)
   7739                 (set-process-query-on-exit-flag tcp-proc nil)
   7740                 (set-process-filter tcp-proc filter)
   7741                 (cons tcp-proc proc)))
   7742    :test? (lambda () (lsp-server-present? (funcall command-fn 0)))))
   7743 
   7744 (defalias 'lsp-tcp-server 'lsp-tcp-server-command)
   7745 
   7746 (defun lsp-tcp-server-command (command-fn)
   7747   "Create tcp server connection.
   7748 In this mode Emacs is TCP server and the language server connects
   7749 to it. COMMAND is function with one parameter(the port) and it
   7750 should return the command to start the LS server."
   7751   (cl-check-type command-fn function)
   7752   (list
   7753    :connect (lambda (filter sentinel name environment-fn _workspace)
   7754               (let* (tcp-client-connection
   7755                      (tcp-server (make-network-process :name (format "*tcp-server-%s*" name)
   7756                                                        :buffer (format "*tcp-server-%s*" name)
   7757                                                        :family 'ipv4
   7758                                                        :service lsp--tcp-server-port
   7759                                                        :sentinel (lambda (proc _string)
   7760                                                                    (lsp-log "Language server %s is connected." name)
   7761                                                                    (setf tcp-client-connection proc))
   7762                                                        :server 't))
   7763                      (port (process-contact tcp-server :service))
   7764                      (final-command (funcall command-fn port))
   7765                      (process-environment
   7766                       (lsp--compute-process-environment environment-fn))
   7767                      (cmd-proc (make-process :name name
   7768                                              :connection-type 'pipe
   7769                                              :coding 'no-conversion
   7770                                              :command final-command
   7771                                              :stderr (format "*tcp-server-%s*::stderr" name)
   7772                                              :noquery t)))
   7773                 (let ((retries 0))
   7774                   ;; wait for the client to connect (we sit-for 500 ms, so have to double lsp--tcp-server-wait-seconds)
   7775                   (while (and (not tcp-client-connection) (< retries (* 2 lsp--tcp-server-wait-seconds)))
   7776                     (lsp--info "Waiting for connection for %s, retries: %s" name retries)
   7777                     (sit-for 0.500)
   7778                     (cl-incf retries)))
   7779 
   7780                 (unless tcp-client-connection
   7781                   (condition-case nil (delete-process tcp-server) (error))
   7782                   (condition-case nil (delete-process cmd-proc) (error))
   7783                   (error "Failed to create connection to %s on port %s" name port))
   7784                 (lsp--info "Successfully connected to %s" name)
   7785 
   7786                 (set-process-query-on-exit-flag cmd-proc nil)
   7787                 (set-process-query-on-exit-flag tcp-client-connection nil)
   7788                 (set-process-query-on-exit-flag tcp-server nil)
   7789 
   7790                 (set-process-filter tcp-client-connection filter)
   7791                 (set-process-sentinel tcp-client-connection sentinel)
   7792                 (cons tcp-client-connection cmd-proc)))
   7793    :test? (lambda () (lsp-server-present? (funcall command-fn 0)))))
   7794 
   7795 (defalias 'lsp-tramp-connection 'lsp-stdio-connection)
   7796 
   7797 (defun lsp--auto-configure ()
   7798   "Autoconfigure `company', `flycheck', `lsp-ui', etc if they are installed."
   7799   (when (functionp 'lsp-ui-mode)
   7800     (lsp-ui-mode))
   7801 
   7802   (if lsp-headerline-breadcrumb-enable
   7803       (add-hook 'lsp-configure-hook 'lsp-headerline-breadcrumb-mode)
   7804     (remove-hook 'lsp-configure-hook 'lsp-headerline-breadcrumb-mode))
   7805   (if lsp-modeline-code-actions-enable
   7806       (add-hook 'lsp-configure-hook 'lsp-modeline-code-actions-mode)
   7807     (remove-hook 'lsp-configure-hook 'lsp-modeline-code-actions-mode))
   7808   (if lsp-modeline-diagnostics-enable
   7809       (add-hook 'lsp-configure-hook 'lsp-modeline-diagnostics-mode)
   7810     (remove-hook 'lsp-configure-hook 'lsp-modeline-diagnostics-mode))
   7811   (if lsp-modeline-workspace-status-enable
   7812       (add-hook 'lsp-configure-hook 'lsp-modeline-workspace-status-mode)
   7813     (remove-hook 'lsp-configure-hook 'lsp-modeline-workspace-status-mode))
   7814   (if lsp-lens-enable
   7815       (add-hook 'lsp-configure-hook 'lsp-lens--enable)
   7816     (remove-hook 'lsp-configure-hook 'lsp-lens--enable))
   7817   (if lsp-semantic-tokens-enable
   7818       (add-hook 'lsp-configure-hook 'lsp-semantic-tokens--enable)
   7819     (remove-hook 'lsp-configure-hook 'lsp-semantic-tokens--enable))
   7820 
   7821   ;; yas-snippet config
   7822   (setq-local yas-inhibit-overlay-modification-protection t))
   7823 
   7824 (defun lsp--restart-if-needed (workspace)
   7825   "Handler restart for WORKSPACE."
   7826   (when (or (eq lsp-restart 'auto-restart)
   7827             (eq (lsp--workspace-shutdown-action workspace) 'restart)
   7828             (and (eq lsp-restart 'interactive)
   7829                  (let ((query (format
   7830                                "Server %s exited (check corresponding stderr buffer for details). Do you want to restart it?"
   7831                                (lsp--workspace-print workspace))))
   7832                    (y-or-n-p query))))
   7833     (--each (lsp--workspace-buffers workspace)
   7834       (when (lsp-buffer-live-p it)
   7835         (lsp-with-current-buffer it
   7836           (if lsp--buffer-deferred
   7837               (lsp-deferred)
   7838             (lsp--info "Restarting LSP in buffer %s" (buffer-name))
   7839             (lsp)))))))
   7840 
   7841 (defun lsp--update-key (table key fn)
   7842   "Apply FN on value corresponding to KEY in TABLE."
   7843   (let ((existing-value (gethash key table)))
   7844     (if-let* ((new-value (funcall fn existing-value)))
   7845         (puthash key new-value table)
   7846       (remhash key table))))
   7847 
   7848 (defun lsp--process-sentinel (workspace process exit-str)
   7849   "Create the sentinel for WORKSPACE."
   7850   (unless (process-live-p process)
   7851     (lsp--handle-process-exit workspace exit-str)))
   7852 
   7853 (defun lsp--handle-process-exit (workspace exit-str)
   7854   (let* ((folder->workspaces (lsp-session-folder->servers (lsp-session)))
   7855          (proc (lsp--workspace-proc workspace)))
   7856     (lsp--warn "%s has exited (%s)"
   7857                (lsp-process-name proc)
   7858                (string-trim-right (or exit-str "")))
   7859     (with-lsp-workspace workspace
   7860       ;; Clean workspace related data in each of the buffers
   7861       ;; in the workspace.
   7862       (--each (lsp--workspace-buffers workspace)
   7863         (when (lsp-buffer-live-p it)
   7864           (lsp-with-current-buffer it
   7865             (setq lsp--buffer-workspaces (delete workspace lsp--buffer-workspaces))
   7866             (lsp--uninitialize-workspace)
   7867             (lsp--spinner-stop)
   7868             (lsp--remove-overlays 'lsp-highlight))))
   7869 
   7870       ;; Cleanup session from references to the closed workspace.
   7871       (--each (hash-table-keys folder->workspaces)
   7872         (lsp--update-key folder->workspaces it (apply-partially 'delete workspace)))
   7873 
   7874       (lsp-process-cleanup proc))
   7875 
   7876     (run-hook-with-args 'lsp-after-uninitialized-functions workspace)
   7877 
   7878     (if (eq (lsp--workspace-shutdown-action workspace) 'shutdown)
   7879         (lsp--info "Workspace %s shutdown." (lsp--workspace-print workspace))
   7880       (lsp--restart-if-needed workspace))
   7881     (lsp--cleanup-hanging-watches)))
   7882 
   7883 (defun lsp-workspace-folders (workspace)
   7884   "Return all folders associated with WORKSPACE."
   7885   (let (result)
   7886     (->> (lsp-session)
   7887          (lsp-session-folder->servers)
   7888          (maphash (lambda (folder workspaces)
   7889                     (when (-contains? workspaces workspace)
   7890                       (push folder result)))))
   7891     result))
   7892 
   7893 (defun lsp--start-workspace (session client-template root &optional initialization-options)
   7894   "Create new workspace for CLIENT-TEMPLATE with project root ROOT.
   7895 INITIALIZATION-OPTIONS are passed to initialize function.
   7896 SESSION is the active session."
   7897   (lsp--spinner-start)
   7898   (-let* ((default-directory root)
   7899           (client (copy-lsp--client client-template))
   7900           (workspace (make-lsp--workspace
   7901                       :root root
   7902                       :client client
   7903                       :status 'starting
   7904                       :buffers (list (lsp-current-buffer))
   7905                       :host-root (file-remote-p root)))
   7906           ((&lsp-cln 'server-id 'environment-fn 'new-connection 'custom-capabilities
   7907                      'multi-root 'initialized-fn) client)
   7908           ((proc . cmd-proc) (funcall
   7909                               (or (plist-get new-connection :connect)
   7910                                   (user-error "Client %s is configured incorrectly" client))
   7911                               (lsp--create-filter-function workspace)
   7912                               (apply-partially #'lsp--process-sentinel workspace)
   7913                               (format "%s" server-id)
   7914                               environment-fn
   7915                               workspace))
   7916           (workspace-folders (gethash server-id (lsp-session-server-id->folders session))))
   7917     (setf (lsp--workspace-proc workspace) proc
   7918           (lsp--workspace-cmd-proc workspace) cmd-proc)
   7919 
   7920     ;; update (lsp-session-folder->servers) depending on whether we are starting
   7921     ;; multi/single folder workspace
   7922     (mapc (lambda (project-root)
   7923             (->> session
   7924                  (lsp-session-folder->servers)
   7925                  (gethash project-root)
   7926                  (cl-pushnew workspace)))
   7927           (or workspace-folders (list root)))
   7928 
   7929     (with-lsp-workspace workspace
   7930       (run-hooks 'lsp-before-initialize-hook)
   7931       (lsp-request-async
   7932        "initialize"
   7933        (append
   7934         (list :processId (unless (file-remote-p (buffer-file-name))
   7935                            (emacs-pid))
   7936               :rootPath (lsp-file-local-name (expand-file-name root))
   7937               :clientInfo (list :name "emacs"
   7938                                 :version (emacs-version))
   7939               :rootUri (lsp--path-to-uri root)
   7940               :capabilities (lsp--client-capabilities custom-capabilities)
   7941               :initializationOptions initialization-options
   7942               :workDoneToken "1")
   7943         (when lsp-server-trace
   7944           (list :trace lsp-server-trace))
   7945         (when multi-root
   7946           (->> workspace-folders
   7947                (-distinct)
   7948                (-map (lambda (folder)
   7949                        (list :uri (lsp--path-to-uri folder)
   7950                              :name (f-filename folder))))
   7951                (apply 'vector)
   7952                (list :workspaceFolders))))
   7953        (-lambda ((&InitializeResult :capabilities))
   7954          ;; we know that Rust Analyzer will send {} which will be parsed as null
   7955          ;; when using plists
   7956          (when (equal 'rust-analyzer server-id)
   7957            (-> capabilities
   7958                (lsp:server-capabilities-text-document-sync?)
   7959                (lsp:set-text-document-sync-options-save? t)))
   7960 
   7961          (setf (lsp--workspace-server-capabilities workspace) capabilities
   7962                (lsp--workspace-status workspace) 'initialized)
   7963 
   7964          (with-lsp-workspace workspace
   7965            (lsp-notify "initialized" lsp--empty-ht))
   7966 
   7967          (when initialized-fn (funcall initialized-fn workspace))
   7968 
   7969          (cl-callf2 -filter #'lsp-buffer-live-p (lsp--workspace-buffers workspace))
   7970          (->> workspace
   7971               (lsp--workspace-buffers)
   7972               (mapc (lambda (buffer)
   7973                       (lsp-with-current-buffer buffer
   7974                         (lsp--open-in-workspace workspace)))))
   7975 
   7976          (with-lsp-workspace workspace
   7977            (run-hooks 'lsp-after-initialize-hook))
   7978          (lsp--info "%s initialized successfully in folders: %s"
   7979                     (lsp--workspace-print workspace)
   7980                     (lsp-workspace-folders workspace)))
   7981        :mode 'detached))
   7982     workspace))
   7983 
   7984 (defun lsp--load-default-session ()
   7985   "Load default session."
   7986   (setq lsp--session (or (condition-case err
   7987                              (lsp--read-from-file lsp-session-file)
   7988                            (error (lsp--error "Failed to parse the session %s, starting with clean one."
   7989                                               (error-message-string err))
   7990                                   nil))
   7991                          (make-lsp-session))))
   7992 
   7993 (defun lsp-session ()
   7994   "Get the session associated with the current buffer."
   7995   (or lsp--session (setq lsp--session (lsp--load-default-session))))
   7996 
   7997 (defun lsp--client-disabled-p (buffer-major-mode client)
   7998   (seq-some
   7999    (lambda (entry)
   8000      (pcase entry
   8001        ((pred symbolp) (eq entry client))
   8002        (`(,mode . ,client-or-list)
   8003         (and (eq mode buffer-major-mode)
   8004              (if (listp client-or-list)
   8005                  (memq client client-or-list)
   8006                (eq client client-or-list))))))
   8007    lsp-disabled-clients))
   8008 
   8009 
   8010 ;; download server
   8011 
   8012 (defcustom lsp-server-install-dir (expand-file-name
   8013                                    (locate-user-emacs-file (f-join ".cache" "lsp")))
   8014   "Directory in which the servers will be installed."
   8015   :risky t
   8016   :type 'directory
   8017   :package-version '(lsp-mode . "6.3")
   8018   :group 'lsp-mode)
   8019 
   8020 (defcustom lsp-verify-signature t
   8021   "Whether to check GPG signatures of downloaded files."
   8022   :type 'boolean
   8023   :package-version '(lsp-mode . "8.0.0")
   8024   :group 'lsp-mode)
   8025 
   8026 (defvar lsp--dependencies (ht))
   8027 
   8028 (defun lsp-dependency (name &rest definitions)
   8029   "Used to specify a language server DEPENDENCY, the server
   8030 executable or other required file path. Typically, the
   8031 DEPENDENCY is found by locating it on the system path using
   8032 `executable-find'.
   8033 
   8034 You can explicitly call lsp-dependency in your environment to
   8035 specify the absolute path to the DEPENDENCY. For example, the
   8036 typescript-language-server requires both the server and the
   8037 typescript compiler. If you have installed them in a team shared
   8038 read-only location, you can instruct lsp-mode to use them via
   8039 
   8040  (eval-after-load `lsp-mode
   8041    `(progn
   8042       (require lsp-javascript)
   8043       (lsp-dependency typescript-language-server (:system ,tls-exe))
   8044       (lsp-dependency typescript (:system ,ts-js))))
   8045 
   8046 where tls-exe is the absolute path to the typescript-language-server
   8047 executable and ts-js is the absolute path to the typescript compiler
   8048 JavaScript file, tsserver.js (the *.js is required for Windows)."
   8049   (ht-set lsp--dependencies name definitions))
   8050 
   8051 (defun lsp--server-binary-present? (client)
   8052   (unless (equal (lsp--client-server-id client) 'lsp-pwsh)
   8053     (condition-case ()
   8054         (-some-> client lsp--client-new-connection (plist-get :test?) funcall)
   8055       (error nil)
   8056       (args-out-of-range nil))))
   8057 
   8058 (define-minor-mode lsp-installation-buffer-mode
   8059   "Mode used in *lsp-installation* buffers.
   8060 It can be used to set-up keybindings, etc. Disabling this mode
   8061 detaches the installation buffer from commands like
   8062 `lsp-select-installation-buffer'."
   8063   :init-value nil
   8064   :lighter nil)
   8065 
   8066 (defface lsp-installation-finished-buffer-face '((t :foreground "orange"))
   8067   "Face used for finished installation buffers.
   8068 Used in `lsp-select-installation-buffer'."
   8069   :group 'lsp-mode)
   8070 
   8071 (defface lsp-installation-buffer-face '((t :foreground "green"))
   8072   "Face used for installation buffers still in progress.
   8073 Used in `lsp-select-installation-buffer'."
   8074   :group 'lsp-mode)
   8075 
   8076 (defun lsp--installation-buffer? (buf)
   8077   "Check whether BUF is an `lsp-async-start-process' buffer."
   8078   (buffer-local-value 'lsp-installation-buffer-mode buf))
   8079 
   8080 (defun lsp-select-installation-buffer (&optional show-finished)
   8081   "Interactively choose an installation buffer.
   8082 If SHOW-FINISHED is set, leftover (finished) installation buffers
   8083 are still shown."
   8084   (interactive "P")
   8085   (let ((bufs (--filter (and (lsp--installation-buffer? it)
   8086                              (or show-finished (get-buffer-process it)))
   8087                         (buffer-list))))
   8088     (pcase bufs
   8089       (`nil (user-error "No installation buffers"))
   8090       (`(,buf) (pop-to-buffer buf))
   8091       (bufs (pop-to-buffer (completing-read "Select installation buffer: "
   8092                                             (--map (propertize (buffer-name it) 'face
   8093                                                                (if (get-buffer-process it)
   8094                                                                    'lsp-installation-buffer-face
   8095                                                                  'lsp-installation-finished-buffer-face))
   8096                                                    bufs)))))))
   8097 
   8098 (defun lsp-cleanup-installation-buffers ()
   8099   "Delete finished *lsp-installation* buffers."
   8100   (interactive)
   8101   (dolist (buf (buffer-list))
   8102     (when (and (lsp--installation-buffer? buf) (not (get-buffer-process buf)))
   8103       (kill-buffer buf))))
   8104 
   8105 (defun lsp--download-status ()
   8106   (-some--> #'lsp--client-download-in-progress?
   8107     (lsp--filter-clients it)
   8108     (-map (-compose #'symbol-name #'lsp--client-server-id) it)
   8109     (format "%s" it)
   8110     (propertize it 'face 'success)
   8111     (format " Installing following servers: %s" it)
   8112     (propertize it
   8113                 'local-map (make-mode-line-mouse-map
   8114                             'mouse-1 #'lsp-select-installation-buffer)
   8115                 'mouse-face 'highlight)))
   8116 
   8117 (defun lsp--install-server-internal (client &optional update?)
   8118   (unless (lsp--client-download-server-fn client)
   8119     (user-error "There is no automatic installation for `%s', you have to install it manually following lsp-mode's documentation."
   8120                 (lsp--client-server-id client)))
   8121 
   8122   (setf (lsp--client-download-in-progress? client) t)
   8123   (add-to-list 'global-mode-string '(t (:eval (lsp--download-status))))
   8124   (cl-flet ((done
   8125              (success? &optional error-message)
   8126              ;; run with idle timer to make sure the lsp command is executed in
   8127              ;; the main thread, see #2739.
   8128              (run-with-timer
   8129               0.0
   8130               nil
   8131               (lambda ()
   8132                 (-let [(&lsp-cln 'server-id 'buffers) client]
   8133                   (setf (lsp--client-download-in-progress? client) nil
   8134                         (lsp--client-buffers client) nil)
   8135                   (if success?
   8136                       (lsp--info "Server %s downloaded, auto-starting in %s buffers." server-id
   8137                                  (length buffers))
   8138                     (lsp--error "Server %s install process failed with the following error message: %s.
   8139 Check `*lsp-install*' and `*lsp-log*' buffer."
   8140                                 server-id
   8141                                 error-message))
   8142                   (seq-do
   8143                    (lambda (buffer)
   8144                      (when (lsp-buffer-live-p buffer)
   8145                        (lsp-with-current-buffer buffer
   8146                          (cl-callf2 -remove-item '(t (:eval (lsp--download-status)))
   8147                                     global-mode-string)
   8148                          (when success? (lsp)))))
   8149                    buffers)
   8150                   (unless (lsp--filter-clients #'lsp--client-download-in-progress?)
   8151                     (cl-callf2 -remove-item '(t (:eval (lsp--download-status)))
   8152                                global-mode-string)))))))
   8153     (lsp--info "Download %s started." (lsp--client-server-id client))
   8154     (condition-case err
   8155         (funcall
   8156          (lsp--client-download-server-fn client)
   8157          client
   8158          (lambda () (done t))
   8159          (lambda (msg) (done nil msg))
   8160          update?)
   8161       (error
   8162        (done nil (error-message-string err))))))
   8163 
   8164 (defun lsp--require-packages ()
   8165   "Load `lsp-client-packages' if needed."
   8166   (when (and lsp-auto-configure (not lsp--client-packages-required))
   8167     (seq-do (lambda (package)
   8168               ;; loading client is slow and `lsp' can be called repeatedly
   8169               (unless (featurep package)
   8170                 (require package nil t)))
   8171             lsp-client-packages)
   8172     (setq lsp--client-packages-required t)))
   8173 
   8174 ;;;###autoload
   8175 (defun lsp-install-server (update? &optional server-id)
   8176   "Interactively install or re-install server.
   8177 When prefix UPDATE? is t force installation even if the server is present."
   8178   (interactive "P")
   8179   (lsp--require-packages)
   8180   (let* ((chosen-client (or (gethash server-id lsp-clients)
   8181                             (lsp--completing-read
   8182                              "Select server to install/re-install: "
   8183                              (or (->> lsp-clients
   8184                                       (ht-values)
   8185                                       (-filter (-andfn
   8186                                                 (-not #'lsp--client-download-in-progress?)
   8187                                                 #'lsp--client-download-server-fn)))
   8188                                  (user-error "There are no servers with automatic installation"))
   8189                              (lambda (client)
   8190                                (let ((server-name (-> client lsp--client-server-id symbol-name)))
   8191                                  (if (lsp--server-binary-present? client)
   8192                                      (concat server-name " (Already installed)")
   8193                                    server-name)))
   8194                              nil
   8195                              t)))
   8196          (update? (or update?
   8197                       (and (not (lsp--client-download-in-progress? chosen-client))
   8198                            (lsp--server-binary-present? chosen-client)))))
   8199     (lsp--install-server-internal chosen-client update?)))
   8200 
   8201 ;;;###autoload
   8202 (defun lsp-uninstall-server (dir)
   8203   "Delete a LSP server from `lsp-server-install-dir'."
   8204   (interactive
   8205    (list (read-directory-name "Uninstall LSP server: " (f-slash lsp-server-install-dir))))
   8206   (unless (file-directory-p dir)
   8207     (user-error "Couldn't find %s directory" dir))
   8208   (delete-directory dir 'recursive)
   8209   (message "Server `%s' uninstalled." (file-name-nondirectory (directory-file-name dir))))
   8210 
   8211 ;;;###autoload
   8212 (defun lsp-uninstall-servers ()
   8213   "Uninstall all installed servers."
   8214   (interactive)
   8215   (let* ((dir lsp-server-install-dir)
   8216          (servers (ignore-errors
   8217                     (directory-files dir t
   8218                                      directory-files-no-dot-files-regexp))))
   8219     (if (or (not (file-directory-p dir)) (zerop (length servers)))
   8220         (user-error "No servers to uninstall")
   8221       (when (yes-or-no-p
   8222              (format "Servers to uninstall: %d (%s), proceed? "
   8223                      (length servers)
   8224                      (mapconcat (lambda (server)
   8225                                   (file-name-nondirectory (directory-file-name server)))
   8226                                 servers " ")))
   8227         (mapc #'lsp-uninstall-server servers)
   8228         (message "All servers uninstalled")))))
   8229 
   8230 ;;;###autoload
   8231 (defun lsp-update-server (&optional server-id)
   8232   "Interactively update (reinstall) a server."
   8233   (interactive)
   8234   (lsp--require-packages)
   8235   (let ((chosen-client (or (gethash server-id lsp-clients)
   8236                            (lsp--completing-read
   8237                             "Select server to update (if not on the list, probably you need to `lsp-install-server`): "
   8238                             (or (->> lsp-clients
   8239                                      (ht-values)
   8240                                      (-filter (-andfn
   8241                                                (-not #'lsp--client-download-in-progress?)
   8242                                                #'lsp--client-download-server-fn
   8243                                                #'lsp--server-binary-present?)))
   8244                                 (user-error "There are no servers to update"))
   8245                             (lambda (client)
   8246                               (-> client lsp--client-server-id symbol-name))
   8247                             nil
   8248                             t))))
   8249     (lsp--install-server-internal chosen-client t)))
   8250 
   8251 ;;;###autoload
   8252 (defun lsp-update-servers ()
   8253   "Update (reinstall) all installed servers."
   8254   (interactive)
   8255   (lsp--require-packages)
   8256   (mapc (lambda (client) (lsp--install-server-internal client t))
   8257         (-filter (-andfn
   8258                   (-not #'lsp--client-download-in-progress?)
   8259                   #'lsp--client-download-server-fn
   8260                   #'lsp--server-binary-present?) (hash-table-values lsp-clients))))
   8261 
   8262 ;;;###autoload
   8263 (defun lsp-ensure-server (server-id)
   8264   "Ensure server SERVER-ID"
   8265   (lsp--require-packages)
   8266   (if-let* ((client (gethash server-id lsp-clients)))
   8267       (unless (lsp--server-binary-present? client)
   8268         (lsp--info "Server `%s' is not preset, installing..." server-id)
   8269         (lsp-install-server nil server-id))
   8270     (warn "Unable to find server registration with id %s" server-id)))
   8271 
   8272 (defun lsp-async-start-process (callback error-callback &rest command)
   8273   "Start async process COMMAND with CALLBACK and ERROR-CALLBACK."
   8274   (let ((name (cl-first command)))
   8275     (with-current-buffer (compilation-start (mapconcat #'shell-quote-argument (-filter (lambda (cmd)
   8276                                                                                          (not (null cmd)))
   8277                                                                                        command)
   8278                                                        " ") t
   8279                                             (lambda (&rest _)
   8280                                               (generate-new-buffer-name (format "*lsp-install: %s*" name))))
   8281       (lsp-installation-buffer-mode +1)
   8282       (view-mode +1)
   8283       (add-hook
   8284        'compilation-finish-functions
   8285        (lambda (_buf status)
   8286          (if (string= "finished\n" status)
   8287              (condition-case err
   8288                  (funcall callback)
   8289                (error
   8290                 (funcall error-callback (error-message-string err))))
   8291            (funcall error-callback (s-trim-right status))))
   8292        nil t))))
   8293 
   8294 (defun lsp-resolve-value (value)
   8295   "Resolve VALUE's value.
   8296 If it is function - call it.
   8297 If it is a variable - return it's value
   8298 Otherwise returns value itself."
   8299   (cond
   8300    ((functionp value) (funcall value))
   8301    ((and (symbolp value) (boundp value)) (symbol-value value))
   8302    (value)))
   8303 
   8304 (defvar lsp-deps-providers
   8305   (list :npm (list :path #'lsp--npm-dependency-path
   8306                    :install #'lsp--npm-dependency-install)
   8307         :cargo (list :path #'lsp--cargo-dependency-path
   8308                      :install #'lsp--cargo-dependency-install)
   8309         :system (list :path #'lsp--system-path)
   8310         :download (list :path #'lsp-download-path
   8311                         :install #'lsp-download-install)))
   8312 
   8313 (defun lsp--system-path (path)
   8314   "If PATH is absolute and exists return it as is. Otherwise,
   8315 return the absolute path to the executable defined by PATH or
   8316 nil."
   8317   ;; For node.js 'sub-packages' PATH may point to a *.js file. Consider the
   8318   ;; typescript-language-server. When lsp invokes the server, lsp needs to
   8319   ;; supply the path to the typescript compiler, tsserver.js, as an argument. To
   8320   ;; make code platform independent, one must pass the absolute path to the
   8321   ;; tsserver.js file (Windows requires a *.js file - see help on the JavaScript
   8322   ;; child process spawn command that is invoked by the
   8323   ;; typescript-language-server). This is why we check for existence and not
   8324   ;; that the path is executable.
   8325   (let ((path (lsp-resolve-value path)))
   8326     (cond
   8327      ((and (f-absolute? path)
   8328            (f-exists? path))
   8329       path)
   8330      ((executable-find path t) path))))
   8331 
   8332 (defun lsp-package-path (dependency)
   8333   "Path to the DEPENDENCY each of the registered providers."
   8334   (let (path)
   8335     (--first (-let [(provider . rest) it]
   8336               (setq path (-some-> lsp-deps-providers
   8337                            (plist-get provider)
   8338                            (plist-get :path)
   8339                            (apply rest))))
   8340              (gethash dependency lsp--dependencies))
   8341     path))
   8342 
   8343 (defun lsp-package-ensure (dependency callback error-callback)
   8344   "Asynchronously ensure a package."
   8345   (or (-first (-lambda ((provider . rest))
   8346                 (-some-> lsp-deps-providers
   8347                   (plist-get provider)
   8348                   (plist-get :install)
   8349                   (apply (cl-list* callback error-callback rest))))
   8350               (gethash dependency lsp--dependencies))
   8351       (funcall error-callback (format "Unable to find a way to install %s" dependency))))
   8352 
   8353 
   8354 ;; npm handling
   8355 
   8356 ;; https://docs.npmjs.com/files/folders#executables
   8357 (cl-defun lsp--npm-dependency-path (&key package path &allow-other-keys)
   8358   "Return npm dependency PATH for PACKAGE."
   8359   (let ((path (executable-find
   8360                (f-join lsp-server-install-dir "npm" package
   8361                        (cond ((eq system-type 'windows-nt) "")
   8362                              (t "bin"))
   8363                        path)
   8364                t)))
   8365     (unless (and path (f-exists? path))
   8366       (error "The package %s is not installed.  Unable to find %s" package path))
   8367     path))
   8368 
   8369 (cl-defun lsp--npm-dependency-install (callback error-callback &key package &allow-other-keys)
   8370   (if-let* ((npm-binary (executable-find "npm")))
   8371       (progn
   8372         ;; Explicitly `make-directory' to work around NPM bug in
   8373         ;; versions 7.0.0 through 7.4.1. See
   8374         ;; https://github.com/emacs-lsp/lsp-mode/issues/2364 for
   8375         ;; discussion.
   8376         (make-directory (f-join lsp-server-install-dir "npm" package "lib") 'parents)
   8377         (lsp-async-start-process (lambda ()
   8378                                    (if (string-empty-p
   8379                                         (string-trim (shell-command-to-string
   8380                                                       (mapconcat #'shell-quote-argument `(,npm-binary "view" ,package "peerDependencies") " "))))
   8381                                        (funcall callback)
   8382                                      (let ((default-directory (f-dirname (car (last (directory-files-recursively (f-join lsp-server-install-dir "npm" package) "package.json")))))
   8383                                            (process-environment (append '("npm_config_yes=true") process-environment))) ;; Disable prompting for older versions of npx
   8384                                        (when (f-dir-p default-directory)
   8385                                          (lsp-async-start-process callback
   8386                                                                   error-callback
   8387                                                                   (executable-find "npx")
   8388                                                                   "npm-install-peers")))))
   8389                                  error-callback
   8390                                  npm-binary
   8391                                  "-g"
   8392                                  "--prefix"
   8393                                  (f-join lsp-server-install-dir "npm" package)
   8394                                  "install"
   8395                                  package))
   8396     (lsp-log "Unable to install %s via `npm' because it is not present" package)
   8397     nil))
   8398 
   8399 
   8400 ;; Cargo dependency handling
   8401 (cl-defun lsp--cargo-dependency-path (&key package path &allow-other-keys)
   8402   (let ((path (executable-find
   8403                (f-join lsp-server-install-dir
   8404                        "cargo"
   8405                        package
   8406                        "bin"
   8407                        path)
   8408                t)))
   8409     (unless (and path (f-exists? path))
   8410       (error "The package %s is not installed.  Unable to find %s" package path))
   8411     path))
   8412 
   8413 (cl-defun lsp--cargo-dependency-install (callback error-callback &key package git &allow-other-keys)
   8414   (if-let* ((cargo-binary (executable-find "cargo")))
   8415       (lsp-async-start-process
   8416        callback
   8417        error-callback
   8418        cargo-binary
   8419        "install"
   8420        package
   8421        (when git
   8422          "--git")
   8423        git
   8424        "--root"
   8425        (f-join lsp-server-install-dir "cargo" package))
   8426     (lsp-log "Unable to install %s via `cargo' because it is not present" package)
   8427     nil))
   8428 
   8429 
   8430 
   8431 ;; Download URL handling
   8432 (cl-defun lsp-download-install (callback error-callback &key url asc-url pgp-key store-path decompress &allow-other-keys)
   8433   (let* ((url (lsp-resolve-value url))
   8434          (store-path (lsp-resolve-value store-path))
   8435          ;; (decompress (lsp-resolve-value decompress))
   8436          (download-path
   8437           (pcase decompress
   8438             (:gzip (concat store-path ".gz"))
   8439             (:zip (concat store-path ".zip"))
   8440             (:targz (concat store-path ".tar.gz"))
   8441             (`nil store-path)
   8442             (_ (error ":decompress must be `:gzip', `:zip', `:targz' or `nil'")))))
   8443     (make-thread
   8444      (lambda ()
   8445        (condition-case err
   8446            (progn
   8447              (when (f-exists? download-path)
   8448                (f-delete download-path))
   8449              (when (f-exists? store-path)
   8450                (f-delete store-path))
   8451              (lsp--info "Starting to download %s to %s..." url download-path)
   8452              (mkdir (f-parent download-path) t)
   8453              (url-copy-file url download-path)
   8454              (lsp--info "Finished downloading %s..." download-path)
   8455              (when (and lsp-verify-signature asc-url pgp-key)
   8456                (if (executable-find epg-gpg-program)
   8457                    (let ((asc-download-path (concat download-path ".asc"))
   8458                          (context (epg-make-context))
   8459                          (fingerprint)
   8460                          (signature))
   8461                      (when (f-exists? asc-download-path)
   8462                        (f-delete asc-download-path))
   8463                      (lsp--info "Starting to download %s to %s..." asc-url asc-download-path)
   8464                      (url-copy-file asc-url asc-download-path)
   8465                      (lsp--info "Finished downloading %s..." asc-download-path)
   8466                      (epg-import-keys-from-string context pgp-key)
   8467                      (setq fingerprint (epg-import-status-fingerprint
   8468                                         (car
   8469                                          (epg-import-result-imports
   8470                                           (epg-context-result-for context 'import)))))
   8471                      (lsp--info "Verifying signature %s..." asc-download-path)
   8472                      (epg-verify-file context asc-download-path download-path)
   8473                      (setq signature (car (epg-context-result-for context 'verify)))
   8474                      (unless (and
   8475                               (eq (epg-signature-status signature) 'good)
   8476                               (equal (epg-signature-fingerprint signature) fingerprint))
   8477                        (error "Failed to verify GPG signature: %s" (epg-signature-to-string signature))))
   8478                  (lsp--warn "GPG is not installed, skipping the signature check.")))
   8479              (when decompress
   8480                (lsp--info "Decompressing %s..." download-path)
   8481                (pcase decompress
   8482                  (:gzip
   8483                   (lsp-gunzip download-path))
   8484                  (:zip (lsp-unzip download-path (f-parent store-path)))
   8485                  (:targz (lsp-tar-gz-decompress download-path (f-parent store-path))))
   8486                (lsp--info "Decompressed %s..." store-path))
   8487              (funcall callback))
   8488          (error (funcall error-callback err)))))))
   8489 
   8490 (cl-defun lsp-download-path (&key store-path binary-path set-executable? &allow-other-keys)
   8491   "Download URL and store it into STORE-PATH.
   8492 
   8493 SET-EXECUTABLE? when non-nil change the executable flags of
   8494 STORE-PATH to make it executable. BINARY-PATH can be specified
   8495 when the binary to start does not match the name of the
   8496 archive (e.g. when the archive has multiple files)"
   8497   (let ((store-path (or (lsp-resolve-value binary-path)
   8498                         (lsp-resolve-value store-path))))
   8499     (cond
   8500      ((executable-find store-path) store-path)
   8501      ((and set-executable? (f-exists? store-path))
   8502       (set-file-modes store-path #o0700)
   8503       store-path)
   8504      ((f-exists? store-path) store-path))))
   8505 
   8506 (defun lsp--find-latest-gh-release-url (url regex)
   8507   "Fetch the latest version in the releases given by URL by using REGEX."
   8508   (let ((url-request-method "GET"))
   8509     (with-current-buffer (url-retrieve-synchronously url)
   8510       (goto-char (point-min))
   8511       (re-search-forward "\n\n" nil 'noerror)
   8512       (delete-region (point-min) (point))
   8513       (let* ((json-result (lsp-json-read-buffer)))
   8514         (message "Latest version found: %s" (lsp-get json-result :tag_name))
   8515         (--> json-result
   8516              (lsp-get it :assets)
   8517              (seq-find (lambda (entry) (string-match-p regex (lsp-get entry :name))) it)
   8518              (lsp-get it :browser_download_url))))))
   8519 
   8520 ;; unzip
   8521 
   8522 (defconst lsp-ext-pwsh-script "pwsh -noprofile -noninteractive \
   8523 -nologo -ex bypass -c Expand-Archive -Path '%s' -DestinationPath '%s'"
   8524   "Pwsh script to unzip file.")
   8525 
   8526 (defconst lsp-ext-powershell-script "powershell -noprofile -noninteractive \
   8527 -nologo -ex bypass -command Expand-Archive -path '%s' -dest '%s'"
   8528   "Powershell script to unzip file.")
   8529 
   8530 (defconst lsp-ext-unzip-script "bash -c 'mkdir -p %2$s && unzip -qq -o %1$s -d %2$s'"
   8531   "Unzip script to unzip file.")
   8532 
   8533 (defcustom lsp-unzip-script (lambda ()
   8534                               (cond ((and (eq system-type 'windows-nt)
   8535                                           (executable-find "pwsh"))
   8536                                      lsp-ext-pwsh-script)
   8537                                     ((and (eq system-type 'windows-nt)
   8538                                           (executable-find "powershell"))
   8539                                      lsp-ext-powershell-script)
   8540                                     ((executable-find "unzip") lsp-ext-unzip-script)
   8541                                     ((executable-find "pwsh") lsp-ext-pwsh-script)
   8542                                     (t nil)))
   8543   "The script to unzip."
   8544   :group 'lsp-mode
   8545   :type 'string
   8546   :package-version '(lsp-mode . "8.0.0"))
   8547 
   8548 (defun lsp-unzip (zip-file dest)
   8549   "Unzip ZIP-FILE to DEST."
   8550   (unless lsp-unzip-script
   8551     (error "Unable to find `unzip' or `powershell' on the path, please customize `lsp-unzip-script'"))
   8552   (shell-command (format (lsp-resolve-value lsp-unzip-script) zip-file dest)))
   8553 
   8554 ;; gunzip
   8555 
   8556 (defconst lsp-ext-gunzip-script "gzip -d %1$s"
   8557   "Script to decompress a gzippped file with gzip.")
   8558 
   8559 (defcustom lsp-gunzip-script (lambda ()
   8560                                (cond ((executable-find "gzip") lsp-ext-gunzip-script)
   8561                                      (t nil)))
   8562   "The script to decompress a gzipped file.
   8563 Should be a format string with one argument for the file to be decompressed
   8564 in place."
   8565   :group 'lsp-mode
   8566   :type 'string
   8567   :package-version '(lsp-mode . "8.0.0"))
   8568 
   8569 (defun lsp-gunzip (gz-file)
   8570   "Decompress GZ-FILE in place."
   8571   (unless lsp-gunzip-script
   8572     (error "Unable to find `gzip' on the path, please either customize `lsp-gunzip-script' or manually decompress %s" gz-file))
   8573   (shell-command (format (lsp-resolve-value lsp-gunzip-script) gz-file)))
   8574 
   8575 ;; tar.gz decompression
   8576 
   8577 (defconst lsp-ext-tar-script "bash -c 'mkdir -p %2$s; tar xf %1$s --directory=%2$s'"
   8578   "Script to decompress a .tar.gz file.")
   8579 
   8580 (defcustom lsp-tar-script (lambda ()
   8581                             (cond ((executable-find "tar") lsp-ext-tar-script)
   8582                                   (t nil)))
   8583   "The script to decompress a .tar.gz file.
   8584 Should be a format string with one argument for the file to be decompressed
   8585 in place."
   8586   :group 'lsp-mode
   8587   :type 'string)
   8588 
   8589 (defun lsp-tar-gz-decompress (targz-file dest)
   8590   "Decompress TARGZ-FILE in DEST."
   8591   (unless lsp-tar-script
   8592     (error "Unable to find `tar' on the path, please either customize `lsp-tar-script' or manually decompress %s" targz-file))
   8593   (shell-command (format (lsp-resolve-value lsp-tar-script) targz-file dest)))
   8594 
   8595 
   8596 ;; VSCode marketplace
   8597 
   8598 (defcustom lsp-vscode-ext-url
   8599   "https://marketplace.visualstudio.com/_apis/public/gallery/publishers/%s/vsextensions/%s/%s/vspackage%s"
   8600   "Vscode extension template url."
   8601   :group 'lsp-mode
   8602   :type 'string
   8603   :package-version '(lsp-mode . "8.0.0"))
   8604 
   8605 (defun lsp-vscode-extension-url (publisher name version &optional targetPlatform)
   8606   "Return the URL to vscode extension.
   8607 PUBLISHER is the extension publisher.
   8608 NAME is the name of the extension.
   8609 VERSION is the version of the extension.
   8610 TARGETPLATFORM is the targetPlatform of the extension."
   8611   (format lsp-vscode-ext-url publisher name version (or targetPlatform "")))
   8612 
   8613 
   8614 
   8615 ;; Queueing prompts
   8616 
   8617 (defvar lsp--question-queue nil
   8618   "List of questions yet to be asked by `lsp-ask-question'.")
   8619 
   8620 (defun lsp-ask-question (question options callback)
   8621   "Prompt the user to answer the QUESTION with one of the OPTIONS from the
   8622 minibuffer. Once the user selects an option, the CALLBACK function will be
   8623 called, passing the selected option to it.
   8624 
   8625 If the user is currently being shown a question, the question will be stored in
   8626 `lsp--question-queue', and will be asked once the user has answered the current
   8627 question."
   8628   (add-to-list 'lsp--question-queue `(("question" . ,question)
   8629                                       ("options" . ,options)
   8630                                       ("callback" . ,callback)) t)
   8631   (when (eq (length lsp--question-queue) 1)
   8632     (lsp--process-question-queue)))
   8633 
   8634 (defun lsp--process-question-queue ()
   8635   "Take the first question from `lsp--question-queue', process it, then process
   8636 the next question until the queue is empty."
   8637   (-let* (((&alist "question" "options" "callback") (car lsp--question-queue))
   8638           (answer (completing-read question options nil t)))
   8639     (pop lsp--question-queue)
   8640     (funcall callback answer)
   8641     (when lsp--question-queue
   8642       (lsp--process-question-queue))))
   8643 
   8644 (defun lsp--supports-buffer? (client)
   8645   (and
   8646    ;; both file and client remote or both local
   8647    (eq (---truthy? (file-remote-p (buffer-file-name)))
   8648        (---truthy? (lsp--client-remote? client)))
   8649 
   8650    ;; activation function or major-mode match.
   8651    (if-let* ((activation-fn (lsp--client-activation-fn client)))
   8652        (funcall activation-fn (buffer-file-name) major-mode)
   8653      (-contains? (lsp--client-major-modes client) major-mode))
   8654 
   8655    ;; check whether it is enabled if `lsp-enabled-clients' is not null
   8656    (or (null lsp-enabled-clients)
   8657        (or (member (lsp--client-server-id client) lsp-enabled-clients)
   8658            (ignore (lsp--info "Client %s is not in lsp-enabled-clients"
   8659                               (lsp--client-server-id client)))))
   8660 
   8661    ;; check whether it is not disabled.
   8662    (not (lsp--client-disabled-p major-mode (lsp--client-server-id client)))))
   8663 
   8664 (defun lsp--filter-clients (pred)
   8665   (->> lsp-clients hash-table-values (-filter pred)))
   8666 
   8667 (defun lsp--find-clients ()
   8668   "Find clients which can handle current buffer."
   8669   (-when-let (matching-clients (lsp--filter-clients (-andfn #'lsp--supports-buffer?
   8670                                                             #'lsp--server-binary-present?)))
   8671     (lsp-log "Found the following clients for %s: %s"
   8672              (buffer-file-name)
   8673              (s-join ", "
   8674                      (-map (lambda (client)
   8675                              (format "(server-id %s, priority %s)"
   8676                                      (lsp--client-server-id client)
   8677                                      (lsp--client-priority client)))
   8678                            matching-clients)))
   8679     (-let* (((add-on-clients main-clients) (-separate #'lsp--client-add-on? matching-clients))
   8680             (selected-clients (if-let* ((main-client (and main-clients
   8681                                                          (--max-by (> (lsp--client-priority it)
   8682                                                                       (lsp--client-priority other))
   8683                                                                    main-clients))))
   8684                                   (cons main-client add-on-clients)
   8685                                 add-on-clients)))
   8686       (lsp-log "The following clients were selected based on priority: %s"
   8687                (s-join ", "
   8688                        (-map (lambda (client)
   8689                                (format "(server-id %s, priority %s)"
   8690                                        (lsp--client-server-id client)
   8691                                        (lsp--client-priority client)))
   8692                              selected-clients)))
   8693       selected-clients)))
   8694 
   8695 (defun lsp-workspace-remove-all-folders()
   8696   "Delete all lsp tracked folders."
   8697   (interactive)
   8698   (--each (lsp-session-folders (lsp-session))
   8699     (lsp-workspace-folders-remove it)))
   8700 
   8701 (defun lsp-register-client (client)
   8702   "Registers LSP client CLIENT."
   8703   (let ((client-id (lsp--client-server-id client)))
   8704     (puthash client-id client lsp-clients)
   8705     (setplist (intern (format "lsp-%s-after-open-hook" client-id))
   8706               `( standard-value (nil) custom-type hook
   8707                  custom-package-version (lsp-mode . "7.0.1")
   8708                  variable-documentation ,(format "Hooks to run after `%s' server is run." client-id)
   8709                  custom-requests nil)))
   8710   (when (and lsp-auto-register-remote-clients
   8711              (not (lsp--client-remote? client)))
   8712     (let ((remote-client (copy-lsp--client client)))
   8713       (setf (lsp--client-remote? remote-client) t
   8714             (lsp--client-server-id remote-client) (intern
   8715                                                    (format "%s-tramp"
   8716                                                            (lsp--client-server-id client)))
   8717             ;; disable automatic download
   8718             (lsp--client-download-server-fn remote-client) nil)
   8719       (lsp-register-client remote-client))))
   8720 
   8721 (defun lsp--create-initialization-options (_session client)
   8722   "Create initialization-options from SESSION and CLIENT.
   8723 Add workspace folders depending on server being multiroot and
   8724 session workspace folder configuration for the server."
   8725   (let* ((initialization-options-or-fn (lsp--client-initialization-options client)))
   8726     (if (functionp initialization-options-or-fn)
   8727         (funcall initialization-options-or-fn)
   8728       initialization-options-or-fn)))
   8729 
   8730 (defvar lsp-client-settings (make-hash-table :test 'equal)
   8731   "For internal use, any external users please use
   8732   `lsp-register-custom-settings' function instead")
   8733 
   8734 (defun lsp-register-custom-settings (props)
   8735   "Register PROPS.
   8736 PROPS is list of triple (path value boolean?) where PATH is the path to the
   8737 property; VALUE can be a literal value, symbol to be evaluated, or either a
   8738 function or lambda function to be called without arguments; BOOLEAN? is an
   8739 optional flag that should be non-nil for boolean settings, when it is nil the
   8740 property will be ignored if the VALUE is nil.
   8741 
   8742 Example: `(lsp-register-custom-settings `((\"foo.bar.buzz.enabled\" t t)))'
   8743 \(note the double parentheses)"
   8744   (mapc
   8745    (-lambda ((path . rest))
   8746      (puthash path rest lsp-client-settings))
   8747    props))
   8748 
   8749 (defun lsp-region-text (region)
   8750   "Get the text for REGION in current buffer."
   8751   (-let (((start . end) (lsp--range-to-region region)))
   8752     (buffer-substring-no-properties start end)))
   8753 
   8754 (defun lsp-ht-set (tbl paths value)
   8755   "Set nested hash table value.
   8756 TBL - a hash table, PATHS is the path to the nested VALUE."
   8757   (pcase paths
   8758     (`(,path) (ht-set! tbl path value))
   8759     (`(,path . ,rst) (let ((nested-tbl (or (gethash path tbl)
   8760                                            (let ((temp-tbl (ht)))
   8761                                              (ht-set! tbl path temp-tbl)
   8762                                              temp-tbl))))
   8763                        (lsp-ht-set nested-tbl rst value)))))
   8764 
   8765 ;; sections
   8766 
   8767 (defalias 'defcustom-lsp 'lsp-defcustom)
   8768 
   8769 (defmacro lsp-defcustom (symbol standard doc &rest args)
   8770   "Defines `lsp-mode' server property."
   8771   (declare (doc-string 3) (debug (name body))
   8772            (indent defun))
   8773   (let ((path (plist-get args :lsp-path))
   8774         (setter (intern (concat (symbol-name symbol) "--set"))))
   8775     (cl-remf args :lsp-path)
   8776     `(progn
   8777        (lsp-register-custom-settings
   8778         (quote ((,path ,symbol ,(equal ''boolean (plist-get args :type))))))
   8779 
   8780        (defcustom ,symbol ,standard ,doc ,@args)
   8781 
   8782        ;; Use a variable watcher instead of registering a `defcustom'
   8783        ;; setter since `hack-local-variables' is not aware of custom
   8784        ;; setters and won't invoke them.
   8785 
   8786        (defun ,setter (sym val op _where)
   8787          (when (eq op 'set)
   8788            (lsp--set-custom-property sym val ,path)))
   8789 
   8790        (add-variable-watcher ',symbol #',setter))))
   8791 
   8792 (defun lsp--set-custom-property (sym val path)
   8793   (set sym val)
   8794   (let ((section (cl-first (s-split "\\." path))))
   8795     (mapc (lambda (workspace)
   8796             (when (-contains? (lsp--client-synchronize-sections (lsp--workspace-client workspace))
   8797                               section)
   8798               (with-lsp-workspace workspace
   8799                 (lsp--set-configuration (lsp-configuration-section section)))))
   8800           (lsp--session-workspaces (lsp-session)))))
   8801 
   8802 (defun lsp-configuration-section (section)
   8803   "Get settings for SECTION."
   8804   (let ((ret (ht-create)))
   8805     (maphash (-lambda (path (variable boolean?))
   8806                (when (s-matches? (concat (regexp-quote section) "\\..*") path)
   8807                  (let* ((symbol-value (-> variable
   8808                                           lsp-resolve-value
   8809                                           lsp-resolve-value))
   8810                         (value (if (and boolean? (not symbol-value))
   8811                                    :json-false
   8812                                  symbol-value)))
   8813                    (when (or boolean? value)
   8814                      (lsp-ht-set ret (s-split "\\." path) value)))))
   8815              lsp-client-settings)
   8816     ret))
   8817 
   8818 
   8819 (defun lsp--start-connection (session client project-root)
   8820   "Initiates connection created from CLIENT for PROJECT-ROOT.
   8821 SESSION is the active session."
   8822   (when (lsp--client-multi-root client)
   8823     (cl-pushnew project-root (gethash (lsp--client-server-id client)
   8824                                       (lsp-session-server-id->folders session))))
   8825   (run-hook-with-args 'lsp-workspace-folders-changed-functions (list project-root) nil)
   8826 
   8827   (unwind-protect
   8828       (lsp--start-workspace session client project-root (lsp--create-initialization-options session client))
   8829     (lsp--spinner-stop)))
   8830 
   8831 ;; lsp-log-io-mode
   8832 
   8833 (defvar lsp-log-io-mode-map
   8834   (let ((map (make-sparse-keymap)))
   8835     (define-key map (kbd "M-n") #'lsp-log-io-next)
   8836     (define-key map (kbd "M-p") #'lsp-log-io-prev)
   8837     (define-key map (kbd "k") #'lsp--erase-log-buffer)
   8838     (define-key map (kbd "K") #'lsp--erase-session-log-buffers)
   8839     map)
   8840   "Keymap for lsp log buffer mode.")
   8841 
   8842 (define-derived-mode lsp-log-io-mode special-mode "LspLogIo"
   8843   "Special mode for viewing IO logs.")
   8844 
   8845 (defun lsp-workspace-show-log (workspace)
   8846   "Display the log buffer of WORKSPACE."
   8847   (interactive
   8848    (list (if lsp-log-io
   8849              (if (eq (length (lsp-workspaces)) 1)
   8850                  (cl-first (lsp-workspaces))
   8851                (lsp--completing-read "Workspace: " (lsp-workspaces)
   8852                                      #'lsp--workspace-print nil t))
   8853            (user-error "IO logging is disabled"))))
   8854   (pop-to-buffer (lsp--get-log-buffer-create workspace)))
   8855 
   8856 (defalias 'lsp-switch-to-io-log-buffer 'lsp-workspace-show-log)
   8857 
   8858 (defun lsp--get-log-buffer-create (workspace)
   8859   "Return the lsp log buffer of WORKSPACE, creating a new one if needed."
   8860   (let* ((server-id (-> workspace lsp--workspace-client lsp--client-server-id symbol-name))
   8861          (pid (-> workspace lsp--workspace-cmd-proc lsp-process-id)))
   8862     (get-buffer-create (format "*lsp-log: %s:%s*" server-id pid))))
   8863 
   8864 (defun lsp--erase-log-buffer (&optional all)
   8865   "Delete contents of current lsp log buffer.
   8866 When ALL is t, erase all log buffers of the running session."
   8867   (interactive)
   8868   (let* ((workspaces (lsp--session-workspaces (lsp-session)))
   8869          (current-log-buffer (current-buffer)))
   8870     (dolist (w workspaces)
   8871       (let ((b (lsp--get-log-buffer-create w)))
   8872         (when (or all (eq b current-log-buffer))
   8873           (with-current-buffer b
   8874             (let ((inhibit-read-only t))
   8875               (erase-buffer))))))))
   8876 
   8877 (defun lsp--erase-session-log-buffers ()
   8878   "Erase log buffers of the running session."
   8879   (interactive)
   8880   (lsp--erase-log-buffer t))
   8881 
   8882 (defun lsp-log-io-next (arg)
   8883   "Move to next log entry."
   8884   (interactive "P")
   8885   (ewoc-goto-next lsp--log-io-ewoc (or arg 1)))
   8886 
   8887 (defun lsp-log-io-prev (arg)
   8888   "Move to previous log entry."
   8889   (interactive "P")
   8890   (ewoc-goto-prev lsp--log-io-ewoc (or arg 1)))
   8891 
   8892 
   8893 
   8894 (cl-defmethod lsp-process-id ((process process))
   8895   (process-id process))
   8896 
   8897 (cl-defmethod lsp-process-name ((process process)) (process-name process))
   8898 
   8899 (cl-defmethod lsp-process-status ((process process)) (process-status process))
   8900 
   8901 (cl-defmethod lsp-process-kill ((process process))
   8902   (when (process-live-p process)
   8903     (kill-process process)))
   8904 
   8905 (cl-defmethod lsp-process-send ((process process) message)
   8906   (condition-case err
   8907       (process-send-string process (lsp--make-message message))
   8908     (error (lsp--error "Sending to process failed with the following error: %s"
   8909                        (error-message-string err)))))
   8910 
   8911 (cl-defmethod lsp-process-cleanup (process)
   8912   ;; Kill standard error buffer only if the process exited normally.
   8913   ;; Leave it intact otherwise for debugging purposes.
   8914   (let ((buffer (-> process process-name get-buffer)))
   8915     (when (and (eq (process-status process) 'exit)
   8916                (zerop (process-exit-status process))
   8917                (buffer-live-p buffer))
   8918       (kill-buffer buffer))))
   8919 
   8920 
   8921 ;; native JSONRPC
   8922 
   8923 (declare-function json-rpc "ext:json")
   8924 (declare-function json-rpc-connection "ext:json")
   8925 (declare-function json-rpc-send "ext:json")
   8926 (declare-function json-rpc-shutdown "ext:json")
   8927 (declare-function json-rpc-stderr "ext:json")
   8928 (declare-function json-rpc-pid "ext:json")
   8929 
   8930 (defvar lsp-json-rpc-thread nil)
   8931 (defvar lsp-json-rpc-queue nil)
   8932 (defvar lsp-json-rpc-done nil)
   8933 (defvar lsp-json-rpc-mutex (make-mutex))
   8934 (defvar lsp-json-rpc-condition (make-condition-variable lsp-json-rpc-mutex))
   8935 
   8936 (defun lsp-json-rpc-process-queue ()
   8937   (while (not lsp-json-rpc-done)
   8938     (while lsp-json-rpc-queue
   8939       (-let (((proc . message) (pop lsp-json-rpc-queue)))
   8940         (json-rpc-send
   8941          proc message
   8942          :null-object nil
   8943          :false-object :json-false)))
   8944     (with-mutex lsp-json-rpc-mutex
   8945       (condition-wait lsp-json-rpc-condition))))
   8946 
   8947 (cl-defmethod lsp-process-id (process) (json-rpc-pid process))
   8948 
   8949 (cl-defmethod lsp-process-name (_process) "TBD")
   8950 
   8951 (cl-defmethod lsp-process-kill (process) (json-rpc-shutdown process))
   8952 
   8953 (cl-defmethod lsp-process-send (proc message)
   8954   (unless lsp-json-rpc-thread
   8955     (with-current-buffer (get-buffer-create " *json-rpc*")
   8956       (setq lsp-json-rpc-thread (make-thread #'lsp-json-rpc-process-queue "*json-rpc-queue*"))))
   8957 
   8958   (with-mutex lsp-json-rpc-mutex
   8959     (setq lsp-json-rpc-queue (append lsp-json-rpc-queue
   8960                                      (list (cons proc message))))
   8961     (condition-notify lsp-json-rpc-condition)))
   8962 
   8963 (cl-defmethod lsp-process-cleanup (_proc))
   8964 
   8965 (defun lsp-json-rpc-connection (workspace command)
   8966   (let ((con (apply #'json-rpc-connection command))
   8967         (object-type (if lsp-use-plists 'plist 'hash-table)))
   8968     (with-current-buffer (get-buffer-create " *json-rpc*")
   8969       (make-thread
   8970        (lambda ()
   8971          (json-rpc
   8972           con
   8973           (lambda (result err done)
   8974             (run-with-timer
   8975              0.0
   8976              nil
   8977              (lambda ()
   8978                (cond
   8979                 (result (lsp--parser-on-message result workspace))
   8980                 (err (warn "Json parsing failed with the following error: %s" err))
   8981                 (done (lsp--handle-process-exit workspace ""))))))
   8982           :object-type object-type
   8983           :null-object nil
   8984           :false-object nil))
   8985        "*json-rpc-connection*"))
   8986     (cons con con)))
   8987 
   8988 (defun lsp-json-rpc-stderr ()
   8989   (interactive)
   8990   (--when-let (pcase (lsp-workspaces)
   8991                 (`nil (user-error "There are no active servers in the current buffer"))
   8992                 (`(,workspace) workspace)
   8993                 (workspaces (lsp--completing-read "Select server: "
   8994                                                   workspaces
   8995                                                   'lsp--workspace-print nil t)))
   8996     (let ((content (json-rpc-stderr (lsp--workspace-cmd-proc it)))
   8997           (buffer (format "*stderr-%s*" (lsp--workspace-print it)) ))
   8998       (with-current-buffer (get-buffer-create buffer)
   8999         (with-help-window buffer
   9000           (insert content))))))
   9001 
   9002 
   9003 (defun lsp--workspace-print (workspace)
   9004   "Visual representation WORKSPACE."
   9005   (let* ((proc (lsp--workspace-cmd-proc workspace))
   9006          (status (lsp--workspace-status workspace))
   9007          (server-id (-> workspace lsp--workspace-client lsp--client-server-id symbol-name))
   9008          (pid (lsp-process-id proc)))
   9009 
   9010     (if (eq 'initialized status)
   9011         (format "%s:%s" server-id pid)
   9012       (format "%s:%s/%s" server-id pid status))))
   9013 
   9014 (defun lsp--map-tree-widget (m)
   9015   "Build `tree-widget' from a hash-table or plist M."
   9016   (when (lsp-structure-p m)
   9017     (let (nodes)
   9018       (lsp-map (lambda (k v)
   9019                  (push `(tree-widget
   9020                          :tag ,(if (lsp-structure-p v)
   9021                                    (format "%s:" k)
   9022                                  (format "%s: %s" k
   9023                                          (propertize (format "%s" v)
   9024                                                      'face
   9025                                                      'font-lock-string-face)))
   9026                          :open t
   9027                          ,@(lsp--map-tree-widget v))
   9028                        nodes))
   9029                m)
   9030       nodes)))
   9031 
   9032 (defun lsp-buffer-name (buffer-id)
   9033   (if-let* ((buffer-name (plist-get buffer-id :buffer-name)))
   9034       (funcall buffer-name buffer-id)
   9035     (buffer-name buffer-id)))
   9036 
   9037 (defun lsp--render-workspace (workspace)
   9038   "Tree node representation of WORKSPACE."
   9039   `(tree-widget :tag ,(lsp--workspace-print workspace)
   9040                 :open t
   9041                 (tree-widget :tag ,(propertize "Buffers" 'face 'font-lock-function-name-face)
   9042                              :open t
   9043                              ,@(->> workspace
   9044                                     (lsp--workspace-buffers)
   9045                                     (--map `(tree-widget
   9046                                              :tag ,(when (lsp-buffer-live-p it)
   9047                                                      (let ((buffer-name (lsp-buffer-name it)))
   9048                                                        (if (lsp-with-current-buffer it buffer-read-only)
   9049                                                            (propertize buffer-name 'face 'font-lock-constant-face)
   9050                                                          buffer-name)))))))
   9051                 (tree-widget :tag ,(propertize "Capabilities" 'face 'font-lock-function-name-face)
   9052                              ,@(-> workspace lsp--workspace-server-capabilities lsp--map-tree-widget))))
   9053 
   9054 (define-derived-mode lsp-browser-mode special-mode "LspBrowser"
   9055   "Define mode for displaying lsp sessions."
   9056   (setq-local display-buffer-base-action '(nil . ((inhibit-same-window . t)))))
   9057 
   9058 (defun lsp-describe-session ()
   9059   "Describes current `lsp-session'."
   9060   (interactive)
   9061   (let ((session (lsp-session))
   9062         (buf (get-buffer-create "*lsp session*"))
   9063         (root (lsp-workspace-root)))
   9064     (with-current-buffer buf
   9065       (lsp-browser-mode)
   9066       (let ((inhibit-read-only t))
   9067         (erase-buffer)
   9068         (--each (lsp-session-folders session)
   9069           (widget-create
   9070            `(tree-widget
   9071              :tag ,(propertize it 'face 'font-lock-keyword-face)
   9072              :open t
   9073              ,@(->> session
   9074                     (lsp-session-folder->servers)
   9075                     (gethash it)
   9076                     (-map 'lsp--render-workspace)))))))
   9077     (pop-to-buffer buf)
   9078     (goto-char (point-min))
   9079     (cl-loop for tag = (widget-get (widget-get (widget-at) :node) :tag)
   9080              until (or (and root (string= tag root)) (eobp))
   9081              do (goto-char (next-overlay-change (point))))))
   9082 
   9083 (defun lsp--session-workspaces (session)
   9084   "Get all workspaces that are part of the SESSION."
   9085   (-> session lsp-session-folder->servers hash-table-values -flatten -uniq))
   9086 
   9087 (defun lsp--find-multiroot-workspace (session client project-root)
   9088   "Look for a multiroot connection in SESSION created from CLIENT for
   9089 PROJECT-ROOT and BUFFER-MAJOR-MODE."
   9090   (when (lsp--client-multi-root client)
   9091     (-when-let (multi-root-workspace (->> session
   9092                                           (lsp--session-workspaces)
   9093                                           (--first (eq (-> it lsp--workspace-client lsp--client-server-id)
   9094                                                        (lsp--client-server-id client)))))
   9095       (with-lsp-workspace multi-root-workspace
   9096         (lsp-notify "workspace/didChangeWorkspaceFolders"
   9097                     (lsp-make-did-change-workspace-folders-params
   9098                      :event (lsp-make-workspace-folders-change-event
   9099                              :added (vector (lsp-make-workspace-folder
   9100                                              :uri (lsp--path-to-uri project-root)
   9101                                              :name (f-filename project-root)))
   9102                              :removed []))))
   9103 
   9104       (->> session (lsp-session-folder->servers) (gethash project-root) (cl-pushnew multi-root-workspace))
   9105       (->> session (lsp-session-server-id->folders) (gethash (lsp--client-server-id client)) (cl-pushnew project-root))
   9106 
   9107       (lsp--persist-session session)
   9108 
   9109       (lsp--info "Opened folder %s in workspace %s" project-root (lsp--workspace-print multi-root-workspace))
   9110       (lsp--open-in-workspace multi-root-workspace)
   9111 
   9112       multi-root-workspace)))
   9113 
   9114 (defun lsp--ensure-lsp-servers (session clients project-root ignore-multi-folder)
   9115   "Ensure that SESSION contain server CLIENTS created for PROJECT-ROOT.
   9116 IGNORE-MULTI-FOLDER to ignore multi folder server."
   9117   (-map (lambda (client)
   9118           (or
   9119            (lsp--find-workspace session client project-root)
   9120            (unless ignore-multi-folder
   9121              (lsp--find-multiroot-workspace session client project-root))
   9122            (lsp--start-connection session client project-root)))
   9123         clients))
   9124 
   9125 (defun lsp--spinner-stop ()
   9126   "Stop the spinner in case all of the workspaces are started."
   9127   (when (--all? (eq (lsp--workspace-status it) 'initialized)
   9128                 lsp--buffer-workspaces)
   9129     (spinner-stop)))
   9130 
   9131 (defun lsp--open-in-workspace (workspace)
   9132   "Open in existing WORKSPACE."
   9133   (if (eq 'initialized (lsp--workspace-status workspace))
   9134       ;; when workspace is initialized just call document did open.
   9135       (progn
   9136         (with-lsp-workspace workspace
   9137           (when-let* ((before-document-open-fn (-> workspace
   9138                                                   lsp--workspace-client
   9139                                                   lsp--client-before-file-open-fn)))
   9140             (funcall before-document-open-fn workspace))
   9141           (lsp--text-document-did-open))
   9142         (lsp--spinner-stop))
   9143     ;; when it is not initialized
   9144     (lsp--spinner-start)
   9145     (cl-pushnew (lsp-current-buffer) (lsp--workspace-buffers workspace))))
   9146 
   9147 (defun lsp--find-workspace (session client project-root)
   9148   "Find server connection created with CLIENT in SESSION for PROJECT-ROOT."
   9149   (when-let* ((workspace (->> session
   9150                              (lsp-session-folder->servers)
   9151                              (gethash project-root)
   9152                              (--first (eql (-> it lsp--workspace-client lsp--client-server-id)
   9153                                            (lsp--client-server-id client))))))
   9154     (lsp--open-in-workspace workspace)
   9155     workspace))
   9156 
   9157 (defun lsp--read-char (prompt &optional options)
   9158   "Wrapper for `read-char-from-minibuffer' if Emacs +27.
   9159 Fallback to `read-key' otherwise.
   9160 PROMPT is the message and OPTIONS the available options."
   9161   (if (fboundp 'read-char-from-minibuffer)
   9162       (read-char-from-minibuffer prompt options)
   9163     (read-key prompt)))
   9164 
   9165 (defun lsp--find-root-interactively (session)
   9166   "Find project interactively.
   9167 Returns nil if the project should not be added to the current SESSION."
   9168   (condition-case nil
   9169       (let* ((project-root-suggestion (or (lsp--suggest-project-root) default-directory))
   9170              (action (lsp--read-char
   9171                       (format
   9172                        "%s is not part of any project.
   9173 
   9174 %s ==> Import project root %s
   9175 %s ==> Import project by selecting root directory interactively
   9176 %s ==> Import project at current directory %s
   9177 %s ==> Do not ask again for the current project by adding %s to lsp-session-folders-blocklist
   9178 %s ==> Do not ask again for the current project by selecting ignore path interactively
   9179 %s ==> Do nothing: ask again when opening other files from the current project
   9180 
   9181 Select action: "
   9182                        (propertize (buffer-name) 'face 'bold)
   9183                        (propertize "i" 'face 'success)
   9184                        (propertize project-root-suggestion 'face 'bold)
   9185                        (propertize "I" 'face 'success)
   9186                        (propertize "." 'face 'success)
   9187                        (propertize default-directory 'face 'bold)
   9188                        (propertize "d" 'face 'warning)
   9189                        (propertize project-root-suggestion 'face 'bold)
   9190                        (propertize "D" 'face 'warning)
   9191                        (propertize "n" 'face 'warning))
   9192                       '(?i ?\r ?I ?. ?d ?D ?n))))
   9193         (cl-case action
   9194           (?i project-root-suggestion)
   9195           (?\r project-root-suggestion)
   9196           (?I (read-directory-name "Select workspace folder to add: "
   9197                                    (or project-root-suggestion default-directory)
   9198                                    nil
   9199                                    t))
   9200           (?. default-directory)
   9201           (?d (push project-root-suggestion (lsp-session-folders-blocklist session))
   9202               (lsp--persist-session session)
   9203               nil)
   9204           (?D (push (read-directory-name "Select folder to blocklist: "
   9205                                          (or project-root-suggestion default-directory)
   9206                                          nil
   9207                                          t)
   9208                     (lsp-session-folders-blocklist session))
   9209               (lsp--persist-session session)
   9210               nil)
   9211           (t nil)))
   9212     (quit)))
   9213 
   9214 (declare-function tramp-file-name-host "ext:tramp" (file) t)
   9215 (declare-function tramp-dissect-file-name "ext:tramp" (file &optional nodefault))
   9216 
   9217 (defun lsp--files-same-host (f1 f2)
   9218   "Predicate on whether or not two files are on the same host."
   9219   (or (not (or (file-remote-p f1) (file-remote-p f2)))
   9220       (and (file-remote-p f1)
   9221            (file-remote-p f2)
   9222            (progn (require 'tramp)
   9223                   (equal (tramp-file-name-host (tramp-dissect-file-name f1))
   9224                          (tramp-file-name-host (tramp-dissect-file-name f2)))))))
   9225 
   9226 (defun lsp-find-session-folder (session file-name)
   9227   "Look in the current SESSION for folder containing FILE-NAME."
   9228   (let ((file-name-canonical (lsp-f-canonical file-name)))
   9229     (->> session
   9230          (lsp-session-folders)
   9231          (--filter (and (lsp--files-same-host it file-name-canonical)
   9232                         (or (lsp-f-same? it file-name-canonical)
   9233                             (and (f-dir? it)
   9234                                  (lsp-f-ancestor-of? it file-name-canonical)))))
   9235          (--max-by (> (length it)
   9236                       (length other))))))
   9237 
   9238 (defun lsp-find-workspace (server-id &optional file-name)
   9239   "Find workspace for SERVER-ID for FILE-NAME."
   9240   (-when-let* ((session (lsp-session))
   9241                (folder->servers (lsp-session-folder->servers session))
   9242                (workspaces (if file-name
   9243                                (gethash (lsp-find-session-folder session file-name) folder->servers)
   9244                              (lsp--session-workspaces session))))
   9245 
   9246     (--first (eq (lsp--client-server-id (lsp--workspace-client it)) server-id) workspaces)))
   9247 
   9248 (defun lsp--calculate-root (session file-name)
   9249   "Calculate project root for FILE-NAME in SESSION."
   9250   (and
   9251    (->> session
   9252         (lsp-session-folders-blocklist)
   9253         (--first (and (lsp--files-same-host it file-name)
   9254                       (lsp-f-ancestor-of? it file-name)
   9255                       (prog1 t
   9256                         (lsp--info "File %s is in blocklisted directory %s" file-name it))))
   9257         not)
   9258    (or
   9259     (when lsp-auto-guess-root
   9260       (lsp--suggest-project-root))
   9261     (unless lsp-guess-root-without-session
   9262       (lsp-find-session-folder session file-name))
   9263     (unless lsp-auto-guess-root
   9264       (when-let* ((root-folder (lsp--find-root-interactively session)))
   9265         (if (or (not (f-equal? root-folder (expand-file-name "~/")))
   9266                 (yes-or-no-p
   9267                  (concat
   9268                   (propertize "[WARNING] " 'face 'warning)
   9269                   "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:
   9270 
   9271 1. Use `I' option from the interactive project import to select subfolder(e. g. `~/foo/bar' instead of `~/').
   9272 2. If your file is under `~/' then create a subfolder and move that file in this folder.
   9273 
   9274 Type `No' to go back to project selection.
   9275 Type `Yes' to confirm `HOME' as project root.
   9276 Type `C-g' to cancel project import process and stop `lsp'")))
   9277             root-folder
   9278           (lsp--calculate-root session file-name)))))))
   9279 
   9280 (defun lsp--try-open-in-library-workspace ()
   9281   "Try opening current file as library file in any of the active workspace.
   9282 The library folders are defined by each client for each of the active workspace."
   9283   (when-let* ((workspace (->> (lsp-session)
   9284                              (lsp--session-workspaces)
   9285                              ;; Sort the last active workspaces first as they are more likely to be
   9286                              ;; the correct ones, especially when jumping to a definition.
   9287                              (-sort (lambda (a _b)
   9288                                       (-contains? lsp--last-active-workspaces a)))
   9289                              (--first
   9290                               (and (-> it lsp--workspace-client lsp--supports-buffer?)
   9291                                    (when-let* ((library-folders-fn
   9292                                                (-> it lsp--workspace-client lsp--client-library-folders-fn)))
   9293                                      (-first (lambda (library-folder)
   9294                                                (lsp-f-ancestor-of? library-folder (buffer-file-name)))
   9295                                              (funcall library-folders-fn it))))))))
   9296     (lsp--open-in-workspace workspace)
   9297     (view-mode t)
   9298     (lsp--info "Opening read-only library file %s." (buffer-file-name))
   9299     (list workspace)))
   9300 
   9301 (defun lsp--persist-session (session)
   9302   "Persist SESSION to `lsp-session-file'."
   9303   (lsp--persist lsp-session-file (make-lsp-session
   9304                                   :folders (lsp-session-folders session)
   9305                                   :folders-blocklist (lsp-session-folders-blocklist session)
   9306                                   :server-id->folders (lsp-session-server-id->folders session))))
   9307 
   9308 (defun lsp--try-project-root-workspaces (ask-for-client ignore-multi-folder)
   9309   "Try create opening file as a project file.
   9310 When IGNORE-MULTI-FOLDER is t the lsp mode will start new
   9311 language server even if there is language server which can handle
   9312 current language. When IGNORE-MULTI-FOLDER is nil current file
   9313 will be opened in multi folder language server if there is
   9314 such."
   9315   (-let ((session (lsp-session)))
   9316     (-if-let (clients (if ask-for-client
   9317                           (list (lsp--completing-read "Select server to start: "
   9318                                                       (ht-values lsp-clients)
   9319                                                       (-compose 'symbol-name 'lsp--client-server-id) nil t))
   9320                         (lsp--find-clients)))
   9321         (-if-let (project-root (-some-> session
   9322                                  (lsp--calculate-root (buffer-file-name))
   9323                                  (lsp-f-canonical)))
   9324             (progn
   9325               ;; update project roots if needed and persist the lsp session
   9326               (unless (-contains? (lsp-session-folders session) project-root)
   9327                 (cl-pushnew project-root (lsp-session-folders session))
   9328                 (lsp--persist-session session))
   9329               (lsp--ensure-lsp-servers session clients project-root ignore-multi-folder))
   9330           (lsp--warn "%s not in project or it is blocklisted." (buffer-name))
   9331           nil)
   9332       (lsp--warn "No LSP server for %s(check *lsp-log*)." major-mode)
   9333       nil)))
   9334 
   9335 (defun lsp-shutdown-workspace ()
   9336   "Shutdown language server."
   9337   (interactive)
   9338   (--when-let (pcase (lsp-workspaces)
   9339                 (`nil (user-error "There are no active servers in the current buffer"))
   9340                 (`(,workspace) (when (y-or-n-p (format "Are you sure you want to stop the server %s?"
   9341                                                        (lsp--workspace-print workspace)))
   9342                                  workspace))
   9343                 (workspaces (lsp--completing-read "Select server: "
   9344                                                   workspaces
   9345                                                   'lsp--workspace-print nil t)))
   9346     (lsp-workspace-shutdown it)))
   9347 
   9348 (make-obsolete 'lsp-shutdown-workspace 'lsp-workspace-shutdown "lsp-mode 6.1")
   9349 
   9350 (defcustom lsp-auto-select-workspace t
   9351   "Shutdown or restart a single workspace.
   9352 If set and the current buffer has only a single workspace
   9353 associated with it, `lsp-shutdown-workspace' and
   9354 `lsp-restart-workspace' will act on it without asking."
   9355   :type 'boolean
   9356   :group 'lsp-mode)
   9357 
   9358 (defun lsp--read-workspace ()
   9359   "Ask the user to select a workspace.
   9360 Errors if there are none."
   9361   (pcase (lsp-workspaces)
   9362     (`nil (error "No workspaces associated with the current buffer"))
   9363     ((and `(,workspace) (guard lsp-auto-select-workspace)) workspace)
   9364     (workspaces (lsp--completing-read "Select workspace: " workspaces
   9365                                       #'lsp--workspace-print nil t))))
   9366 
   9367 (defun lsp-workspace-shutdown (workspace)
   9368   "Shut the workspace WORKSPACE and the language server associated with it"
   9369   (interactive (list (lsp--read-workspace)))
   9370   (lsp--warn "Stopping %s" (lsp--workspace-print workspace))
   9371   (with-lsp-workspace workspace (lsp--shutdown-workspace)))
   9372 
   9373 (defun lsp-disconnect ()
   9374   "Disconnect the buffer from the language server."
   9375   (interactive)
   9376   (lsp--text-document-did-close t)
   9377   (lsp-managed-mode -1)
   9378   (lsp-mode -1)
   9379   (setq lsp--buffer-workspaces nil)
   9380   (lsp--info "Disconnected"))
   9381 
   9382 (defun lsp-restart-workspace ()
   9383   (interactive)
   9384   (--when-let (pcase (lsp-workspaces)
   9385                 (`nil (user-error "There are no active servers in the current buffer"))
   9386                 (`(,workspace) workspace)
   9387                 (workspaces (lsp--completing-read "Select server: "
   9388                                                   workspaces
   9389                                                   'lsp--workspace-print nil t)))
   9390     (lsp-workspace-restart it)))
   9391 
   9392 (make-obsolete 'lsp-restart-workspace 'lsp-workspace-restart "lsp-mode 6.1")
   9393 
   9394 (defun lsp-workspace-restart (workspace)
   9395   "Restart the workspace WORKSPACE and the language server associated with it"
   9396   (interactive (list (lsp--read-workspace)))
   9397   (lsp--warn "Restarting %s" (lsp--workspace-print workspace))
   9398   (with-lsp-workspace workspace (lsp--shutdown-workspace t)))
   9399 
   9400 ;;;###autoload
   9401 (defun lsp (&optional arg)
   9402   "Entry point for the server startup.
   9403 When ARG is t the lsp mode will start new language server even if
   9404 there is language server which can handle current language. When
   9405 ARG is nil current file will be opened in multi folder language
   9406 server if there is such. When `lsp' is called with prefix
   9407 argument ask the user to select which language server to start."
   9408   (interactive "P")
   9409 
   9410   (lsp--require-packages)
   9411 
   9412   (when (buffer-file-name)
   9413     (let (clients
   9414           (matching-clients (lsp--filter-clients
   9415                              (-andfn #'lsp--supports-buffer?
   9416                                      #'lsp--server-binary-present?))))
   9417       (cond
   9418        (matching-clients
   9419         (when (setq lsp--buffer-workspaces
   9420                     (or (and
   9421                          ;; Don't open as library file if file is part of a project.
   9422                          (not (lsp-find-session-folder (lsp-session) (buffer-file-name)))
   9423                          (lsp--try-open-in-library-workspace))
   9424                         (lsp--try-project-root-workspaces (equal arg '(4))
   9425                                                           (and arg (not (equal arg 1))))))
   9426           (lsp-mode 1)
   9427           (when lsp-auto-configure (lsp--auto-configure))
   9428           (setq lsp-buffer-uri (lsp--buffer-uri))
   9429           (lsp--info "Connected to %s."
   9430                      (apply 'concat (--map (format "[%s %s]"
   9431                                                    (lsp--workspace-print it)
   9432                                                    (lsp--workspace-root it))
   9433                                            lsp--buffer-workspaces)))))
   9434        ;; look for servers which are currently being downloaded.
   9435        ((setq clients (lsp--filter-clients (-andfn #'lsp--supports-buffer?
   9436                                                    #'lsp--client-download-in-progress?)))
   9437         (lsp--info "There are language server(%s) installation in progress.
   9438 The server(s) will be started in the buffer when it has finished."
   9439                    (-map #'lsp--client-server-id clients))
   9440         (seq-do (lambda (client)
   9441                   (cl-pushnew (current-buffer) (lsp--client-buffers client)))
   9442                 clients))
   9443        ;; look for servers to install
   9444        ((setq clients (lsp--filter-clients
   9445                        (-andfn #'lsp--supports-buffer?
   9446                                (-const lsp-enable-suggest-server-download)
   9447                                #'lsp--client-download-server-fn
   9448                                (-not #'lsp--client-download-in-progress?))))
   9449         (let ((client (lsp--completing-read
   9450                        (concat "Unable to find installed server supporting this file. "
   9451                                "The following servers could be installed automatically: ")
   9452                        clients
   9453                        (-compose #'symbol-name #'lsp--client-server-id)
   9454                        nil
   9455                        t)))
   9456           (cl-pushnew (current-buffer) (lsp--client-buffers client))
   9457           (lsp--install-server-internal client)))
   9458        ;; ignore other warnings
   9459        ((not lsp-warn-no-matched-clients)
   9460         nil)
   9461        ;; automatic installation disabled
   9462        ((setq clients (unless matching-clients
   9463                         (lsp--filter-clients (-andfn #'lsp--supports-buffer?
   9464                                                      #'lsp--client-download-server-fn
   9465                                                      (-not (-const lsp-enable-suggest-server-download))
   9466                                                      (-not #'lsp--server-binary-present?)))))
   9467         (lsp--warn "The following servers support current file but automatic download is disabled: %s
   9468 \(If you have already installed the server check *lsp-log*)."
   9469                    (mapconcat (lambda (client)
   9470                                 (symbol-name (lsp--client-server-id client)))
   9471                               clients
   9472                               " ")))
   9473        ;; no clients present
   9474        ((setq clients (unless matching-clients
   9475                         (lsp--filter-clients (-andfn #'lsp--supports-buffer?
   9476                                                      (-not #'lsp--server-binary-present?)))))
   9477         (lsp--warn "The following servers support current file but do not have automatic installation: %s
   9478 You may find the installation instructions at https://emacs-lsp.github.io/lsp-mode/page/languages.
   9479 \(If you have already installed the server check *lsp-log*)."
   9480                    (mapconcat (lambda (client)
   9481                                 (symbol-name (lsp--client-server-id client)))
   9482                               clients
   9483                               " ")))
   9484        ;; no matches
   9485        ((-> #'lsp--supports-buffer? lsp--filter-clients not)
   9486         (lsp--error "There are no language servers supporting current mode `%s' registered with `lsp-mode'.
   9487 This issue might be caused by:
   9488 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'.
   9489 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'.
   9490 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/ .
   9491 4. You are over `tramp'. In this case follow https://emacs-lsp.github.io/lsp-mode/page/remote/.
   9492 5. You have disabled the `lsp-mode' clients for that file. (Check `lsp-enabled-clients' and `lsp-disabled-clients').
   9493 You can customize `lsp-warn-no-matched-clients' to disable this message."
   9494                     major-mode major-mode major-mode))))))
   9495 
   9496 (defun lsp--buffer-visible-p ()
   9497   "Return non nil if current buffer is visible."
   9498   (or (buffer-modified-p) (get-buffer-window nil t)))
   9499 
   9500 (defun lsp--init-if-visible ()
   9501   "Run `lsp' for the current buffer if the buffer is visible.
   9502 Returns non nil if `lsp' was run for the buffer."
   9503   (when (lsp--buffer-visible-p)
   9504     (remove-hook 'window-configuration-change-hook #'lsp--init-if-visible t)
   9505     (lsp)
   9506     t))
   9507 
   9508 ;;;###autoload
   9509 (defun lsp-deferred ()
   9510   "Entry point that defers server startup until buffer is visible.
   9511 `lsp-deferred' will wait until the buffer is visible before invoking `lsp'.
   9512 This avoids overloading the server with many files when starting Emacs."
   9513   ;; Workspace may not be initialized yet. Use a buffer local variable to
   9514   ;; remember that we deferred loading of this buffer.
   9515   (setq lsp--buffer-deferred t)
   9516   (let ((buffer (current-buffer)))
   9517     ;; Avoid false positives as desktop-mode restores buffers by deferring
   9518     ;; visibility check until the stack clears.
   9519     (run-with-idle-timer 0 nil (lambda ()
   9520                                  (when (buffer-live-p buffer)
   9521                                    (with-current-buffer buffer
   9522                                      (unless (lsp--init-if-visible)
   9523                                        (add-hook 'window-configuration-change-hook #'lsp--init-if-visible nil t))))))))
   9524 
   9525 
   9526 
   9527 (defvar lsp-file-truename-cache (ht))
   9528 
   9529 (defmacro lsp-with-cached-filetrue-name (&rest body)
   9530   "Executes BODY caching the `file-truename' calls."
   9531   `(let ((old-fn (symbol-function 'file-truename)))
   9532      (unwind-protect
   9533          (progn
   9534            (fset 'file-truename
   9535                  (lambda (file-name &optional counter prev-dirs)
   9536                    (or (gethash file-name lsp-file-truename-cache)
   9537                        (puthash file-name (apply old-fn (list file-name counter prev-dirs))
   9538                                 lsp-file-truename-cache))))
   9539            ,@body)
   9540        (fset 'file-truename old-fn))))
   9541 
   9542 
   9543 (defun lsp-virtual-buffer-call (key &rest args)
   9544   (when lsp--virtual-buffer
   9545     (when-let* ((fn (plist-get lsp--virtual-buffer key)))
   9546       (apply fn args))))
   9547 
   9548 (defun lsp-translate-column (column)
   9549   "Translate COLUMN taking into account virtual buffers."
   9550   (or (lsp-virtual-buffer-call :real->virtual-char column)
   9551       column))
   9552 
   9553 (defun lsp-translate-line (line)
   9554   "Translate LINE taking into account virtual buffers."
   9555   (or (lsp-virtual-buffer-call :real->virtual-line line)
   9556       line))
   9557 
   9558 
   9559 ;; lsp internal validation.
   9560 
   9561 (defmacro lsp--doctor (&rest checks)
   9562   `(-let [buf (current-buffer)]
   9563      (with-current-buffer (get-buffer-create "*lsp-performance*")
   9564        (with-help-window (current-buffer)
   9565          ,@(-map (-lambda ((msg form))
   9566                    `(insert (format "%s: %s\n" ,msg
   9567                                     (let ((res (with-current-buffer buf
   9568                                                  ,form)))
   9569                                       (cond
   9570                                        ((eq res :optional) (propertize "OPTIONAL" 'face 'warning))
   9571                                        (res (propertize "OK" 'face 'success))
   9572                                        (t (propertize "ERROR" 'face 'error)))))))
   9573                  (-partition 2 checks))))))
   9574 
   9575 (define-obsolete-function-alias 'lsp-diagnose
   9576   'lsp-doctor "lsp-mode 8.0.0")
   9577 
   9578 (defun lsp-doctor ()
   9579   "Validate performance settings."
   9580   (interactive)
   9581   (lsp--doctor
   9582    "Checking for Native JSON support" (functionp 'json-serialize)
   9583    "Check emacs supports `read-process-output-max'" (boundp 'read-process-output-max)
   9584    "Check `read-process-output-max' default has been changed from 4k"
   9585    (and (boundp 'read-process-output-max)
   9586         (> read-process-output-max 4096))
   9587    "Byte compiled against Native JSON (recompile lsp-mode if failing when Native JSON available)"
   9588    (condition-case _err
   9589        (progn (lsp--make-message (list "a" "b"))
   9590               nil)
   9591      (error t))
   9592    "`gc-cons-threshold' increased?" (> gc-cons-threshold 800000)
   9593    "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)
   9594    "Using emacs 28+ with native compilation?"
   9595    (or (and (fboundp 'native-comp-available-p)
   9596             (native-comp-available-p))
   9597        :optional)))
   9598 
   9599 (declare-function package-version-join "ext:package")
   9600 (declare-function package-desc-version "ext:package")
   9601 (declare-function package--alist "ext:package")
   9602 
   9603 (defun lsp-version ()
   9604   "Return string describing current version of `lsp-mode'."
   9605   (interactive)
   9606   (unless (featurep 'package)
   9607     (require 'package))
   9608   (let ((ver (format "lsp-mode %s, Emacs %s, %s"
   9609                      (package-version-join
   9610                       (package-desc-version
   9611                        (car (alist-get 'lsp-mode (package--alist)))))
   9612                      emacs-version
   9613                      system-type)))
   9614     (if (called-interactively-p 'interactive)
   9615         (lsp--info "%s" ver)
   9616       ver)))
   9617 
   9618 
   9619 
   9620 ;; org-mode/virtual-buffer
   9621 
   9622 (declare-function org-babel-get-src-block-info "ext:ob-core")
   9623 (declare-function org-do-remove-indentation "ext:org-macs")
   9624 (declare-function org-src-get-lang-mode "ext:org-src")
   9625 (declare-function org-element-context "ext:org-element")
   9626 
   9627 (defun lsp--virtual-buffer-update-position ()
   9628   (-if-let (virtual-buffer (-first (-lambda ((&plist :in-range))
   9629                                      (funcall in-range))
   9630                                    lsp--virtual-buffer-connections))
   9631       (unless (equal virtual-buffer lsp--virtual-buffer)
   9632         (lsp-org))
   9633     (when lsp-managed-mode
   9634       (lsp-managed-mode -1)
   9635       (lsp-mode -1)
   9636       (setq lsp--buffer-workspaces nil)
   9637       (setq lsp--virtual-buffer nil)
   9638       (setq lsp-buffer-uri nil)
   9639 
   9640       ;; force refresh of diagnostics
   9641       (run-hooks 'lsp-after-diagnostics-hook))))
   9642 
   9643 (defun lsp-virtual-buffer-on-change (start end length)
   9644   "Adjust on change event to be executed against the proper language server."
   9645   (let ((max-point (max end
   9646                         (or (plist-get lsp--before-change-vals :end) 0)
   9647                         (+ start length))))
   9648     (when-let* ((virtual-buffer (-first (lambda (vb)
   9649                                          (let ((lsp--virtual-buffer vb))
   9650                                            (and (lsp-virtual-buffer-call :in-range start)
   9651                                                 (lsp-virtual-buffer-call :in-range max-point))))
   9652                                        lsp--virtual-buffer-connections)))
   9653       (lsp-with-current-buffer virtual-buffer
   9654         (lsp-on-change start end length
   9655                        (lambda (&rest _)
   9656                          (list :range (lsp--range (list :character 0 :line 0)
   9657                                                   lsp--virtual-buffer-point-max)
   9658                                :text (lsp--buffer-content))))))))
   9659 
   9660 (defun lsp-virtual-buffer-before-change (start _end)
   9661   (when-let* ((virtual-buffer (-first (lambda (vb)
   9662                                        (lsp-with-current-buffer vb
   9663                                          (lsp-virtual-buffer-call :in-range start)))
   9664                                      lsp--virtual-buffer-connections)))
   9665     (lsp-with-current-buffer virtual-buffer
   9666       (setq lsp--virtual-buffer-point-max
   9667             (lsp--point-to-position (lsp-virtual-buffer-call :last-point))))))
   9668 
   9669 (defun lsp-patch-on-change-event ()
   9670   (remove-hook 'after-change-functions #'lsp-on-change t)
   9671   (add-hook 'after-change-functions #'lsp-virtual-buffer-on-change nil t)
   9672   (add-hook 'before-change-functions #'lsp-virtual-buffer-before-change nil t))
   9673 
   9674 (defun lsp-kill-virtual-buffers ()
   9675   (mapc #'lsp-virtual-buffer-disconnect lsp--virtual-buffer-connections))
   9676 
   9677 (defun lsp--move-point-in-indentation (point indentation)
   9678   (save-excursion
   9679     (goto-char point)
   9680     (if (<= point (+ (line-beginning-position) indentation))
   9681         (line-beginning-position)
   9682       point)))
   9683 
   9684 (declare-function flycheck-checker-supports-major-mode-p "ext:flycheck")
   9685 (declare-function flycheck-add-mode "ext:flycheck")
   9686 (declare-function lsp-diagnostics-lsp-checker-if-needed "lsp-diagnostics")
   9687 
   9688 (defalias 'lsp-client-download-server-fn 'lsp--client-download-server-fn)
   9689 
   9690 (defun lsp-flycheck-add-mode (mode)
   9691   "Register flycheck support for MODE."
   9692   (lsp-diagnostics-lsp-checker-if-needed)
   9693   (unless (flycheck-checker-supports-major-mode-p 'lsp mode)
   9694     (flycheck-add-mode 'lsp mode)))
   9695 
   9696 (defun lsp-progress-spinner-type ()
   9697   "Retrieve the spinner type value, if value is not a symbol of `spinner-types
   9698 defaults to `progress-bar."
   9699   (or (car (assoc lsp-progress-spinner-type spinner-types)) 'progress-bar))
   9700 
   9701 (defun lsp-org ()
   9702   (interactive)
   9703   (-if-let ((virtual-buffer &as &plist :workspaces) (-first (-lambda ((&plist :in-range))
   9704                                                               (funcall in-range))
   9705                                                             lsp--virtual-buffer-connections))
   9706       (unless (equal lsp--virtual-buffer virtual-buffer)
   9707         (setq lsp--buffer-workspaces workspaces)
   9708         (setq lsp--virtual-buffer virtual-buffer)
   9709         (setq lsp-buffer-uri nil)
   9710         (lsp-mode 1)
   9711         (lsp-managed-mode 1)
   9712         (lsp-patch-on-change-event))
   9713 
   9714     (save-excursion
   9715       (-let* (virtual-buffer
   9716               (wcb (lambda (f)
   9717                      (with-current-buffer (plist-get virtual-buffer :buffer)
   9718                        (-let* (((&plist :major-mode :buffer-file-name
   9719                                         :goto-buffer :workspaces) virtual-buffer)
   9720                                (lsp--virtual-buffer virtual-buffer)
   9721                                (lsp--buffer-workspaces workspaces))
   9722                          (save-excursion
   9723                            (funcall goto-buffer)
   9724                            (funcall f))))))
   9725               ((&plist :begin :end :post-blank :language) (cl-second (org-element-context)))
   9726               ((&alist :tangle file-name) (cl-third (org-babel-get-src-block-info 'light)))
   9727 
   9728               (file-name (if file-name
   9729                              (f-expand file-name)
   9730                            (user-error "You should specify file name in the src block header.")))
   9731               (begin-marker (progn
   9732                               (goto-char begin)
   9733                               (forward-line)
   9734                               (set-marker (make-marker) (point))))
   9735               (end-marker (progn
   9736                             (goto-char end)
   9737                             (forward-line (1- (- post-blank)))
   9738                             (set-marker (make-marker) (1+ (point)))))
   9739               (buf (current-buffer))
   9740               (src-block (buffer-substring-no-properties begin-marker
   9741                                                          (1- end-marker)))
   9742               (indentation (with-temp-buffer
   9743                              (insert src-block)
   9744 
   9745                              (goto-char (point-min))
   9746                              (let ((indentation (current-indentation)))
   9747                                (plist-put lsp--virtual-buffer :indentation indentation)
   9748                                (org-do-remove-indentation)
   9749                                (goto-char (point-min))
   9750                                (- indentation (current-indentation))))))
   9751         (add-hook 'post-command-hook #'lsp--virtual-buffer-update-position nil t)
   9752 
   9753         (when (fboundp 'flycheck-add-mode)
   9754           (lsp-flycheck-add-mode 'org-mode))
   9755 
   9756         (setq lsp--virtual-buffer
   9757               (list
   9758                :in-range (lambda (&optional point)
   9759                            (<= begin-marker (or point (point)) (1- end-marker)))
   9760                :goto-buffer (lambda () (goto-char begin-marker))
   9761                :buffer-string
   9762                (lambda ()
   9763                  (let ((src-block (buffer-substring-no-properties
   9764                                    begin-marker
   9765                                    (1- end-marker))))
   9766                    (with-temp-buffer
   9767                      (insert src-block)
   9768 
   9769                      (goto-char (point-min))
   9770                      (while (not (eobp))
   9771                        (delete-region (point) (if (> (+ (point) indentation) (line-end-position))
   9772                                                   (line-end-position)
   9773                                                 (+ (point) indentation)))
   9774                        (forward-line))
   9775                      (buffer-substring-no-properties (point-min)
   9776                                                      (point-max)))))
   9777                :buffer buf
   9778                :begin begin-marker
   9779                :end end-marker
   9780                :indentation indentation
   9781                :last-point (lambda () (1- end-marker))
   9782                :cur-position (lambda ()
   9783                                (lsp-save-restriction-and-excursion
   9784                                  (list :line (- (lsp--cur-line)
   9785                                                 (lsp--cur-line begin-marker))
   9786                                        :character (let ((character (- (point)
   9787                                                                       (line-beginning-position)
   9788                                                                       indentation)))
   9789                                                     (if (< character 0)
   9790                                                         0
   9791                                                       character)))))
   9792                :line/character->point (-lambda (line character)
   9793                                         (-let [inhibit-field-text-motion t]
   9794                                           (+ indentation
   9795                                              (lsp-save-restriction-and-excursion
   9796                                                (goto-char begin-marker)
   9797                                                (forward-line line)
   9798                                                (-let [line-end (line-end-position)]
   9799                                                  (if (> character (- line-end (point)))
   9800                                                      line-end
   9801                                                    (forward-char character)
   9802                                                    (point)))))))
   9803                :major-mode (org-src-get-lang-mode language)
   9804                :buffer-file-name file-name
   9805                :buffer-uri (lsp--path-to-uri file-name)
   9806                :with-current-buffer wcb
   9807                :buffer-live? (lambda (_) (buffer-live-p buf))
   9808                :buffer-name (lambda (_)
   9809                               (propertize (format "%s(%s:%s)%s"
   9810                                                   (buffer-name buf)
   9811                                                   begin-marker
   9812                                                   end-marker
   9813                                                   language)
   9814                                           'face 'italic))
   9815                :real->virtual-line (lambda (line)
   9816                                      (+ line (line-number-at-pos begin-marker) -1))
   9817                :real->virtual-char (lambda (char) (+ char indentation))
   9818                :cleanup (lambda ()
   9819                           (set-marker begin-marker nil)
   9820                           (set-marker end-marker nil))))
   9821         (setf virtual-buffer lsp--virtual-buffer)
   9822         (puthash file-name virtual-buffer lsp--virtual-buffer-mappings)
   9823         (push virtual-buffer lsp--virtual-buffer-connections)
   9824 
   9825         ;; TODO: tangle only connected sections
   9826         (add-hook 'after-save-hook 'org-babel-tangle nil t)
   9827         (add-hook 'lsp-after-open-hook #'lsp-patch-on-change-event nil t)
   9828         (add-hook 'kill-buffer-hook #'lsp-kill-virtual-buffers nil t)
   9829 
   9830         (setq lsp--buffer-workspaces
   9831               (lsp-with-current-buffer virtual-buffer
   9832                 (lsp)
   9833                 (plist-put virtual-buffer :workspaces (lsp-workspaces))
   9834                 (lsp-workspaces)))))))
   9835 
   9836 (defun lsp-virtual-buffer-disconnect (virtual-buffer)
   9837   (interactive (list (or
   9838                       lsp--virtual-buffer
   9839                       (when lsp--virtual-buffer-connections
   9840                         (lsp--completing-read "Select virtual buffer to disconnect: "
   9841                                               lsp--virtual-buffer-connections
   9842                                               (-lambda ((&plist :buffer-file-name))
   9843                                                 buffer-file-name))))))
   9844   (-if-let ((&plist :buffer-file-name file-name :cleanup) virtual-buffer)
   9845       (progn
   9846         (lsp-with-current-buffer virtual-buffer
   9847           (lsp--text-document-did-close))
   9848         (setq lsp--virtual-buffer-connections (-remove-item virtual-buffer lsp--virtual-buffer-connections))
   9849         (when (eq virtual-buffer lsp--virtual-buffer)
   9850           (setf lsp--virtual-buffer nil))
   9851         (when cleanup (funcall cleanup))
   9852         (remhash file-name lsp--virtual-buffer-mappings)
   9853 
   9854         (lsp--virtual-buffer-update-position)
   9855         (lsp--info "Disconnected from buffer %s" file-name))
   9856     (lsp--error "Nothing to disconnect from?")))
   9857 
   9858 
   9859 ;; inlay hints
   9860 
   9861 (defface lsp-inlay-hint-face
   9862   '((t :inherit font-lock-comment-face))
   9863   "The face to use for the JavaScript inlays."
   9864   :group 'lsp-mode
   9865   :package-version '(lsp-mode . "9.0.0"))
   9866 
   9867 (defface lsp-inlay-hint-type-face
   9868   '((t :inherit lsp-inlay-hint-face))
   9869   "Face for inlay type hints (e.g. inferred variable types)."
   9870   :group 'lsp-mode
   9871   :package-version '(lsp-mode . "9.0.0"))
   9872 
   9873 (defcustom lsp-inlay-hint-type-format "%s"
   9874   "Format string for variable inlays (part of the inlay face)."
   9875   :type '(string :tag "String")
   9876   :group 'lsp-mode
   9877   :package-version '(lsp-mode . "9.0.0"))
   9878 
   9879 (defface lsp-inlay-hint-parameter-face
   9880   '((t :inherit lsp-inlay-hint-face))
   9881   "Face for inlay parameter hints (e.g. function parameter names at
   9882 call-site)."
   9883   :group 'lsp-mode
   9884   :package-version '(lsp-mode . "9.0.0"))
   9885 
   9886 (defcustom lsp-inlay-hint-param-format "%s"
   9887   "Format string for parameter inlays (part of the inlay face)."
   9888   :type '(string :tag "String")
   9889   :group 'lsp-mode
   9890   :package-version '(lsp-mode . "9.0.0"))
   9891 
   9892 (defcustom lsp-update-inlay-hints-on-scroll t
   9893   "If non-nil update inlay hints immediately when scrolling or
   9894 modifying window sizes."
   9895   :type 'boolean
   9896   :package-version '(lsp-mode . "9.0.0"))
   9897 
   9898 (defun lsp--format-inlay (text kind)
   9899   (cond
   9900    ((eql kind lsp/inlay-hint-kind-type-hint) (format lsp-inlay-hint-type-format text))
   9901    ((eql kind lsp/inlay-hint-kind-parameter-hint) (format lsp-inlay-hint-param-format text))
   9902    (t text)))
   9903 
   9904 (defun lsp--face-for-inlay (kind)
   9905   (cond
   9906    ((eql kind lsp/inlay-hint-kind-type-hint) 'lsp-inlay-hint-type-face)
   9907    ((eql kind lsp/inlay-hint-kind-parameter-hint) 'lsp-inlay-hint-parameter-face)
   9908    (t 'lsp-inlay-hint-face)))
   9909 
   9910 (defun lsp--update-inlay-hints-scroll-function (window start)
   9911   (lsp-update-inlay-hints start (window-end window t)))
   9912 
   9913 (defun lsp--update-inlay-hints ()
   9914   (lsp-update-inlay-hints (window-start) (window-end nil t)))
   9915 
   9916 (defun lsp--label-from-inlay-hints-response (label)
   9917   "Returns a string label built from an array of
   9918 InlayHintLabelParts or the argument itself if it's already a
   9919 string."
   9920   (cl-typecase label
   9921     (string label)
   9922     (vector
   9923      (string-join (mapcar (lambda (part)
   9924                             (-let (((&InlayHintLabelPart :value) part))
   9925                               value))
   9926                           label)))))
   9927 
   9928 (defun lsp-update-inlay-hints (start end)
   9929   (lsp-request-async
   9930    "textDocument/inlayHint"
   9931    (lsp-make-inlay-hints-params
   9932     :text-document (lsp--text-document-identifier)
   9933     :range (lsp-make-range :start
   9934                            (lsp-point-to-position start)
   9935                            :end
   9936                            (lsp-point-to-position end)))
   9937    (lambda (res)
   9938      (lsp--remove-overlays 'lsp-inlay-hint)
   9939      (dolist (hint res)
   9940        (-let* (((&InlayHint :label :position :kind? :padding-left? :padding-right?) hint)
   9941                (kind (or kind? lsp/inlay-hint-kind-type-hint))
   9942                (label (lsp--label-from-inlay-hints-response label))
   9943                (pos (lsp--position-to-point position))
   9944                (overlay (make-overlay pos pos nil 'front-advance 'end-advance)))
   9945          (when (stringp label)
   9946            (overlay-put overlay 'lsp-inlay-hint t)
   9947            (overlay-put overlay 'before-string
   9948                         (format "%s%s%s"
   9949                                 (if padding-left? " " "")
   9950                                 (propertize (lsp--format-inlay label kind)
   9951                                             'font-lock-face (lsp--face-for-inlay kind))
   9952                                 (if padding-right? " " "")))))))
   9953    :mode 'tick))
   9954 
   9955 (define-minor-mode lsp-inlay-hints-mode
   9956   "Mode for displaying inlay hints."
   9957   :lighter nil
   9958   (cond
   9959    ((and lsp-inlay-hints-mode lsp--buffer-workspaces)
   9960     (add-hook 'lsp-on-idle-hook #'lsp--update-inlay-hints nil t)
   9961     (when lsp-update-inlay-hints-on-scroll
   9962       (add-to-list (make-local-variable 'window-scroll-functions)
   9963                    #'lsp--update-inlay-hints-scroll-function)))
   9964    (t
   9965     (lsp--remove-overlays 'lsp-inlay-hint)
   9966     (remove-hook 'lsp-on-idle-hook #'lsp--update-inlay-hints t)
   9967     (setf window-scroll-functions
   9968           (delete #'lsp--update-inlay-hints-scroll-function window-scroll-functions)))))
   9969 
   9970 
   9971 
   9972 ;;;###autoload
   9973 (defun lsp-start-plain ()
   9974   "Start `lsp-mode' using minimal configuration using the latest `melpa' version
   9975 of the packages.
   9976 
   9977 In case the major-mode that you are using for "
   9978   (interactive)
   9979   (let ((start-plain (make-temp-file "plain" nil ".el")))
   9980     (url-copy-file "https://raw.githubusercontent.com/emacs-lsp/lsp-mode/master/scripts/lsp-start-plain.el"
   9981                    start-plain t)
   9982     (start-process "lsp-start-plain"
   9983                    (generate-new-buffer " *lsp-start-plain*")
   9984                    (expand-file-name invocation-name invocation-directory)
   9985                     "-q" "-l" start-plain (or (buffer-file-name) ""))))
   9986 
   9987 
   9988 
   9989 (provide 'lsp-mode)
   9990 ;;; lsp-mode.el ends here