update
This commit is contained in:
parent
b659d61c26
commit
f4119e7818
10 changed files with 320 additions and 6 deletions
3
init.lua
3
init.lua
|
|
@ -15,7 +15,8 @@ require("user.files_utils")
|
|||
require("user.commands")
|
||||
require("user.comment")
|
||||
require("user.trouble")
|
||||
require("user.java")
|
||||
require("user.android")
|
||||
require("user.flutter")
|
||||
|
||||
return require("packer").startup(function(use)
|
||||
-- Let packer manage itself
|
||||
|
|
|
|||
BIN
jars/ktfmt.jar
Normal file
BIN
jars/ktfmt.jar
Normal file
Binary file not shown.
86
lua/user/android.lua
Normal file
86
lua/user/android.lua
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
-- lua/user/android.lua
|
||||
-- Android development support for Neovim:
|
||||
-- * exports the Android SDK env (so LSP, Gradle and :terminal jobs see it)
|
||||
-- * :Android* commands + <leader>a* keymaps for build / run / test / logcat / emulator
|
||||
--
|
||||
-- Java (nvim-jdtls) and Kotlin (JetBrains kotlin-lsp) are configured elsewhere; this
|
||||
-- module is purely the build/run/device tooling around them.
|
||||
|
||||
local sdk = vim.fn.expand("~/Android/Sdk")
|
||||
|
||||
-- 1. Make the Android SDK visible to LSP, Gradle and terminal jobs launched from nvim.
|
||||
vim.env.ANDROID_HOME = vim.env.ANDROID_HOME or sdk
|
||||
vim.env.ANDROID_SDK_ROOT = vim.env.ANDROID_SDK_ROOT or sdk
|
||||
do
|
||||
local path = vim.env.PATH or ""
|
||||
local extra = {
|
||||
sdk .. "/platform-tools", -- adb
|
||||
sdk .. "/emulator", -- emulator
|
||||
sdk .. "/cmdline-tools/latest/bin",-- sdkmanager/avdmanager
|
||||
vim.fn.expand("~/.local/bin"), -- the `android` CLI
|
||||
}
|
||||
for _, p in ipairs(extra) do
|
||||
if vim.fn.isdirectory(p) == 1 and not string.find(path, p, 1, true) then
|
||||
path = p .. ":" .. path
|
||||
end
|
||||
end
|
||||
vim.env.PATH = path
|
||||
end
|
||||
|
||||
-- 2. Locate the Gradle project root (nearest ancestor with a gradlew wrapper).
|
||||
local function gradle_root()
|
||||
local start = vim.fn.expand("%:p:h")
|
||||
if start == "" then start = vim.fn.getcwd() end
|
||||
local found = vim.fs.find("gradlew", { upward = true, path = start })
|
||||
if found and found[1] then
|
||||
return vim.fn.fnamemodify(found[1], ":h")
|
||||
end
|
||||
return vim.fn.getcwd()
|
||||
end
|
||||
|
||||
-- 3. Run a shell command in a bottom terminal split (live, scrollable output).
|
||||
local function run_in_term(shell_cmd)
|
||||
vim.cmd("botright 15split")
|
||||
vim.cmd("terminal " .. shell_cmd)
|
||||
vim.cmd("startinsert")
|
||||
end
|
||||
|
||||
local function run_gradle(args)
|
||||
run_in_term(string.format("cd %s && ./gradlew %s", vim.fn.shellescape(gradle_root()), args))
|
||||
end
|
||||
|
||||
local function run_cmd(c)
|
||||
run_in_term(string.format("cd %s && %s", vim.fn.shellescape(gradle_root()), c))
|
||||
end
|
||||
|
||||
-- 4. User commands.
|
||||
local cmd = vim.api.nvim_create_user_command
|
||||
cmd("AndroidBuild", function() run_gradle("assembleDebug") end, { desc = "Gradle assembleDebug" })
|
||||
cmd("AndroidClean", function() run_gradle("clean") end, { desc = "Gradle clean" })
|
||||
cmd("AndroidInstall", function() run_gradle("installDebug") end, { desc = "Gradle installDebug" })
|
||||
cmd("AndroidTest", function() run_gradle("testDebugUnitTest") end,{ desc = "Gradle unit tests" })
|
||||
cmd("AndroidRun", function() run_cmd("android run") end, { desc = "Deploy app (android run)" })
|
||||
cmd("AndroidDevices", function() run_cmd("adb devices -l") end, { desc = "List adb devices" })
|
||||
cmd("AndroidLogcat", function() run_cmd("adb logcat -c; adb logcat") end, { desc = "adb logcat (cleared)" })
|
||||
cmd("AndroidEmulators", function() run_cmd("android emulator list") end, { desc = "List AVDs" })
|
||||
cmd("AndroidEmulator", function(o)
|
||||
if o.args ~= "" then
|
||||
run_cmd("android emulator start " .. vim.fn.shellescape(o.args))
|
||||
else
|
||||
-- Default: start the first available AVD.
|
||||
run_cmd([[android emulator start "$("]] .. sdk .. [[/emulator/emulator" -list-avds | head -1)"]])
|
||||
end
|
||||
end, { nargs = "?", desc = "Start an emulator (optional AVD name)" })
|
||||
cmd("AndroidStopEmulator", function() run_cmd("android emulator stop") end, { desc = "Stop emulator" })
|
||||
|
||||
-- 5. Keymaps (<leader>A* = Android).
|
||||
-- NOTE: uppercase A so it does NOT clash with <leader>a (LSP code action).
|
||||
local map = vim.keymap.set
|
||||
map("n", "<leader>Ab", "<cmd>AndroidBuild<CR>", { silent = true, desc = "Android: build (assembleDebug)" })
|
||||
map("n", "<leader>Ar", "<cmd>AndroidRun<CR>", { silent = true, desc = "Android: run/deploy" })
|
||||
map("n", "<leader>Ai", "<cmd>AndroidInstall<CR>", { silent = true, desc = "Android: install" })
|
||||
map("n", "<leader>At", "<cmd>AndroidTest<CR>", { silent = true, desc = "Android: unit tests" })
|
||||
map("n", "<leader>Al", "<cmd>AndroidLogcat<CR>", { silent = true, desc = "Android: logcat" })
|
||||
map("n", "<leader>Ad", "<cmd>AndroidDevices<CR>", { silent = true, desc = "Android: devices" })
|
||||
map("n", "<leader>Ae", "<cmd>AndroidEmulator<CR>", { silent = true, desc = "Android: start emulator" })
|
||||
map("n", "<leader>Ac", "<cmd>AndroidClean<CR>", { silent = true, desc = "Android: clean" })
|
||||
|
|
@ -3,6 +3,13 @@
|
|||
local cmp = require("cmp")
|
||||
|
||||
cmp.setup({
|
||||
-- Throttle LSP completion requests.
|
||||
-- Default: no debounce → every keystroke fires a compiler pass (CPU heat).
|
||||
performance = {
|
||||
debounce = 300, -- wait 300ms after typing stops before requesting
|
||||
throttle = 500, -- max one completion request every 500ms
|
||||
max_view_entries = 30,
|
||||
},
|
||||
snippet = {
|
||||
expand = function(args)
|
||||
require("luasnip").lsp_expand(args.body)
|
||||
|
|
|
|||
63
lua/user/flutter.lua
Normal file
63
lua/user/flutter.lua
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
-- Flutter-specific Neovim configuration
|
||||
-- Keymaps for Flutter development workflow
|
||||
|
||||
local function flutter_root()
|
||||
return vim.fn.finddir("android", vim.fn.getcwd() .. ";") ~= ""
|
||||
or vim.fn.findfile("pubspec.yaml", vim.fn.getcwd() .. ";") ~= ""
|
||||
end
|
||||
|
||||
-- Create Flutter-specific user commands
|
||||
vim.api.nvim_create_user_command("FlutterRun", function()
|
||||
vim.cmd("split | terminal flutter run")
|
||||
end, {})
|
||||
|
||||
vim.api.nvim_create_user_command("FlutterClean", function()
|
||||
vim.cmd("terminal flutter clean")
|
||||
end, {})
|
||||
|
||||
vim.api.nvim_create_user_command("FlutterPubGet", function()
|
||||
vim.cmd("terminal flutter pub get")
|
||||
end, {})
|
||||
|
||||
vim.api.nvim_create_user_command("FlutterPubOutdated", function()
|
||||
vim.cmd("terminal flutter pub outdated")
|
||||
end, {})
|
||||
|
||||
vim.api.nvim_create_user_command("FlutterPubUpgrade", function()
|
||||
vim.cmd("terminal flutter pub upgrade")
|
||||
end, {})
|
||||
|
||||
vim.api.nvim_create_user_command("FlutterAnalyze", function()
|
||||
vim.cmd("terminal flutter analyze")
|
||||
end, {})
|
||||
|
||||
vim.api.nvim_create_user_command("FlutterTest", function()
|
||||
vim.cmd("terminal flutter test")
|
||||
end, {})
|
||||
|
||||
vim.api.nvim_create_user_command("FlutterBuildApk", function()
|
||||
vim.cmd("terminal flutter build apk")
|
||||
end, {})
|
||||
|
||||
vim.api.nvim_create_user_command("FlutterDevices", function()
|
||||
vim.cmd("terminal flutter devices")
|
||||
end, {})
|
||||
|
||||
-- Dart filetype-specific settings
|
||||
vim.api.nvim_create_autocmd("FileType", {
|
||||
pattern = "dart",
|
||||
callback = function()
|
||||
vim.opt_local.expandtab = true
|
||||
vim.opt_local.tabstop = 2
|
||||
vim.opt_local.shiftwidth = 2
|
||||
vim.opt_local.softtabstop = 2
|
||||
vim.opt_local.commentstring = "// %s"
|
||||
vim.opt_local.colorcolumn = "80"
|
||||
end,
|
||||
})
|
||||
|
||||
-- Open Flutter DevTools in browser
|
||||
vim.api.nvim_set_keymap("n", "<leader>fd", ":!flutter devtools<CR>", { noremap = true, silent = false, desc = "Flutter: DevTools" })
|
||||
|
||||
-- Flutter Run in a new tmux split (if tmux available)
|
||||
vim.api.nvim_set_keymap("n", "<leader>fe", ":terminal flutter emulators<CR>", { noremap = true, silent = false, desc = "Flutter: List Emulators" })
|
||||
|
|
@ -31,3 +31,4 @@ require("user.lsp_servers.ts_ls")
|
|||
require("user.lsp_servers.marksman")
|
||||
require("user.lsp_servers.kotlin_ls")
|
||||
require("user.lsp_servers.graphql")
|
||||
require("user.lsp_servers.dartls")
|
||||
|
|
|
|||
79
lua/user/lsp_servers/dartls.lua
Normal file
79
lua/user/lsp_servers/dartls.lua
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
-- Dart/Flutter LSP configuration
|
||||
-- dartls is bundled with the Dart SDK (which ships with Flutter)
|
||||
|
||||
local function get_dart_sdk_path()
|
||||
-- Try Flutter's bundled Dart SDK first
|
||||
local flutter_dart = vim.fn.expand("~/development/flutter/bin/cache/dart-sdk/bin/dart")
|
||||
if vim.fn.executable(flutter_dart) == 1 then
|
||||
return flutter_dart
|
||||
end
|
||||
-- Fall back to system dart
|
||||
return "dart"
|
||||
end
|
||||
|
||||
vim.lsp.config("dartls", {
|
||||
cmd = { get_dart_sdk_path(), "language-server", "--protocol=lsp" },
|
||||
filetypes = { "dart" },
|
||||
root_markers = { "pubspec.yaml", "pubspec.yml" },
|
||||
|
||||
-- Dart-specific settings
|
||||
settings = {
|
||||
dart = {
|
||||
-- Enable Flutter integration
|
||||
completeFunctionCalls = true,
|
||||
showTodos = true,
|
||||
runPubGetOnPubspecChanges = true,
|
||||
updateImportsOnRename = true,
|
||||
closingLabels = true,
|
||||
-- Flutter-specific
|
||||
enableSdkFormatter = true,
|
||||
lineLength = 80,
|
||||
-- Analysis
|
||||
enableSnippets = true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
-- Dart/Flutter-specific LSP attach handlers
|
||||
vim.api.nvim_create_autocmd("LspAttach", {
|
||||
callback = function(args)
|
||||
local client = vim.lsp.get_client_by_id(args.data.client_id)
|
||||
if client and client.name == "dartls" then
|
||||
local bufnr = args.buf
|
||||
|
||||
-- Flutter hot reload
|
||||
vim.keymap.set("n", "<leader>fr", function()
|
||||
vim.lsp.buf_request(bufnr, "dart/reanalyze", nil)
|
||||
vim.cmd("write")
|
||||
vim.cmd("!flutter hot-reload 2>/dev/null || flutter run --hot")
|
||||
end, { buffer = bufnr, desc = "Flutter: Hot Reload" })
|
||||
|
||||
-- Flutter hot restart
|
||||
vim.keymap.set("n", "<leader>fR", function()
|
||||
vim.cmd("write")
|
||||
vim.cmd("!flutter run --restart 2>/dev/null")
|
||||
end, { buffer = bufnr, desc = "Flutter: Hot Restart" })
|
||||
|
||||
-- Organize imports
|
||||
vim.keymap.set("n", "<leader>fo", function()
|
||||
vim.lsp.buf.execute_command({ command = "dart.organizeImports", arguments = { vim.fn.expand("%:p") } })
|
||||
end, { buffer = bufnr, desc = "Dart: Organize Imports" })
|
||||
|
||||
-- Fix all auto-fixable issues
|
||||
vim.keymap.set("n", "<leader>fa", function()
|
||||
vim.lsp.buf.code_action({
|
||||
context = { only = { "source.fixAll" } },
|
||||
apply = true,
|
||||
})
|
||||
end, { buffer = bufnr, desc = "Dart: Fix All" })
|
||||
|
||||
-- Sort members
|
||||
vim.keymap.set("n", "<leader>fs", function()
|
||||
vim.lsp.buf.execute_command({ command = "dart.sortMembers", arguments = { vim.fn.expand("%:p") } })
|
||||
end, { buffer = bufnr, desc = "Dart: Sort Members" })
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Enable the server
|
||||
vim.lsp.enable("dartls")
|
||||
|
|
@ -1,19 +1,83 @@
|
|||
-- Kotlin LSP = fwcd kotlin-language-server (installed via Mason).
|
||||
--
|
||||
-- NOTE: the JetBrains `kotlin-lsp` (intellij-server) was tried but it imports
|
||||
-- Android Gradle modules with an EMPTY set of source sets, so it resolves
|
||||
-- nothing for Android (hover/definition/references all return empty). fwcd
|
||||
-- resolves the Gradle compile classpath itself and DOES navigate Android
|
||||
-- projects, so we use it here. (kotlin-lsp remains fine for plain Kotlin/JVM.)
|
||||
--
|
||||
-- CPU/Memory notes for Android projects:
|
||||
-- - Formatting disabled in LSP capabilities — ktfmt in-process spawns a SECOND
|
||||
-- Kotlin compiler, doubling memory (OOMs even at 4GB). Formatting is handled
|
||||
-- externally by null-ls running ktfmt as a separate process.
|
||||
-- - Linting enabled — runs on the same compiler already loaded for completions,
|
||||
-- so no extra memory cost. Provides error diagnostics (red squiggles).
|
||||
-- - Semantic tokens disabled — extra compilation passes, not worth the CPU.
|
||||
-- - 500ms debounce reduces compilation frequency during typing.
|
||||
-- - Persistent tmpdir so the SQLite compilation cache survives across sessions.
|
||||
local bin = vim.fn.expand("~/.local/share/nvim/mason/bin/kotlin-language-server")
|
||||
|
||||
if vim.fn.executable(bin) == 0 then
|
||||
vim.notify("kotlin-language-server not found — run :MasonInstall kotlin-language-server",
|
||||
vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
|
||||
-- Build capabilities, then strip formatting to prevent ktfmt OOMs.
|
||||
local capabilities = require("cmp_nvim_lsp").default_capabilities()
|
||||
capabilities.textDocument.formatting = nil
|
||||
capabilities.textDocument.rangeFormatting = nil
|
||||
capabilities.textDocument.onTypeFormatting = nil
|
||||
|
||||
-- 1. Configuration
|
||||
vim.lsp.config('kotlin_language_server', {
|
||||
cmd = { "kotlin-language-server" },
|
||||
cmd = { bin },
|
||||
filetypes = { "kotlin" },
|
||||
-- Kotlin projects are usually defined by build files or git
|
||||
root_markers = { "settings.gradle", "settings.gradle.kts", "pom.xml", ".git" },
|
||||
|
||||
-- flags in lspconfig setup are now part of the general config table
|
||||
-- Kotlin/Android projects are rooted at a Gradle build file or git repo.
|
||||
-- vim.lsp.config expects callback form: function(bufnr, on_dir).
|
||||
root_dir = function(bufnr, on_dir)
|
||||
local fname = vim.api.nvim_buf_get_name(bufnr)
|
||||
local root = vim.fs.root(fname, {
|
||||
"settings.gradle.kts",
|
||||
"settings.gradle",
|
||||
"build.gradle.kts",
|
||||
"build.gradle",
|
||||
"pom.xml",
|
||||
".git",
|
||||
})
|
||||
on_dir(root or vim.fs.dirname(fname))
|
||||
end,
|
||||
|
||||
capabilities = capabilities,
|
||||
|
||||
-- Strip formatting from the server's advertised capabilities.
|
||||
-- client-side capabilities only prevent the server from expecting format
|
||||
-- requests; server-side capabilities are what vim.lsp.buf.format() actually
|
||||
-- checks. Without this, format-on-save routes through the LSP's ktfmt →
|
||||
-- second Kotlin compiler → OOM.
|
||||
on_attach = function(client)
|
||||
client.server_capabilities.documentFormattingProvider = false
|
||||
client.server_capabilities.documentRangeFormattingProvider = false
|
||||
end,
|
||||
|
||||
-- 6GB heap — Android classpath is large (163 deps + 320 source files).
|
||||
-- Persistent tmpdir so the compilation cache survives across sessions.
|
||||
-- Use Android Studio's JBR 21 — optimised GC/JIT for Kotlin workloads.
|
||||
cmd_env = {
|
||||
KOTLIN_LANGUAGE_SERVER_OPTS = "-Xmx6G -Xms512m -Djava.io.tmpdir=/home/prabhat/.cache/kotlin-ls-fwcd",
|
||||
JAVA_HOME = "/opt/android-studio/jbr",
|
||||
},
|
||||
|
||||
init_options = {
|
||||
debounceTextChanges = 150,
|
||||
debounceTextChanges = 500,
|
||||
},
|
||||
|
||||
settings = {
|
||||
kotlin = {
|
||||
linting = { enabled = true },
|
||||
completion = { enabled = true },
|
||||
semanticTokens = { enabled = false },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -16,6 +16,18 @@ local sources = {
|
|||
extra_args = { "--aosp" }, -- optional: use AOSP style formatting
|
||||
--command = "google-java-format", -- specify command if not in PATH
|
||||
}),
|
||||
-- Kotlin formatting via ktfmt — runs as separate JVM, no OOM risk.
|
||||
-- Custom formatter (not in null-ls builtins for this version).
|
||||
{
|
||||
name = "ktfmt",
|
||||
method = null_ls.methods.FORMATTING,
|
||||
filetypes = { "kotlin" },
|
||||
generator = null_ls.generator({
|
||||
command = "java",
|
||||
args = { "-jar", "/home/prabhat/.config/nvim/jars/ktfmt.jar", "-" },
|
||||
to_stdin = true,
|
||||
}),
|
||||
},
|
||||
-- Add other formatters based on your needs
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@ require("nvim-treesitter").setup({
|
|||
"javascript",
|
||||
"kotlin",
|
||||
"go",
|
||||
"dart",
|
||||
},
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue