From 73f89e55229c664cfc1db3badd4a086cb270c4e6 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 12 Nov 2025 11:36:05 +0100 Subject: [PATCH 1/2] Extend loading of VSCode code-workspace files for Java workspaces I find myself often loading vscode workspaces with multiple Java projects that have dependencies between one another, and require the use of custom Java runtimes and debugging settings. Because of the way JDTLS works, the dependent project folders need to be "open" in the session at the same time, even though I don't usually have files from all projects open, so I add them into the jdtls hash. For the runtimes and debug settings, I just read from the code-workspace file's json config. --- lsp-java.el | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/lsp-java.el b/lsp-java.el index 5350b23..4b8df78 100644 --- a/lsp-java.el +++ b/lsp-java.el @@ -2182,6 +2182,58 @@ With prefix 2 show both." (user-error "No class under point.")) (setq lsp--buffer-workspaces workspaces))) +(defun lsp-java--load-vscode-workspace (file) + "Prepare workspace loaded from vscode workspace file +if Java projects and settings were configured. This adds all the folders +to the JDTLS session. Because of the way JDTLS works, dependent projects +would not be *open* from the PoV of the JDTLS server otherwise and thus +typechecking against them and building multi-project workspaces would +not work properly. + +Additionally, this also takes a few configuration settings into account +to setup Java runtimes and debug templates if possible." + + (when-let* ((json (json-read-file file))) + (--> json + (alist-get 'settings it) + (alist-get 'java.configuration.runtimes it) + (-each it (-lambda ((&alist 'name 'path 'default)) + (setq lsp-java-configuration-runtimes + (vconcat lsp-java-configuration-runtimes + `[(:name ,name :path ,path :default ,default)]))))) + (--> json + (alist-get 'launch it) + (alist-get 'configurations it) + (-each it (-lambda ((&alist 'type 'name 'projectName 'request 'hostName 'port)) + (when (and name (string-equal type "java")) + (eval-after-load 'dap-java + (lambda () + (dap-register-debug-template name + (list :type type + :request request + :projectName projectName + :hostName hostName + :port port))))))))) + + (seq-do (lambda (folder) + (if-let* ((project-file (f-join folder ".project")) + (xml (condition-case nil + (with-temp-buffer + (insert-file-contents project-file) + (xml-parse-region (point-min) (point-max))) + (error nil))) + (project-description (xml-get-children (car xml) 'projectDescription)) + (natures (xml-get-children (xml-get-children (car project-description) 'natures) 'nature))) + (if (and (= 1 (seq-length natures)) + (member "org.eclipse.jdt.core.javanature" (xml-node-children (car natures)))) + (puthash 'jdtls + (append (gethash 'jdtls (lsp-session-server-id->folders (lsp-session))) + (list folder)) + (lsp-session-server-id->folders (lsp-session)))))) + (lsp-session-folders (lsp-session)))) + +(advice-add #'lsp-load-vscode-workspace :after #'lsp-java--load-vscode-workspace) + (provide 'lsp-java) ;;; lsp-java.el ends here From 1e08bb60efef51672319f6a764c2bf17784e5b72 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 18 Nov 2025 10:09:35 +0100 Subject: [PATCH 2/2] Make lsp-java-load-vscode-workspace it's own command --- README.md | 5 +++++ lsp-java.el | 43 ++++++++++++++++++++++++++++++++----------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 902fcc5..3c91aa6 100644 --- a/README.md +++ b/README.md @@ -325,3 +325,8 @@ LSP slowness could be caused by slow JDT server, especially on large JAVA projec ;; current VSCode defaults (setq lsp-java-vmargs '("-XX:+UseParallelGC" "-XX:GCTimeRatio=4" "-XX:AdaptiveSizePolicyWeight=90" "-Dsun.zip.disableMemoryMapping=true" "-Xmx2G" "-Xms100m")) ``` + +* I have configured everything in VSCode and saved the code workspace there, can import it? + +Yes, the command `lsp-java-load-vscode-workspace` allows you to load a code-workspace file created in VScode. +It will also import the Java runtime and Debug launch configurations from the VSCode settings. diff --git a/lsp-java.el b/lsp-java.el index 4b8df78..9b8ef5d 100644 --- a/lsp-java.el +++ b/lsp-java.el @@ -2182,25 +2182,49 @@ With prefix 2 show both." (user-error "No class under point.")) (setq lsp--buffer-workspaces workspaces))) -(defun lsp-java--load-vscode-workspace (file) - "Prepare workspace loaded from vscode workspace file -if Java projects and settings were configured. This adds all the folders -to the JDTLS session. Because of the way JDTLS works, dependent projects -would not be *open* from the PoV of the JDTLS server otherwise and thus -typechecking against them and building multi-project workspaces would -not work properly. +;;;###autoload +(defun lsp-java-load-vscode-workspace (file &optional prefix) + "Load a Java workspace from a VSCode workspace file. + +With prefix, delete the JDTLS workspace and cache dirs first. + +Any Java projects are added directly into the to the JDTLS session. +Because of the way JDTLS works, dependent projects would not be *open* +from the PoV of the JDTLS server otherwise and thus typechecking against +them and building multi-project workspaces would not work properly. Additionally, this also takes a few configuration settings into account to setup Java runtimes and debug templates if possible." + (interactive "fSelect file to import: \nP") + + (lsp-load-vscode-workspace file) + + (when prefix + (f-delete lsp-java-workspace-cache-dir t) + (f-delete lsp-java-workspace-dir t)) + + ;; lsp-load-vscode-workspace cleared the workspace folders, also clear the + ;; jdtls session folders + (puthash 'jdtls '() (lsp-session-server-id->folders (lsp-session))) (when-let* ((json (json-read-file file))) (--> json (alist-get 'settings it) (alist-get 'java.configuration.runtimes it) + (if it (progn (setq lsp-java-configuration-runtimes (vector)) it) it) (-each it (-lambda ((&alist 'name 'path 'default)) (setq lsp-java-configuration-runtimes (vconcat lsp-java-configuration-runtimes `[(:name ,name :path ,path :default ,default)]))))) + + (--> json + (alist-get 'settings it) + (alist-get 'java.completion.filteredTypes it) + (if it (progn (setq lsp-java-completion-filtered-types (vector)) it) it) + (-each it (lambda (str) + (setq lsp-java-completion-filtered-types + (vconcat lsp-java-completion-filtered-types + `[,str]))))) (--> json (alist-get 'launch it) (alist-get 'configurations it) @@ -2222,8 +2246,7 @@ to setup Java runtimes and debug templates if possible." (insert-file-contents project-file) (xml-parse-region (point-min) (point-max))) (error nil))) - (project-description (xml-get-children (car xml) 'projectDescription)) - (natures (xml-get-children (xml-get-children (car project-description) 'natures) 'nature))) + (natures (xml-get-children (car (xml-get-children (car xml) 'natures)) 'nature))) (if (and (= 1 (seq-length natures)) (member "org.eclipse.jdt.core.javanature" (xml-node-children (car natures)))) (puthash 'jdtls @@ -2232,8 +2255,6 @@ to setup Java runtimes and debug templates if possible." (lsp-session-server-id->folders (lsp-session)))))) (lsp-session-folders (lsp-session)))) -(advice-add #'lsp-load-vscode-workspace :after #'lsp-java--load-vscode-workspace) - (provide 'lsp-java) ;;; lsp-java.el ends here