Skip to content

Commit

Permalink
Proposal: make it easier to work with dotnet tools for C#/F#
Browse files Browse the repository at this point in the history
This commit implements an approach proposed in #3906. Specifically, it provides
new control variables to make it possible to use C# and F# language servers
_either_ as global _or_ local dotnet tools. So far, I've done this by providing
boolean variables to control command construction, but I'm not attached to this
approach.

Closes #3906.
  • Loading branch information
Gastove committed Jul 6, 2024
1 parent 2531042 commit c6c272d
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 18 deletions.
43 changes: 38 additions & 5 deletions clients/lsp-csharp.el
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,28 @@ Usually this is to be set in your .dir-locals.el on the project root directory."
:group 'lsp-csharp-omnisharp
:type 'file)


(defcustom lsp-csharp-omnisharp-enable-decompilation-support
nil
"Decompile bytecode when browsing method metadata for types in assemblies.
Otherwise only declarations for the methods are visible (the default)."
:group 'lsp-csharp
:type 'boolean)

(defcustom lsp-csharp-csharpls-use-dotnet-tool t
"Whether to use a dotnet tool version of the expected C# language server; only available for csharp-ls"
:group 'lsp-csharp
:type 'boolean
:risky t)

(defcustom lsp-csharp-csharpls-use-local-tool nil
"Whether to use csharp-ls as a global or local dotnet tool.
Note: this variable has no effect if lsp-csharp-csharpls-use-dotnet-tool is nil."
:group 'lsp-csharp
:type 'boolean
:risky t)

(lsp-dependency
'omnisharp-roslyn
`(:download :url lsp-csharp-omnisharp-roslyn-download-url
Expand Down Expand Up @@ -485,6 +500,15 @@ filename is returned so lsp-mode can display this file."
(with-temp-buffer (insert-file-contents metadata-file-name)
(buffer-string))))))

(defun lsp-csharp--cls-find-executable ()
(or (when lsp-csharp-csharpls-use-dotnet-tool
(-flatten (list "dotnet" (if lsp-csharp-csharpls-use-local-tool (list "tool" "run") "") "csharp-ls")))
(executable-find "csharp-ls")
;; NOTE[gastove|2023-02-03] This approach might be remove-able if we
;; standardize on going through the `dotnet' cli.
(f-join (or (getenv "USERPROFILE") (getenv "HOME"))
".dotnet" "tools" "csharp-ls")))

(defun lsp-csharp--cls-make-launch-cmd ()
"Return command line to invoke csharp-ls."

Expand All @@ -504,16 +528,25 @@ filename is returned so lsp-mode can display this file."

(t nil)))

(csharp-ls-exec (or (executable-find "csharp-ls")
(f-join (or (getenv "USERPROFILE") (getenv "HOME"))
".dotnet" "tools" "csharp-ls")))
(csharp-ls-exec (lsp-csharp--cls-find-executable))

(solution-file-params (when lsp-csharp-solution-file
(list "-s" lsp-csharp-solution-file))))
(append startup-wrapper
(list csharp-ls-exec)
(if (listp csharp-ls-exec)
csharp-ls-exec
(list csharp-ls-exec))
solution-file-params)))

(defun lsp-csharp--cls-test-csharp-ls-present ()
"Return non-nil if dotnet tool csharp-ls is installed as a dotnet tool."
(string-match-p "csharp-ls"
(shell-command-to-string
(if lsp-csharp-csharpls-use-local-tool
"dotnet tool list"
"dotnet tool list -g")))
)

(defun lsp-csharp--cls-download-server (_client callback error-callback update?)
"Install/update csharp-ls language server using `dotnet tool'.
Expand All @@ -522,7 +555,7 @@ Will update if UPDATE? is t"
(lsp-async-start-process
callback
error-callback
"dotnet" "tool" (if update? "update" "install") "-g" "csharp-ls"))
"dotnet" "tool" (if update? "update" "install") (if lsp-csharp-csharpls-use-local-tool "" "-g") "csharp-ls"))

(lsp-register-client
(make-lsp-client :new-connection (lsp-stdio-connection #'lsp-csharp--cls-make-launch-cmd)
Expand Down
50 changes: 37 additions & 13 deletions clients/lsp-fsharp.el
Original file line number Diff line number Diff line change
Expand Up @@ -157,15 +157,6 @@ with test projects are not autoloaded by FSharpAutoComplete."
:type 'boolean
:package-version '(lsp-mode . "9.0.0"))

(defun lsp-fsharp--fsac-install (_client callback error-callback update?)
"Install/update fsautocomplete language server using `dotnet tool'.
Will invoke CALLBACK or ERROR-CALLBACK based on result. Will update if
UPDATE? is t."
(lsp-async-start-process
callback
error-callback
"dotnet" "tool" (if update? "update" "install") "-g" "fsautocomplete"))

(defcustom lsp-fsharp-use-dotnet-tool-for-fsac t
"Run FsAutoComplete as a dotnet tool.
Expand All @@ -176,14 +167,39 @@ available, else the globally installed tool."
:type 'boolean
:risky t)


(defcustom lsp-fsharp-use-dotnet-local-tool nil
"When running FsAutoComplete as a dotnet tool, use the local version.
This variable will have no effect if
`lsp-fsharp-use-dotnet-tool-for-fsac' is nil.
This variable is risky as a buffer-local, and should instead be
set per-project (e.g. in a .dir-locals.el at the root of a
repository)."
:group 'lsp-fsharp
:type 'boolean
:risky t)

(defcustom lsp-fsharp-workspace-extra-exclude-dirs '()
"Additional directories to exclude from FsAutoComplete workspace loading / discovery."
:group 'lsp-fsharp
:type 'lsp-string-vector)

(defun lsp-fsharp--fsac-install (_client callback error-callback update?)
"Install/update fsautocomplete language server using `dotnet tool'.
Will invoke CALLBACK or ERROR-CALLBACK based on result. Will update if
UPDATE? is t."
(lsp-async-start-process
callback
error-callback
"dotnet" "tool" (if update? "update" "install") (when lsp-fsharp-use-dotnet-local-tool "-g") "fsautocomplete"))

(defun lsp-fsharp--fsac-cmd ()
"The location of fsautocomplete executable."
(or (-let [maybe-local-executable (expand-file-name "fsautocomplete" lsp-fsharp-server-install-dir)]
(or (when lsp-fsharp-use-dotnet-tool-for-fsac
(list "dotnet" (if lsp-fsharp-use-dotnet-local-tool "" "tool") "run" "fsautocomplete"))
(-let [maybe-local-executable (expand-file-name "fsautocomplete" lsp-fsharp-server-install-dir)]
(when (f-exists-p maybe-local-executable)
maybe-local-executable))
(executable-find "fsautocomplete")
Expand Down Expand Up @@ -214,14 +230,22 @@ available, else the globally installed tool."
(t nil)))
(fsautocomplete-exec (lsp-fsharp--fsac-cmd)))
(append startup-wrapper
(list fsautocomplete-exec)
(if (listp fsautocomplete-exec)
fsautocomplete-exec
(list fsautocomplete-exec))
lsp-fsharp-server-args)))

(defun lsp-fsharp--test-fsautocomplete-present ()
"Return non-nil if dotnet tool fsautocomplete is installed globally."
(if lsp-fsharp-use-dotnet-tool-for-fsac
(string-match-p "fsautocomplete"
(shell-command-to-string "dotnet tool list -g"))
(-let* ((cmd-str (if lsp-fsharp-use-dotnet-local-tool
"dotnet tool list"
"dotnet tool list -g"))
(res (string-match-p "fsautocomplete"
(shell-command-to-string cmd-str))))
(if res res
(error "Failed to locate fsautocomplete binary; due to lsp-fsharp-use-dotnet-local-tool == %s, checked with command %s" lsp-fsharp-use-dotnet-local-tool cmd-str)))

(f-exists? (lsp-fsharp--fsac-cmd))))

(defun lsp-fsharp--project-list (workspace)
Expand Down

0 comments on commit c6c272d

Please sign in to comment.