From 7ced548261f52109717ad7588e7a521368fed148 Mon Sep 17 00:00:00 2001 From: Frairlyn Camilo Roque Suarez Date: Thu, 25 Apr 2024 15:27:15 -0400 Subject: [PATCH 1/5] feat(lsp-csharp): Add goto to metadata definition Now if we try to find the definition of a symbol that is defined externally, it will try to load a stripped-down version of the file where is defined and show it in a temporal file. --- clients/lsp-csharp.el | 58 +++++++++++++++++++++++++++++++++++++++++++ lsp-protocol.el | 4 ++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/clients/lsp-csharp.el b/clients/lsp-csharp.el index 49d7cd6a48..4240a9e66a 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--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." @@ -334,6 +341,56 @@ using the `textDocument/references' request." (lsp-show-xrefs (lsp--locations-to-xref-items locations-found) nil t) (message "No references found"))) +(defun lsp-csharp--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--metadata-uri-re uri) + (-when-let* ((project-name (lsp-csharp--path->qualified-name (url-unhex-string (match-string 1 uri)))) + (assembly-name (lsp-csharp--path->qualified-name (url-unhex-string (match-string 2 uri)))) + (type-name (lsp-csharp--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--uri->path-fn (uri) + "Custom implementation of lsp--uri-to-path function to glue omnisharp's metadata uri." + (if (string-match-p lsp-csharp--metadata-uri-re uri) + (lsp-csharp--omnisharp-metadata-uri-handler uri) + (lsp--uri-to-path-1 uri)) + ) + (lsp-register-client (make-lsp-client :new-connection (lsp-stdio-connection @@ -348,6 +405,7 @@ using the `textDocument/references' request." :activation-fn (lsp-activate-on "csharp") :server-id 'omnisharp :priority -1 + :uri->path-fn #'lsp-csharp--uri->path-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))) From 2d6a54275ac0bdbd9379d0018648f95c648f09f6 Mon Sep 17 00:00:00 2001 From: Frairlyn Camilo Roque Suarez Date: Thu, 25 Apr 2024 15:52:29 -0400 Subject: [PATCH 2/5] feat(lsp-csharp): Add option for decompilation on goto definition. --- clients/lsp-csharp.el | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/clients/lsp-csharp.el b/clients/lsp-csharp.el index 4240a9e66a..408fac137f 100644 --- a/clients/lsp-csharp.el +++ b/clients/lsp-csharp.el @@ -120,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-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 @@ -391,6 +398,11 @@ stores this metadata and filename is returned so lsp-mode can display this file. (lsp--uri-to-path-1 uri)) ) +(defun lsp-csharp--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-enable-decompilation-support "true" "false")))) + (lsp-register-client (make-lsp-client :new-connection (lsp-stdio-connection @@ -406,6 +418,7 @@ stores this metadata and filename is returned so lsp-mode can display this file. :server-id 'omnisharp :priority -1 :uri->path-fn #'lsp-csharp--uri->path-fn + :environment-fn #'lsp-csharp--environment-fn :action-handlers (ht ("omnisharp/client/findReferences" 'lsp-csharp--action-client-find-references)) :notification-handlers (ht ("o#/projectadded" 'ignore) ("o#/projectchanged" 'ignore) From 2b90a1bbfbc0861173a5fd2da8cd7d84d700723d Mon Sep 17 00:00:00 2001 From: Frairlyn Camilo Roque Suarez Date: Tue, 28 May 2024 21:02:08 -0400 Subject: [PATCH 3/5] Add entry to the CHANGELOG --- CHANGELOG.org | 2 ++ 1 file changed, 2 insertions(+) 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. From 25f88b1e81a3b2d4bcea8e55963c5da756b45e73 Mon Sep 17 00:00:00 2001 From: Frairlyn Camilo Roque Suarez Date: Tue, 28 May 2024 21:19:08 -0400 Subject: [PATCH 4/5] refactor(lsp-csharp): Follow razzmat's suggestion. I renamed functionallity only used by omnisharp to be prefixed with lsp-csharp--omnisharp- I'm a little bit torn with lsp-csharp--path->qualified-name being prefixed like that, but only omnisharp is using it. --- clients/lsp-csharp.el | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/clients/lsp-csharp.el b/clients/lsp-csharp.el index 408fac137f..9c566935da 100644 --- a/clients/lsp-csharp.el +++ b/clients/lsp-csharp.el @@ -41,7 +41,7 @@ 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--metadata-uri-re +(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 @@ -120,7 +120,7 @@ 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-enable-decompilation-support +(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)." @@ -348,7 +348,7 @@ using the `textDocument/references' request." (lsp-show-xrefs (lsp--locations-to-xref-items locations-found) nil t) (message "No references found"))) -(defun lsp-csharp--path->qualified-name (path) +(defun lsp-csharp--omnisharp-path->qualified-name (path) "Convert PATH to qualified-namespace-like name." (replace-regexp-in-string (regexp-quote "/") @@ -360,10 +360,10 @@ using the `textDocument/references' request." 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--metadata-uri-re uri) - (-when-let* ((project-name (lsp-csharp--path->qualified-name (url-unhex-string (match-string 1 uri)))) - (assembly-name (lsp-csharp--path->qualified-name (url-unhex-string (match-string 2 uri)))) - (type-name (lsp-csharp--path->qualified-name (url-unhex-string (match-string 3 uri)))) + (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)) @@ -391,17 +391,17 @@ stores this metadata and filename is returned so lsp-mode can display this file. file-location)) -(defun lsp-csharp--uri->path-fn (uri) +(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--metadata-uri-re 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--environment-fn () +(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-enable-decompilation-support "true" "false")))) + `(("OMNISHARP_RoslynExtensionsOptions:enableDecompilationSupport" . ,(if lsp-csharp-omnisharp-enable-decompilation-support "true" "false")))) (lsp-register-client (make-lsp-client :new-connection @@ -417,8 +417,8 @@ See https://github.com/OmniSharp/omnisharp-roslyn/wiki/Configuration-Options" :activation-fn (lsp-activate-on "csharp") :server-id 'omnisharp :priority -1 - :uri->path-fn #'lsp-csharp--uri->path-fn - :environment-fn #'lsp-csharp--environment-fn + :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) From b8d671d3d61e43aab0dc775be0d8074e3a01adea Mon Sep 17 00:00:00 2001 From: Frairlyn Camilo Roque Suarez Date: Wed, 29 May 2024 08:30:53 -0400 Subject: [PATCH 5/5] style(lsp-csharp): Fix compilation warnings and other misc stuff. --- clients/lsp-csharp.el | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clients/lsp-csharp.el b/clients/lsp-csharp.el index 9c566935da..a978c44401 100644 --- a/clients/lsp-csharp.el +++ b/clients/lsp-csharp.el @@ -356,8 +356,9 @@ using the `textDocument/references' request." 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 + "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) @@ -392,11 +393,11 @@ stores this metadata and filename is returned so lsp-mode can display this file. file-location)) (defun lsp-csharp--omnisharp-uri->path-fn (uri) - "Custom implementation of lsp--uri-to-path function to glue omnisharp's metadata 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)) - ) + (lsp--uri-to-path-1 uri))) (defun lsp-csharp--omnisharp-environment-fn () "Build environment structure for current values of lsp-csharp customizables.