eclipse-jdtls / eclipse.jdt.ls

Java language server
1.8k stars 400 forks source link

No delegateCommandHandler for java.action.organizeImports #2126

Closed asmodeus812 closed 1 year ago

asmodeus812 commented 2 years ago

Hi, I am having an issue trying to force trigger an action for jdtls, (which used to work some time ago) and i have not done any changes to my configuration, the error seems to be coming directly from jdtls itself, and i am not sure why, or what changed. I am using 1.9.0 milestone build from 03.22. But the same issue persists on the latest snapshot build. Note the programmatic action procedure below works fine for other servers which support organize imports such as tsserver.

local action = 'source.organizeImports'
local bufnr = vim.api.nvim_get_current_buf()
    local params = vim.lsp.util.make_range_params()
    params.context = {
        diagnostics = vim.lsp.diagnostic.get_line_diagnostics(),
        only = { action }
    }
    local responses = vim.lsp.buf_request_sync(bufnr, "textDocument/codeAction", params)

    if not responses or vim.tbl_isempty(responses) then
        return nil
    end
    for client_id, response in pairs(responses) do
        for _, result in pairs(response.result or {}) do
            if result.edit then
                vim.lsp.util.apply_workspace_edit(result.edit,
                    vim.lsp.get_client_by_id(client_id).offset_encoding)
            else
                vim.lsp.buf.execute_command(result.command)
            end
        end
    end
    return action

The error i get is as the title states, seems that jdtls does understand that lsp source.organizeImports maps to internally but fails somewhere else. No delegateCommandHandler for java.action.organizeImports

Simplified config being passed for the server

{
                    -- jdt = {
                    --     ls = {
                    --         vmargs = "-Dsun.zip.disableMemoryMapping=true -Xms2048m -Xmx4096m -XX:GCTimeRatio=20 -XX:+UseParallelGC"
                    --     }
                    -- },
                    trace = {
                        server = "message",
                    },
                    signatureHelp = {
                        enabled = false
                    },
                    referenceCodeLens = {
                        enabled = true
                    },
                    format = {
                        enabled = true,
                        settings = {
                            profile = "GoogleStyle",
                            url = opts.format_file or "https://raw.githubusercontent.com/google/styleguide/gh-pages/eclipse-java-google-style.xml"
                        },
                    },
                    saveActions = {
                        organizeImports = true
                    },
                    completion = {
                        importOrder = {
                            "javax",
                            "java",
                            "com",
                            "org"
                        }
                    },
                    codeGeneration = {
                        tostring = {
                            listArrayContents = true,
                            skipNullValues = true,
                            template = "${object.className}{${member.name()}=${member.value}, ${otherMembers}}",
                        },
                        useBlocks = true,
                        hashCodeEquals = {
                            useInstanceof = true,
                            useJava7Objects = true
                        },
                        generateComments = true,
                        insertLocation = true
                    },
                    autobuild = {
                        enabled = true
                    },
                    progressReports = {
                        enabled = false
                    },
                    eclipse = {
                        downloadSources = true
                    },
                    maven = {
                        downloadSources = true,
                        updateSnapshots = true
                    }
                }

https://github.com/eclipse/eclipse.jdt.ls/issues/1146 - no idea if this is related.

snjeza commented 2 years ago

@asmodeus812 could you try to set

"initializationOptions": {
        "extendedClientCapabilities": {
           ...
            "advancedGenerateAccessorsSupport": false,
           ...
        },

    }
asmodeus812 commented 2 years ago

@snjeza thanks for the quick feedback, i did try it but did not make any difference, same error is observed, this is what jdtls plugin passes as default, and i just extended with it with your suggestion

 init_options = {
                bundles = bundles,
                extendedClientCapabilities = {
                    advancedGenerateAccessorsSupport = true,
                    progressReportProvider = true;
                    classFileContentsSupport = true;
                    generateToStringPromptSupport = true;
                    hashCodeEqualsPromptSupport = true;
                    advancedExtractRefactoringSupport = true;
                    advancedOrganizeImportsSupport = true;
                    generateConstructorsPromptSupport = true;
                    generateDelegateMethodsPromptSupport = true;
                    moveRefactoringSupport = true;
                    overrideMethodsPromptSupport = true;
                    inferSelectionSupport = { "extractMethod", "extractVariable", "extractConstant" };
                },
            },

The lsp log is also empty, with jdtls trace enabled [START][2022-06-15 06:52:18] LSP logging initiated [WARN][2022-06-15 06:52:41] ...lsp/handlers.lua:109 "The language server jdt.ls triggers a registerCapability handler despite dynamicRegistration set to false. Report upstream, this warning is harmless"

snjeza commented 2 years ago

@asmodeus812 could you attach your server log?

asmodeus812 commented 2 years ago

@snjeza i did actually in the last post, that was with verbose turned on, nothing is reported from jdtls.

snjeza commented 2 years ago

@asmodeus812 could you set java.trace.server=verbose - Enable logging and check your initializationOptions?

asmodeus812 commented 2 years ago

Yeah, i already had it at verbose, this is what my config looked/looks like while i am testing this issue

            init_options = {
                extendedClientCapabilities = {
                    advancedGenerateAccessorsSupport = true,
                    progressReportProvider = true;
                    classFileContentsSupport = true;
                    generateToStringPromptSupport = true;
                    hashCodeEqualsPromptSupport = true;
                    advancedExtractRefactoringSupport = true;
                    advancedOrganizeImportsSupport = true;
                    generateConstructorsPromptSupport = true;
                    generateDelegateMethodsPromptSupport = true;
                    moveRefactoringSupport = true;
                    overrideMethodsPromptSupport = true;
                    inferSelectionSupport = { "extractMethod", "extractVariable", "extractConstant" };
                },
            },
            settings = {
                java = {
                    trace = {
                        server = "verbose",
                    },
                    signatureHelp = {
                        enabled = false
                    },
                    referenceCodeLens = {
                        enabled = true
                    },
                    format = {
                        enabled = true,
                        settings = {
                            profile = "GoogleStyle",
                            url = opts.format_file or "https://raw.githubusercontent.com/google/styleguide/gh-pages/eclipse-java-google-style.xml"
                        },
                    },
                    saveActions = {
                        organizeImports = true
                    },
                    completion = {
                        importOrder = {
                            "javax",
                            "java",
                            "com",
                            "org"
                        }
                    },
                    codeGeneration = {
                        tostring = {
                            listArrayContents = true,
                            skipNullValues = true,
                            template = "${object.className}{${member.name()}=${member.value}, ${otherMembers}}",
                        },
                        useBlocks = true,
                        hashCodeEquals = {
                            useInstanceof = true,
                            useJava7Objects = true
                        },
                        generateComments = true,
                        insertLocation = true
                    },
                    autobuild = {
                        enabled = true
                    },
                    progressReports = {
                        enabled = false
                    },
                    eclipse = {
                        downloadSources = true
                    },
                    maven = {
                        downloadSources = true,
                        updateSnapshots = true
                    }
                }
            }

The logs reported just the following [START][2022-06-15 06:52:18] LSP logging initiated [WARN][2022-06-15 06:52:41] ...lsp/handlers.lua:109 "The language server jdt.ls triggers a registerCapability handler despite dynamicRegistration set to false. Report upstream, this warning is harmless"

The workspace logs contain the following

!ENTRY org.eclipse.jdt.ls.core 1 0 2022-06-17 14:29:45.421
!MESSAGE >> workspace/executeCommand java.action.organizeImports

!ENTRY org.eclipse.jdt.ls.core 1 0 2022-06-17 14:33:08.562
!MESSAGE >> document/signatureHelp

!ENTRY org.eclipse.jdt.ls.core 1 0 2022-06-17 14:33:08.919
!MESSAGE >> document/signatureHelp

!ENTRY org.eclipse.jdt.ls.core 1 0 2022-06-17 14:33:09.515
!MESSAGE >> document/codeAction

!ENTRY org.eclipse.jdt.ls.core 1 0 2022-06-17 14:33:09.551
!MESSAGE >> workspace/executeCommand java.action.organizeImports

!ENTRY org.eclipse.jdt.ls.core 1 0 2022-06-17 14:33:10.299
!MESSAGE >> document/codeAction

!ENTRY org.eclipse.jdt.ls.core 1 0 2022-06-17 14:33:10.303
!MESSAGE >> workspace/executeCommand java.action.organizeImports

!ENTRY org.eclipse.jdt.ls.core 1 0 2022-06-17 14:33:10.711
!MESSAGE >> document/codeAction

!ENTRY org.eclipse.jdt.ls.core 1 0 2022-06-17 14:33:10.715
!MESSAGE >> workspace/executeCommand java.action.organizeImports

!ENTRY org.eclipse.jdt.ls.core 1 0 2022-06-17 14:33:11.116
!MESSAGE >> document/codeAction

!ENTRY org.eclipse.jdt.ls.core 1 0 2022-06-17 14:33:11.120
!MESSAGE >> workspace/executeCommand java.action.organizeImports

!ENTRY org.eclipse.jdt.ls.core 1 0 2022-06-17 14:33:12.923
!MESSAGE >> document/signatureHelp
snjeza commented 2 years ago

@asmodeus812 You may want to take a look at https://github.com/eclipse/eclipse.jdt.ls/pull/1059#discussion_r291870361 Could you attach a sample project or java class?

mfussenegger commented 2 years ago

The code snippet shown here is lacking support for the client side commands. nvim-jdtls would include those.

You'd need to set advancedOrganizeImportsSupport = false in your extendedClientCapabilities to opt-out, given that your code-action logic doesn't handle them, or use vim.lsp.buf.code_action instead of your own custom solution. vim.lsp.buf.code_action supports client side commands

asmodeus812 commented 2 years ago

Not sure i understand what you mean, but i am pretty sure that used to work before for me in jdtls. It actually works with other lang servers as i have already mentioned. Are you implying that it is an issue with nvim/lsp client rather than the server. For example the same snippet above works fine with quickfix even with jdtls.

mfussenegger commented 2 years ago

The issue is neither with the client nor with the server but with your custom code snippet.

You're telling the server that the client supports a client side organize import command by setting advancedOrganizeImportsSupport to true, but your custom code doesn't support it.

The reason it works with other servers is because they don't recognise the advancedOrganizeImportsSupport setting and therefore don't try to use the client side command. This is a eclipse.jdt.ls specific extension

Your options:

asmodeus812 commented 2 years ago

Sorry but had you bothered to read the full thread you would have noticed that i am not setting advancedOrganizeImportsSupport to true, this snippet above was verbatum copied from the source of nvim jdtls which has this option set to true BY DEAFULT i just took the defaults and added the optionadvancedGenerateAccessorsSupport @snjeza suggested to the lua table since it is not configured to deepextend those but rather just checks if initoptions exists and uses the user provided table.

https://github.com/mfussenegger/nvim-jdtls/blob/3a148dac526396678f141a033270961d0d9ccb88/lua/jdtls/setup.lua#L127

https://github.com/mfussenegger/nvim-jdtls/blob/3a148dac526396678f141a033270961d0d9ccb88/lua/jdtls/setup.lua#L257

Here are the references. So what is the purpose of the advanced organize option in regards to jdtls capabilities compared to "non advanced imports" ??

mfussenegger commented 2 years ago

Sorry but had you bothered to read the full thread you would have noticed

No need for bad faith accusations.

this is what jdtls plugin passes as default, and i just extended with it with your suggestion

I implied from this that you're using nvim-jdtls, is that not the case? As you correctly stated, nvim-jdtls sets advancedOrganizeImportsSupport to true by default. So whether you set it yourself or not doesn't matter. If the effective value is true you cannot use your code snippet.

So what is the purpose of the advanced organize option in regards to jdtls capabilities compared to "non advanced imports" ??

It allows to choose the right import if there are ambiguous choices:

organize import demo

asmodeus812 commented 2 years ago

@mfussenegger had some free time to play around, setting the option to false does not seem to work, breaks at nvim lua level now, seems like a property of the result (i.e the actions snippet i've been using above) is missing. Migrating to .8 is not an option at the moment.

init_options = {
                extendedClientCapabilities = {
                    advancedGenerateAccessorsSupport = true,
                    progressReportProvider = true;
                    classFileContentsSupport = true;
                    generateToStringPromptSupport = true;
                    hashCodeEqualsPromptSupport = true;
                    advancedExtractRefactoringSupport = true;
                    advancedOrganizeImportsSupport = false;
                    generateConstructorsPromptSupport = true;
                    generateDelegateMethodsPromptSupport = true;
                    moveRefactoringSupport = true;
                    overrideMethodsPromptSupport = true;
                    inferSelectionSupport = { "extractMethod", "extractVariable", "extractConstant" };
                },
            },

image

I am not familiar enough with the internal lua api, what i wanted is to simply tell the lang server to apply a given action that's it.

local action = 'source.organizeImports'
local bufnr = vim.api.nvim_get_current_buf()
    local params = vim.lsp.util.make_range_params()
    params.context = {
        diagnostics = vim.lsp.diagnostic.get_line_diagnostics(),
        only = { action }
    }
    local responses = vim.lsp.buf_request_sync(bufnr, "textDocument/codeAction", params)

    if not responses or vim.tbl_isempty(responses) then
        return nil
    end
    for client_id, response in pairs(responses) do
        for _, result in pairs(response.result or {}) do
            if result.edit then
                vim.lsp.util.apply_workspace_edit(result.edit,
                    vim.lsp.get_client_by_id(client_id).offset_encoding)
            else
                -- fails here, result.edit is false, but missing command params ?
                vim.lsp.buf.execute_command(result.command)
            end
        end
    end
    return action
asmodeus812 commented 1 year ago

This can be closed as at the time i was unsure as to how jdtls handles its relationship between lsp code actions and handlers.