diff --git a/CHANGELOG.org b/CHANGELOG.org index e7629a2319..0f486bb97a 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -3,6 +3,8 @@ * Add support for GNAT Project (~gpr-mode~, ~gpr-ts-mode~). * Add SQL support * Add support for Meson build system. (~meson-mode~). + * Add support for go to definition for external files (.dll) in CSharp projects for OmniSharp server. + ** 9.0.0 * Add language server config for QML (Qt Modeling Language) using qmlls. * Add new configuration options for lsp-html. Now able to toggle documentation hovers. Custom data is no longer experimental, and is now a vector. diff --git a/clients/lsp-csharp.el b/clients/lsp-csharp.el index 49d7cd6a48..a978c44401 100644 --- a/clients/lsp-csharp.el +++ b/clients/lsp-csharp.el @@ -41,6 +41,13 @@ Version 1.34.3 minimum is required." :link '(url-link "https://github.com/OmniSharp/omnisharp-roslyn") :package-version '(lsp-mode . "9.0.0")) +(defconst lsp-csharp--omnisharp-metadata-uri-re + "^file:///%24metadata%24/Project/\\(.+\\)/Assembly/\\(.+\\)/Symbol/\\(.+\\)\.cs$" + "Regular expression matching omnisharp's metadata uri. +Group 1 contains the Project name +Group 2 contains the Assembly name +Group 3 contains the Type name") + (defcustom lsp-csharp-server-install-dir (f-join lsp-server-install-dir "omnisharp-roslyn/") "Installation directory for OmniSharp Roslyn server." @@ -113,6 +120,13 @@ 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) + (lsp-dependency 'omnisharp-roslyn `(:download :url lsp-csharp-omnisharp-roslyn-download-url @@ -334,6 +348,62 @@ using the `textDocument/references' request." (lsp-show-xrefs (lsp--locations-to-xref-items locations-found) nil t) (message "No references found"))) +(defun lsp-csharp--omnisharp-path->qualified-name (path) + "Convert PATH to qualified-namespace-like name." + (replace-regexp-in-string + (regexp-quote "/") + "." + path)) + +(defun lsp-csharp--omnisharp-metadata-uri-handler (uri) + "Handle `file:/(metadata)' URI from omnisharp-roslyn server. + +The URI is parsed and then `o#/metadata' request is issued to retrieve +metadata from the server. A cache file is created on project root dir that +stores this metadata and filename is returned so lsp-mode can display this file." + (string-match lsp-csharp--omnisharp-metadata-uri-re uri) + (-when-let* ((project-name (lsp-csharp--omnisharp-path->qualified-name (url-unhex-string (match-string 1 uri)))) + (assembly-name (lsp-csharp--omnisharp-path->qualified-name (url-unhex-string (match-string 2 uri)))) + (type-name (lsp-csharp--omnisharp-path->qualified-name (url-unhex-string (match-string 3 uri)))) + (metadata-req (lsp-make-omnisharp-metadata-request :project-name project-name + :assembly-name assembly-name + :type-name type-name)) + (metadata (lsp-request "o#/metadata" metadata-req)) + ((&omnisharp:MetadataResponse :source-name :source) metadata) + (filename (f-join ".cache" + "lsp-csharp" + "metadata" + "Project" project-name + "Assembly" assembly-name + "Symbol" (concat type-name ".cs"))) + (file-location (expand-file-name filename (lsp--suggest-project-root))) + (metadata-file-location (concat file-location ".metadata-uri")) + (path (f-dirname file-location))) + + (unless (find-buffer-visiting file-location) + (unless (file-directory-p path) + (make-directory path t)) + + (with-temp-file metadata-file-location + (insert uri)) + + (with-temp-file file-location + (insert source))) + + file-location)) + +(defun lsp-csharp--omnisharp-uri->path-fn (uri) + "Custom implementation of lsp--uri-to-path function to glue omnisharp's +metadata uri." + (if (string-match-p lsp-csharp--omnisharp-metadata-uri-re uri) + (lsp-csharp--omnisharp-metadata-uri-handler uri) + (lsp--uri-to-path-1 uri))) + +(defun lsp-csharp--omnisharp-environment-fn () + "Build environment structure for current values of lsp-csharp customizables. +See https://github.com/OmniSharp/omnisharp-roslyn/wiki/Configuration-Options" + `(("OMNISHARP_RoslynExtensionsOptions:enableDecompilationSupport" . ,(if lsp-csharp-omnisharp-enable-decompilation-support "true" "false")))) + (lsp-register-client (make-lsp-client :new-connection (lsp-stdio-connection @@ -348,6 +418,8 @@ using the `textDocument/references' request." :activation-fn (lsp-activate-on "csharp") :server-id 'omnisharp :priority -1 + :uri->path-fn #'lsp-csharp--omnisharp-uri->path-fn + :environment-fn #'lsp-csharp--omnisharp-environment-fn :action-handlers (ht ("omnisharp/client/findReferences" 'lsp-csharp--action-client-find-references)) :notification-handlers (ht ("o#/projectadded" 'ignore) ("o#/projectchanged" 'ignore) diff --git a/lsp-protocol.el b/lsp-protocol.el index b3cdb0db09..034107a5b3 100644 --- a/lsp-protocol.el +++ b/lsp-protocol.el @@ -399,7 +399,9 @@ See `-let' for a description of the destructuring mechanism." (omnisharp:RunTestsInClassRequest (:MethodNames :RunSettings :TestFrameworkname :TargetFrameworkVersion :NoBuild :Line :Column :Buffer :FileName)) (omnisharp:RunTestResponse (:Results :Pass :Failure :ContextHadNoTests)) (omnisharp:TestMessageEvent (:MessageLevel :Message)) - (omnisharp:DotNetTestResult (:MethodName :Outcome :ErrorMessage :ErrorStackTrace :StandardOutput :StandardError))) + (omnisharp:DotNetTestResult (:MethodName :Outcome :ErrorMessage :ErrorStackTrace :StandardOutput :StandardError)) + (omnisharp:MetadataRequest (:AssemblyName :TypeName :ProjectName :VersionNumber :Language)) + (omnisharp:MetadataResponse (:SourceName :Source))) (lsp-interface (csharp-ls:CSharpMetadata (:textDocument)) (csharp-ls:CSharpMetadataResponse (:source :projectName :assemblyName :symbolName)))