summaryrefslogtreecommitdiffstats
path: root/after/ftplugin/java.lua
blob: 5a5ae446eabd009ca3b342c6aea7f65ab2d29133 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
local misc = require("core.misc")
local map, auto = misc.map, misc.auto

local jdtls = require("jdtls")
local jdtls_install = vim.fs.joinpath(vim.fn.stdpath('data'),
    "/mason/packages/jdtls")
local java_dap_install = vim.fs.joinpath(vim.fn.stdpath('data'),
    "/mason/packages/java-debug-adapter")

-- make sure to check if things with 💀 need updating
local config = {
  cmd = {
    "/usr/lib/jvm/openjdk21/bin/java", -- 💀
    "-jar", vim.fn.glob(jdtls_install.."/plugins/org.eclipse.equinox.launcher_*.jar"), -- 💀
    "-configuration", jdtls_install.."/config_linux",
    "-data", vim.fn.stdpath("cache").."/nvim-jdtls",

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

  root_dir = vim.fs.dirname(vim.fs.find({
    "gradlew",
    ".git",
    "mvnw",
    "settings.gradle",     -- Gradle (multi-project)
    "settings.gradle.kts", -- Gradle (multi-project)
    "build.xml",           -- Ant
    "pom.xml"              -- Maven
  }, { upward = true })[1]),

  on_attach = function(_, bufnr)
    jdtls.setup.add_commands()

    -- add some jdtls specific mappings
    local opts = { buffer = bufnr }
    map("n", "cri", jdtls.organize_imports, opts)
    map("n", "crv", jdtls.extract_variable, opts)
    map("n", "crc", jdtls.extract_constant, opts)
    map("x", "crv", function() jdtls.extract_variable(true) end, opts)
    map("x", "crc", function() jdtls.extract_constant(true) end, opts)
    map("x", "crm", function() jdtls.extract_method(true) end, opts)

    pcall(vim.lsp.codelens.refresh)
    auto("BufWritePost", {
      buffer = bufnr,
      desc = "refresh codelens",
      callback = function()
        pcall(vim.lsp.codelens.refresh)
      end
    })

    -- setup nvim-dap
    require("dap").adapters.java = nil -- remove any old java adapters
    jdtls.setup_dap({ hotcodereplace = "auto" })
    require("jdtls.dap").setup_dap_main_class_configs()
  end,

  -- don"t print out status messages
  handlers = {
    ["language/status"] = function() end
  },

  init_options = {
    bundles = {
      vim.fs.joinpath(java_dap_install,
        vim.fn.glob("/extension/server/com.microsoft.java.debug.plugin-*.jar",
          true)
      )
    }
  }
}

-- generate the path to the java file(s)
---@type string|nil
local cache_path = vim.fs.joinpath(vim.fn.stdpath("cache"), "/JavaVersion.class")
---@type string|nil
local src_path = vim.fs.joinpath(vim.fn.stdpath("config"), "/extras/JavaVersion.java")

-- if either path is invalid
if not cache_path or not src_path then
  return
end

--- build a cache of the JavaVersion code
local function build_cache()
  -- check if we have javac
  vim.system({ "javac" }, {}, function(out)
    if out.code == 127 then
      cache_path = nil
      return
    end

    -- compile our code
    vim.system({ "javac", src_path, "-d", vim.fn.stdpath("cache") }, {}, function(out)
      if out.code ~= 0 then
        cache_path = nil
      end
    end)
  end)
end

-- check if we have a compiled version of JavaVersion
local f, _ = io.open(cache_path, "r")
if not f then -- if we don"t have a cache
  build_cache()
else
  io.close(f)
end

local function version_check()
  -- check the java version
  local out = vim.system({
    config.cmd[1], -- use the same java executable that the lsp will be using
    (cache_path and "JavaVersion") or src_path
  }, { cwd = vim.fn.stdpath("cache"), text = true }):wait()

  -- parse the version information aquired
  local v = vim.version.parse(out.stdout)

  -- if there's an error, no version info, or the java version is
  -- less than 21 stop the lsp from starting
  if out.code ~= 0 then
    vim.notify(string.format(
      "java version check failed: exit code %s", out.code),
      vim.log.levels.ERROR, { title = misc.appid })
    vim.notify(string.format(
      "%s", vim.inspect(out.stdout)),
      vim.log.levels.ERROR, { title = misc.appid })
    return false
  elseif not v then
    vim.notify("no java version info found", vim.log.levels.ERROR,
      { title = misc.appid })
    return false
  elseif v.major < 21 then
    vim.notify(string.format(
      "java version %s < 21.0.0 Cannot run jdtls, bailing out",
      v[1] .. "." .. v[2] .. "." .. v[3]),
      vim.log.levels.ERROR, { title = misc.appid })
    return false
  end

  return true
end


-- start the jdtls with dap!
if not version_check() then
  return
end
jdtls.start_or_attach(config)