mfussenegger / nvim-jdtls

Extensions for the built-in LSP support in Neovim for eclipse.jdt.ls
GNU General Public License v3.0
1k stars 62 forks source link

Go to definition errors out on javas builtin classes and methods #560

Closed xebcam closed 9 months ago

xebcam commented 10 months ago

LSP client configuration

Basically I have a similar issue as #375 the only difference is the error.

-- See `:help vim.lsp.start_client` for an overview of the supported `config` options.
    local jdtls = require("jdtls")
    local home = vim.fn.expand('$HOME')
    local root_dir_path = require('jdtls.setup').find_root({ '.project', '.git', 'mvnw', 'gradlew' })
    local root_dir_name = root_dir_path:match("[^/]+$")
    local workspace_dir = home .. '/.cache/jdtls-workspace/' .. root_dir_name
    jdtls.myconfig = {
      -- The command that starts the language server
      -- See: https://github.com/eclipse/eclipse.jdt.ls#running-from-the-command-line
      cmd = {

        -- 💀
        'java', -- or '/path/to/java17_or_newer/bin/java'
        -- depends on if `java` is in your $PATH env variable and if it points to the right version.

        '-Declipse.application=org.eclipse.jdt.ls.core.id1',
        '-Dosgi.bundles.defaultStartLevel=4',
        '-Declipse.product=org.eclipse.jdt.ls.core.product',
        '-Dlog.protocol=true',
        '-Dlog.level=ALL',
        '-Xmx1g',
        '--add-modules=ALL-SYSTEM',
        '--add-opens', 'java.base/java.util=ALL-UNNAMED',
        '--add-opens', 'java.base/java.lang=ALL-UNNAMED',

        -- 💀
        '-jar',
        home .. '/.local/share/nvim/mason/packages/jdtls/plugins/org.eclipse.equinox.launcher_1.6.500.v20230717-2134.jar',
        -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                                       ^^^^^^^^^^^^^^
        -- Must point to the                                                     Change this to
        -- eclipse.jdt.ls installation                                           the actual version

        -- 💀
        '-configuration', home .. '/.local/share/nvim/mason/packages/jdtls/config_linux',
        -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        ^^^^^^
        -- Must point to the                      Change to one of `linux`, `win` or `mac`
        -- eclipse.jdt.ls installation            Depending on your system.

        -- 💀
        -- See `data directory configuration` section in the README
        '-data', workspace_dir
      },

      -- 💀
      -- This is the default if not provided, you can remove it. Or adjust as needed.
      -- One dedicated LSP server & client will be started per unique root_dir
      root_dir = root_dir_path,

      -- Here you can configure eclipse.jdt.ls specific settings
      -- See https://github.com/eclipse/eclipse.jdt.ls/wiki/Running-the-JAVA-LS-server-from-the-command-line#initialize-request
      -- for a list of options
      settings = {
        java = {
        }
      },
      -- settings = {
      --   java = {
      --     autobuild = {
      --       enabled = true,
      --     },
      --     project = {
      --       output_path = '/home/sebas/Projects/learning/java/casting/bin',
      --       source_paths = {
      --         '/home/sebas/Projects/learning/java/casting/src',
      --       },
      --     }
      --   }
      -- },
      -- Language server `initializationOptions`
      -- You need to extend the `bundles` with paths to jar files
      -- if you want to use additional eclipse.jdt.ls plugins.
      --
      -- See https://github.com/mfussenegger/nvim-jdtls#java-debug-installation
      --
      -- If you don't plan on using the debugger or other eclipse.jdt.ls plugins you can remove this
      init_options = {
        bundles = {},
        -- workspace_folders = {
        --   "file:///home/sebas/Projects/learning/java/jdtls-workspace/casting"
        -- },
      },
    }

Eclipse.jdt.ls version

1.27.1

Steps to Reproduce

  1. Open a blank java project.
  2. Write the following code in some method: System.out.println("-");
  3. Put the cursor onto the word println
  4. Use vim.lsp.buf.definition() to jump to the definition
  5. Wait a bit
  6. Now you should see an error being thrown

Expected Result

To jump to the definition of the println method, without any errors.

Actual Result

Error message

Error executing vim.schedule lua callback: BufReadCmd Autocommands for "jdt://*": Vim(lua):E5108: Error executing lua
/home/sebas/.local/share/nvim/lazy/nvim-jdtls/lua/jdtls.lua:1185: Must have a `jdtls` client to load class file or jdt
 uri
stack traceback:
        [C]: in function 'assert'
        /home/sebas/.local/share/nvim/lazy/nvim-jdtls/lua/jdtls.lua:1185: in function 'open_classfile'
        [string ":lua"]:1: in main chunk
        [C]: in function 'bufload'
        /usr/share/nvim/runtime/lua/vim/lsp/util.lua:272: in function 'get_lines'
        /usr/share/nvim/runtime/lua/vim/lsp/util.lua:1822: in function 'locations_to_items'
        /usr/share/nvim/runtime/lua/vim/lsp/handlers.lua:398: in function 'handler'
        /usr/share/nvim/runtime/lua/vim/lsp.lua:1393: in function ''
        vim/_editor.lua: in function <vim/_editor.lua:0>
stack traceback:
        [C]: in function 'bufload'
        /usr/share/nvim/runtime/lua/vim/lsp/util.lua:272: in function 'get_lines'
        /usr/share/nvim/runtime/lua/vim/lsp/util.lua:1822: in function 'locations_to_items'
        /usr/share/nvim/runtime/lua/vim/lsp/handlers.lua:398: in function 'handler'
        /usr/share/nvim/runtime/lua/vim/lsp.lua:1393: in function ''
        vim/_editor.lua: in function <vim/_editor.lua:0>
xebcam commented 10 months ago

Adding to my last post. I forgot to indicate that I'm using a user command to initiate nvim-jdtls

vim.api.nvim_create_user_command(
  'JdtStart',
  function()
    local jdtls = require("jdtls")
    jdtls.start_or_attach(jdtls.myconfig)
  end,
  {}
)

If I use this command I get the error

Error executing vim.schedule lua callback: BufReadCmd Autocommands for "jdt://*": Vim(lua):E5108: Error executing lua
/home/sebas/.local/share/nvim/lazy/nvim-jdtls/lua/jdtls.lua:1185: Must have a `jdtls` client to load class file or jdt
 uri
stack traceback:
        [C]: in function 'assert'
        /home/sebas/.local/share/nvim/lazy/nvim-jdtls/lua/jdtls.lua:1185: in function 'open_classfile'
        [string ":lua"]:1: in main chunk
        [C]: in function 'bufload'
        /usr/share/nvim/runtime/lua/vim/lsp/util.lua:272: in function 'get_lines'
        /usr/share/nvim/runtime/lua/vim/lsp/util.lua:1822: in function 'locations_to_items'
        /usr/share/nvim/runtime/lua/vim/lsp/handlers.lua:398: in function 'handler'
        /usr/share/nvim/runtime/lua/vim/lsp.lua:1393: in function ''
        vim/_editor.lua: in function <vim/_editor.lua:0>
stack traceback:
        [C]: in function 'bufload'
        /usr/share/nvim/runtime/lua/vim/lsp/util.lua:272: in function 'get_lines'
        /usr/share/nvim/runtime/lua/vim/lsp/util.lua:1822: in function 'locations_to_items'
        /usr/share/nvim/runtime/lua/vim/lsp/handlers.lua:398: in function 'handler'
        /usr/share/nvim/runtime/lua/vim/lsp.lua:1393: in function ''
        vim/_editor.lua: in function <vim/_editor.lua:0>

But if I use the ftplugin/java.lua way I get this error

Error executing vim.schedule lua callback: BufReadCmd Autocommands for "jdt://*": Vim(lua):E5108: Error executing lua
/home/sebas/.local/share/nvim/lazy/nvim-jdtls/lua/jdtls.lua:1179: BufReadCmd Autocommands for "jdt://*"..FileType Auto
commands for "*"..function <SNR>1_LoadFTPlugin[19]..script /home/sebas/.dotfiles/.config/nvim/ftplugin/java.lua: Vim(r
untime):E5113: Error while calling lua chunk: /home/sebas/.dotfiles/.config/nvim/ftplugin/java.lua:11: attempt to inde
x local 'root_dir_path' (a nil value)
stack traceback:
        /home/sebas/.dotfiles/.config/nvim/ftplugin/java.lua:11: in main chunk
        [C]: in function '__newindex'
        /home/sebas/.local/share/nvim/lazy/nvim-jdtls/lua/jdtls.lua:1179: in function 'open_classfile'
        [string ":lua"]:1: in main chunk
        [C]: in function 'bufload'
        /usr/share/nvim/runtime/lua/vim/lsp/util.lua:272: in function 'get_lines'
        /usr/share/nvim/runtime/lua/vim/lsp/util.lua:1822: in function 'locations_to_items'
        /usr/share/nvim/runtime/lua/vim/lsp/handlers.lua:398: in function 'handler'
        /usr/share/nvim/runtime/lua/vim/lsp.lua:1393: in function ''
        vim/_editor.lua: in function <vim/_editor.lua:0>
stack traceback:
        [C]: in function '__newindex'
        /home/sebas/.local/share/nvim/lazy/nvim-jdtls/lua/jdtls.lua:1179: in function 'open_classfile'
        [string ":lua"]:1: in main chunk
        [C]: in function 'bufload'
        /usr/share/nvim/runtime/lua/vim/lsp/util.lua:272: in function 'get_lines'
        /usr/share/nvim/runtime/lua/vim/lsp/util.lua:1822: in function 'locations_to_items'
        /usr/share/nvim/runtime/lua/vim/lsp/handlers.lua:398: in function 'handler'
        /usr/share/nvim/runtime/lua/vim/lsp.lua:1393: in function ''
        vim/_editor.lua: in function <vim/_editor.lua:0>
stack traceback:
        [C]: in function 'bufload'
        /usr/share/nvim/runtime/lua/vim/lsp/util.lua:272: in function 'get_lines'
        /usr/share/nvim/runtime/lua/vim/lsp/util.lua:1822: in function 'locations_to_items'
        /usr/share/nvim/runtime/lua/vim/lsp/handlers.lua:398: in function 'handler'
        /usr/share/nvim/runtime/lua/vim/lsp.lua:1393: in function ''
        vim/_editor.lua: in function <vim/_editor.lua:0>
JosefLitos commented 10 months ago

I don't experience errors, but in my case nvim tries to open up source .class file (and freezes ~ forever). I have setup:

settings.java.configuration.runtimes = {
  {
    default = true,
    path = '/usr/lib/jvm/default-runtime/',
    sources = '/usr/lib/jvm/default-runtime/lib/src.zip',
    javadoc = '/usr/share/doc/java17-openjdk/',
  }
}

But neither sources nor javadoc fields make jdtls use the actual source files (using openjdk17-src and openjdk17-doc Archlinux extra package).

idelice commented 9 months ago

I don't experience errors, but in my case nvim tries to open up source .class file (and freezes ~ forever). I have setup:

settings.java.configuration.runtimes = {
  {
    default = true,
    path = '/usr/lib/jvm/default-runtime/',
    sources = '/usr/lib/jvm/default-runtime/lib/src.zip',
    javadoc = '/usr/share/doc/java17-openjdk/',
  }
}

But neither sources nor javadoc fields make jdtls use the actual source files (using openjdk17-src and openjdk17-doc Archlinux extra package).

I experience something similar.

Going to definition for a source file freezes the terminal. I have to quit and reopen nvim before I can continue.

TheBlob42 commented 9 months ago

I experience the same error message as @xebcam My current workaround is to pin the plugin to commit 34202bc. This way I can still jump to definitions in source files.

mfussenegger commented 9 months ago

Going to definition for a source file freezes the terminal. I have to quit and reopen nvim before I can continue.

It blocks while it is retrieving the contents for a jdt:// buffer from the language server. But there is a 5 second timeout after which you should get an error if it couldn't load it in time.


I can't really reproduce the problem and I suspect some other plugins may be interferring. (Last time this came up, it turned out to be lspsaga that caused problems)

idelice commented 9 months ago

I don't experience the issue anymore. I really don't know what fixed it. Maybe latest updates from jdtls? lspsaga? idk.

TheBlob42 commented 9 months ago

I spent some time on it yesterday and found a fix for me. And from looking into the provided example code I am also sure this could fix the issue of @xebcam (as it seems to be the same).

Since f8fb45e0 nvim-jdtls supports basic functionality, like "go to definition", in decompiled class files (requires jdtls 1.22.0). From how I understand it (please correct me, if I'm wrong) entering such a file will attach the running jdtls instance to it in "single file mode". That means that any call to require('jdtls.setup').find_root({ ... }) will return nil. Therefore any code that operates on such a "root dir" variable and expecting it to not be nil will fail:

(from @xebcam provided example)

local root_dir_path = require('jdtls.setup').find_root({ '.project', '.git', 'mvnw', 'gradlew' })
local root_dir_name = root_dir_path:match("[^/]+$") -- this will FAIL for files in "single file mode"
...

In my personal config I had a similar case and upon fixing it everything works fine :partying_face: now I can finally navigate through decompiled class files. Hope this helps some users running into a similar issue

JosefLitos commented 9 months ago

I don't experience the issue anymore. I really don't know what fixed it. Maybe latest updates from jdtls? lspsaga? idk.

I don't use lspsaga and, unfortunately, still face the issue, though I assume I usually wouldn't decompile classes if I could use the available real sourcecode. But I haven't been very successful in finding any material on what other things need to be done for java sources to be used by go to definition.

xebcam commented 9 months ago

I spent some time on it yesterday and found a fix for me. And from looking into the provided example code I am also sure this could fix the issue of @xebcam (as it seems to be the same).

Since f8fb45e0 nvim-jdtls supports basic functionality, like "go to definition", in decompiled class files (requires jdtls 1.22.0). From how I understand it (please correct me, if I'm wrong) entering such a file will attach the running jdtls instance to it in "single file mode". That means that any call to require('jdtls.setup').find_root({ ... }) will return nil. Therefore any code that operates on such a "root dir" variable and expecting it to not be nil will fail:

(from @xebcam provided example)

local root_dir_path = require('jdtls.setup').find_root({ '.project', '.git', 'mvnw', 'gradlew' })
local root_dir_name = root_dir_path:match("[^/]+$") -- this will FAIL for files in "single file mode"
...

In my personal config I had a similar case and upon fixing it everything works fine 🥳 now I can finally navigate through decompiled class files. Hope this helps some users running into a similar issue

Yeah, It does have something to do with that require('jdtls.setup').find_root({ ... }) I just don't know how to make it so that jdtls doesn't fail if its nil (I'm kind of a noob. I'm sorry 😂). How did yout do it @TheBlob42?

TheBlob42 commented 9 months ago

I can try :sweat_smile: Is the above still the configuration you have? In that case I would propose the following changes (please feel free to correct me if anybody has a better/cooler/easier solution):

...
local root_dir_path = require('jdtls.setup').find_root({ '.project', '.git', 'mvnw', 'gradlew' })
-- in case of root_dir_path being nil this will return the current working directory (otherwise it returns the folder name)
local root_dir_name = vim.fn.fnamemodify(root_dir_path, ':p:h:t')
-- now this line should never fail (because root_dir_name can not be nil)
local workspace_dir = home .. '/.cache/jdtls-workspace/' .. root_dir_name
...
xebcam commented 9 months ago

Yup, that resolved the error I got when using ftplugin/java.luathis error. Now, when using ftplugin/java.lua, I can see the class and method definitions. Thank you!!! @TheBlob42 👍

Although I like using a user command to start the Jdt server, that way the server doesn't auto-start every time I open a Java file, but that error persists. Makes sense, though, given that it's not the advised way of starting nvim-jdtls.😂

xebcam commented 9 months ago

I guess I will close this now. Thanks!