lazyvim折腾日记(10)

lazyvim 折腾日记(10)

前言

接续上一章节,我们对 java 语言在 lazy(astro)vim 中的开发进行了相关的配置\
但是在实际的使用过程中仍然存在一些问题,具体体现在

  1. 在加载 gradle project 的时候,无法识别 build.gradle 文件的变更, 导致依赖无法导入
  2. 无法自动生成模板代码,具体体现为在新建类的时候需要手动编写相关的模板语言

针对这两个问题该如何处理呢?

  1. 添加相关函数,使得 Nvim 能够自动识别依赖
  2. 配置 Cmp 插件,使得拥有自动生成代码的功能

内容

基本知识点准备

java 命令的含义

我觉得这里还有一个东西是需要阐明的,就是说,这里的 java 并不是简单的用于跑一个程序

而是用于为 eclipse 构建一个可以承载 lsp 的 jvm

所以说这里还是与一般的存在区别,针对 lsp 的启动方式

大类参数含义

序号 前缀 含义
1 -X 内存与堆栈
2 -D 系统参数设置
3 -XX JVM 垃圾回收设置

详细参数定义

序号 前缀 含义
1 -Declipse.application 设置eclipse.eclipse 的值,一般用于 eclipse(osgi) 应用程序
2 -Dosgi.bundles.defaultStartLevel 设置 osgi 模型的 log 等级
3 -Declipse.product 确定 eclipse.product 的产品属性
4 -Dlog.protocol 控制 lsp 的 logging 行为
5 -Dlog.level 控制 lsp 的 log 的打印等级
6 -javaagent 设置额外的 java 组件
7 -Xms 设置最小堆栈
8 -Xmx 设置最大堆栈

特殊参数定义

序号 前缀 含义
1 --add-modules 添加模块
2 --add-opens 打开模块(能够读取其中的方法名)
3 java.base/java.util 包名
4 java.base/java.lang 包名

OSGI framework 参数定义

序号 前缀 含义
1 -configuration OSGI 设置,本文中需要加载 linux 的设置
2 -data lsp 的 index 和 log 的存储位置

Jdtls 初始化配置参数

由于这是一个 Gradle 项目,我们需要关注与 gradle 有关的配置选项

interface GradleOption {
        annotationProcessing?: EnabledOption;
        arguments?: string[];
        enabled?: boolean;
        home?: string;
        java?: HomeOption;
        jvmArguments?: string[];
        offline?: EnabledOption;
        user?: HomeOption;
        version?: string;
        wrapper?: GradleWrapperOption;
}
interface GradleWrapperOption {
        enabled?: boolean;
        checksums?: string[];
}

其参考文档为:

initial-request

新建 vim 自定义命令

如果说自动导入不成功的话,我们需要自定义一个命令,
使得 nvim 能够接受这个命令从而手动刷新项目依赖

序号 函数 含义
1 vim.api.nvim_create_autocmd 根据事件创建一个自动执行的命令
2 vim.api.nvim_create_user_command 创建一个用户手动执行的命令

具体用法分别参考

  1. nvim_create_autocmd()
  2. nvim_create_user_command

在 lazy(astro)vim 中一般会选择放在 conifg = function 函数块中

问题分析

  1. 无法自动加载 build.gradle 文件并更新其依赖\ 原因:
    Gradle 没有进行正确配置,并且没有正确识别 gradle 项目

  2. 无法自动生成模板语法\ 原因:
    没有对 Jdtls Initoption 进行相关配置

针对以上两点问题,结合上述方法,我们可以做出如下判断

  1. 正确配置 jdtls , 从而能够正确加载 gradle 项目
    配置更大的构建内存,加快项目的编译
    配置 jdtls , 使得其能识别 gradle 项目

  2. 添加手动以及自动命令,使得 nvim 能够加载识别项目
    在 config 中添加命令

解决方案(具体的配置方法)

结合上一章节的知识点,下面放出具体的配置代码

{
  "mfussenegger/nvim-jdtls",
  lazy = true,
  ft = { "java" },
  dependencies = {
    "williamboman/mason.nvim",
    "neovim/nvim-lspconfig",
    "williamboman/mason-lspconfig.nvim",
    {
      "AstroNvim/astrolsp",
      optional = true,
      ---@type AstroLSPOpts
      opts = {
        setup_handlers = {
          ---@diagnostic disable:missing-fields
          jdtls = false,
        },
      },
    },
  },
  opts = function(_, opts)
    local utils = require "astrocore"
    local project_name = vim.fn.fnamemodify(vim.fn.getcwd(), ":p:h:t")
    local workspace_dir = vim.fn.stdpath "data" .. "/jdtls/workspace/" .. project_name
    vim.fn.mkdir(workspace_dir, "p")

    local jdtls_path = "${the path of jdtls}"

    return utils.extend_tbl(opts, {
      cmd = {
        "java",
        -- 设置 eclipse.application , 告诉 java 现在启动的是命令行 lsp
        "-Declipse.application=org.eclipse.jdt.ls.core.id1",
        -- 设置 osgi 模型的 log 等级
        "-Dosgi.bundles.defaultStartLevel=4",
        -- 使用 org.eclipse.jdt.ls.core.product 定义 eclipse.product 的产品属性
        "-Declipse.product=org.eclipse.jdt.ls.core.product",
        -- 打印 lsp 的 log
        "-Dlog.protocol=true",
        "-Dlog.level=ALL",
        "-javaagent:${the path of lombok}",
        -- 设置堆栈大小
        "-Xms1g",
        "-Xmx2g",
        -- 加载所有系统 model
        "--add-modules=ALL-SYSTEM",
        "--add-opens",
        -- 前面一个 --add-modules 是让 java 能够加载所有包,
        -- 这个 --add-opens 是让 lsp 能够解析这些包
        -- 打开 java.base/java.util 能够加载未命名包,
        "java.base/java.util=ALL-UNNAMED",
        "--add-opens",
        "java.base/java.lang=ALL-UNNAMED",
        "-jar",
        -- 这个 jar 包是 lsp 的启动器, jvm 首先启动这个 jar 包, 再通过这个 jar 包启动 jdtls
        vim.fn.glob(jdtls_path .. "/plugins/org.eclipse.equinox.launcher_*.jar"),
        "-configuration",
        jdtls_path .. "/config_linux",
        "-data",
        workspace_dir,
      },
      -- 寻找项目的根目录
      root_dir = require("jdtls.setup").find_root {
        ".git",
        "mvnw",
        "gradlew",
        "pom.xml",
        "build.gradle",
        "settings.gradle",
      },
      settings = {
        java = {
          configuration = {
            updateBuildConfiguration = "automatic",
            runtimes = {
              {
                name = "JavaSE-21",
                path = "${the path of java21}",
                default = true,
              },
              {
                name = "JavaSE-17",
                path = "${the path of java17}",
              },
              {
                name = "JavaSE-11",
                path = "${the path of java11}",
              },
            },
          },
          implementationsCodeLens = {
            enabled = true,
          },
          referencesCodeLens = {
            enabled = true,
          },
          references = {
            includeDecompiledSources = true,
          },
          format = {
            enabled = true,
          },
          -- 参考前面的资料
          import = {
            gradle = {
              enabled = true,
              wrapper = {
                enabled = true,
              },
              version = nil,
              home = nil,
              offline = {
                enabled = false,
              },
              arguments = nil,
              jvmArguments = nil,
              user = {
                home = nil,
              },
            },
            maven = {
              enabled = true,
            },
            exclusions = {
              "**/node_modules/**",
              "**/.metadata/**",
              "**/archetype-resources/**",
              "**/META-INF/maven/**",
            },
          },
        },
        signatureHelp = { enabled = true },
        completion = {
          -- 优先注入这些静态成员
          favoriteStaticMembers = {
            "org.junit.Assert.*",
            "org.junit.Assume.*",
            "org.junit.jupiter.api.Assertions.*",
            "org.junit.jupiter.api.Assumptions.*",
            "org.junit.jupiter.api.DynamicContainer.*",
            "org.junit.jupiter.api.DynamicTest.*",
          },
        },
        sources = {
          organizeImports = {
            starThreshold = 9999,
            staticStarThreshold = 9999,
          },
        },
        codeGeneration = {
          -- 定义 lsp 的 tostring 方法
          toString = {
            template = "${object.className}{${member.name()}=${member.value}, ${otherMembers}}",
          },
          useBlocks = true,
        },
      },
      init_options = {
        bundles = {
          vim.fn.glob "${the path of debug jar}",
        },
      },
    })
  end,
  config = function(_, opts)
    vim.api.nvim_create_autocmd("Filetype", {
      pattern = "java",
      callback = function()
        if opts.root_dir and opts.root_dir ~= "" then
          require("jdtls").start_or_attach(opts)
          -- 等待 LSP 启动后自动触发项目导入
          vim.defer_fn(function()
            local clients = vim.lsp.get_active_clients({ name = "jdtls" })
            if #clients > 0 then vim.notify("jdtls started, importing Gradle project...", vim.log.levels.INFO) end
          end, 3000)
        else
          require("astrocore").notify("jdtls: root_dir not found, not starting jdtls", vim.log.levels.ERROR)
        end
      end,
    })

    -- 添加用户命令来手动刷新项目
    vim.api.nvim_create_user_command("JdtlsUpdateProject", function()
      local bufnr = vim.api.nvim_get_current_buf()
      local params = {
        command = "java.projectConfiguration.update",
        arguments = { vim.uri_from_bufnr(bufnr) },
      }

      vim.lsp.buf_request(bufnr, "workspace/executeCommand", params, function(err)
        if err then
          vim.notify("Failed to update project: " .. vim.inspect(err), vim.log.levels.ERROR)
        else
          vim.notify("Java project configuration updated", vim.log.levels.INFO)
        end
      end)
    end, { desc = "Update Java project configuration" })

    -- 添加用户命令来重新导入项目
    vim.api.nvim_create_user_command("JdtlsReimport", function()
      local bufnr = vim.api.nvim_get_current_buf()
      -- 定义 lsp 命令,使得 lsp 执行'java.project.import' 命令
      local params = {
        command = "java.project.import",
      }

      vim.lsp.buf_request(bufnr, "workspace/executeCommand", params, function(err)
        if err then
          vim.notify("Failed to reimport project: " .. vim.inspect(err), vim.log.levels.ERROR)
        else
          vim.notify("Java project reimported", vim.log.levels.INFO)
        end
      end)
    end, { desc = "Reimport Java project" })

    vim.api.nvim_create_user_command("JdtClearWorkspace", function()
      local project_name = vim.fn.fnamemodify(vim.fn.getcwd(), ":p:h:t")
      local workspace_dir = vim.fn.stdpath "data" .. "/jdtls/workspace/" .. project_name

      -- 停止 jdtls
      local clients = vim.lsp.get_active_clients({ name = "jdtls" })
      for _, client in ipairs(clients) do
        client.stop()
      end

      -- 删除工作空间
      vim.fn.delete(workspace_dir, "rf")
      vim.notify("Workspace cleared. Please restart Neovim.", vim.log.levels.INFO)
    end, { desc = "Clear jdtls workspace" })
  end,
}

总结

讲述了 java 命令的具体意思以及对 jdtls 的具体配置

根据以上的调整,我的项目能够成功加载 gradle 项目

posted @ 2026-02-05 12:09  五花肉炒河粉  阅读(14)  评论(0)    收藏  举报