commit 3a9bbfef9e331b636cca090aadcd5650e4879d9b Author: light7734 Date: Sat Jul 12 16:12:11 2025 +0330 add nvim diff --git a/nvim/init.lua b/nvim/init.lua new file mode 100644 index 0000000..1adcce5 --- /dev/null +++ b/nvim/init.lua @@ -0,0 +1,21 @@ +-- Core +require("_options") +require("_keymaps") +require("_plugins") + +-- Editing +require("_lsp") +require("_cmp") +require("_autopairs") + +-- Navigation +require("_telescope") +require("_nvim_tree") + +-- Aesthetics +require("_alpha") +require("_lualine") +require("_gitsigns") +require("_indentline") +require("_treesitter") +require("_gruvbox") diff --git a/nvim/lsp/clangd.lua b/nvim/lsp/clangd.lua new file mode 100644 index 0000000..6a9b431 --- /dev/null +++ b/nvim/lsp/clangd.lua @@ -0,0 +1,152 @@ +local function lsp_highlight_document(client) + if client.server_capabilities.document_highlight then + vim.api.nvim_exec( + [[ + augroup lsp_document_highlight + autocmd! * + autocmd CursorHold lua vim.lsp.buf.document_highlight() + autocmd CursorMoved lua vim.lsp.buf.clear_references() + augroup END + ]], + false + ) + end +end + +local function lsp_keymaps(bufnr) + local opts = { noremap = true, silent = true } + + vim.api.nvim_buf_set_keymap(bufnr, "n", "gd", "lua vim.lsp.buf.definition()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gD", "lua vim.lsp.buf.declaration()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gi", "lua vim.lsp.buf.implementation()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "K", "lua vim.lsp.buf.hover()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "", "lua vim.lsp.buf.signature_help()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gr", "lua vim.lsp.buf.references()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "[d", 'lua vim.diagnostic.goto_prev({border="rounded"})', opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "]d", 'lua vim.diagnostic.goto_next({border="rounded"})', opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "lr", "lua vim.lsp.buf.rename()", opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "q", "lua vim.diagnostic.setloclist()", opts) + + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "td", + "lua require 'telescope.builtin'.diagnostics()", + opts + ) + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "tr", + "lua require 'telescope.builtin'.lsp_references()", + opts + ) +end + +local status_ok, cmp_nvim_lsp = pcall(require, "cmp_nvim_lsp") +if not status_ok then + print("Failed to require cmp_nvim_lsp") + return +end + +local client_capabilities = vim.lsp.protocol.make_client_capabilities() +local capabilities = cmp_nvim_lsp.default_capabilities(client_capabilities) +capabilities.offsetEncoding = { "utf-8", "utf-16" } +capabilities.textDocument.completion.editsNearCursor = true + +---@brief +--- +--- https://clangd.llvm.org/installation.html +--- +--- - **NOTE:** Clang >= 11 is recommended! See [#23](https://github.com/neovim/nvim-lspconfig/issues/23). +--- - If `compile_commands.json` lives in a build directory, you should +--- symlink it to the root of your source tree. +--- ``` +--- ln -s /path/to/myproject/build/compile_commands.json /path/to/myproject/ +--- ``` +--- - clangd relies on a [JSON compilation database](https://clang.llvm.org/docs/JSONCompilationDatabase.html) +--- specified as compile_commands.json, see https://clangd.llvm.org/installation#compile_commandsjson + +-- https://clangd.llvm.org/extensions.html#switch-between-sourceheader +local function switch_source_header(bufnr) + local method_name = 'textDocument/switchSourceHeader' + local client = vim.lsp.get_clients({ bufnr = bufnr, name = 'clangd' })[1] + if not client then + return vim.notify(('method %s is not supported by any servers active on the current buffer'):format(method_name)) + end + local params = vim.lsp.util.make_text_document_params(bufnr) + client.request(method_name, params, function(err, result) + if err then + error(tostring(err)) + end + if not result then + vim.notify('corresponding file cannot be determined') + return + end + vim.cmd.edit(vim.uri_to_fname(result)) + end, bufnr) +end + +local function symbol_info() + local bufnr = vim.api.nvim_get_current_buf() + local clangd_client = vim.lsp.get_clients({ bufnr = bufnr, name = 'clangd' })[1] + if not clangd_client or not clangd_client.supports_method 'textDocument/symbolInfo' then + return vim.notify('Clangd client not found', vim.log.levels.ERROR) + end + local win = vim.api.nvim_get_current_win() + local params = vim.lsp.util.make_position_params(win, clangd_client.offset_encoding) + clangd_client.request('textDocument/symbolInfo', params, function(err, res) + if err or #res == 0 then + -- Clangd always returns an error, there is not reason to parse it + return + end + local container = string.format('container: %s', res[1].containerName) ---@type string + local name = string.format('name: %s', res[1].name) ---@type string + vim.lsp.util.open_floating_preview({ name, container }, '', { + height = 2, + width = math.max(string.len(name), string.len(container)), + focusable = false, + focus = false, + border = 'single', + title = 'Symbol Info', + }) + end, bufnr) +end + +return { + cmd = { 'clangd' }, + filetypes = { 'c', 'cpp', 'objc', 'objcpp', 'cuda', 'proto' }, + root_markers = { + '.clangd', + '.clang-tidy', + '.clang-format', + 'compile_commands.json', + 'compile_flags.txt', + 'configure.ac', -- AutoTools + '.git', + }, + capabilities = capabilities, + on_attach = function(client, bufnr) + lsp_keymaps(bufnr) + lsp_highlight_document(client) + + vim.api.nvim_clear_autocmds({ group = augroup, buffer = bufnr }) + vim.api.nvim_create_autocmd("BufWritePre", { + group = augroup, + buffer = bufnr, + callback = function() + vim.lsp.buf.format({ async = false }) + end, + }) + + vim.api.nvim_buf_create_user_command(0, 'LspClangdSwitchSourceHeader', function() + switch_source_header(0) + end, { desc = 'Switch between source/header' }) + + vim.api.nvim_buf_create_user_command(0, 'LspClangdShowSymbolInfo', function() + symbol_info() + end, { desc = 'Show symbol info' }) + end, +} diff --git a/nvim/lsp/cssls.lua b/nvim/lsp/cssls.lua new file mode 100644 index 0000000..6b7bf9f --- /dev/null +++ b/nvim/lsp/cssls.lua @@ -0,0 +1,112 @@ +local function lsp_highlight_document(client) + if client.server_capabilities.document_highlight then + vim.api.nvim_create_augroup("lsp_document_highlight", { clear = true }) + + vim.api.nvim_create_autocmd("CursorHold", { + group = "lsp_document_highlight", + buffer = 0, + callback = function() + vim.lsp.buf.document_highlight() + end, + }) + + vim.api.nvim_create_autocmd("CursorMoved", { + group = "lsp_document_highlight", + buffer = 0, + callback = function() + vim.lsp.buf.clear_references() + end, + }) + end +end + +local function lsp_keymaps(bufnr) + local opts = { noremap = true, silent = true } + + vim.api.nvim_buf_set_keymap(bufnr, "n", "gd", "lua vim.lsp.buf.definition()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gD", "lua vim.lsp.buf.declaration()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gi", "lua vim.lsp.buf.implementation()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "K", "lua vim.lsp.buf.hover()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "", "lua vim.lsp.buf.signature_help()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gr", "lua vim.lsp.buf.references()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "[d", 'lua vim.diagnostic.goto_prev({border="rounded"})', opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "]d", 'lua vim.diagnostic.goto_next({border="rounded"})', opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "lr", "lua vim.lsp.buf.rename()", opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "q", "lua vim.diagnostic.setloclist()", opts) + + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "td", + "lua require 'telescope.builtin'.diagnostics()", + opts + ) + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "tr", + "lua require 'telescope.builtin'.lsp_references()", + opts + ) +end + +local status_ok, cmp_nvim_lsp = pcall(require, "cmp_nvim_lsp") +if not status_ok then + print("Failed to require cmp_nvim_lsp") + return +end + +local client_capabilities = vim.lsp.protocol.make_client_capabilities() +local capabilities = cmp_nvim_lsp.default_capabilities(client_capabilities) +capabilities.offsetEncoding = { "utf-8", "utf-16" } + +---@brief +--- +--- https://github.com/hrsh7th/vscode-langservers-extracted +--- +--- `css-languageserver` can be installed via `npm`: +--- +--- ```sh +--- npm i -g vscode-langservers-extracted +--- ``` +--- +--- Neovim does not currently include built-in snippets. `vscode-css-language-server` only provides completions when snippet support is enabled. To enable completion, install a snippet plugin and add the following override to your language client capabilities during setup. +--- +--- ```lua +--- --Enable (broadcasting) snippet capability for completion +--- local capabilities = vim.lsp.protocol.make_client_capabilities() +--- capabilities.textDocument.completion.completionItem.snippetSupport = true +--- +--- vim.lsp.config('cssls', { +--- capabilities = capabilities, +--- }) +--- ``` +return { + cmd = { 'vscode-css-language-server', '--stdio' }, + filetypes = { 'css', 'scss', 'less' }, + init_options = { provideFormatter = true }, -- needed to enable formatting capabilities + root_markers = { 'package.json', '.git' }, + settings = { + css = { validate = true }, + scss = { validate = true }, + less = { validate = true }, + }, + capabilities = capabilities, + on_attach = function(client, bufnr) + lsp_keymaps(bufnr) + lsp_highlight_document(client) + + if client.supports_method("textDocument/formatting") then + vim.api.nvim_clear_autocmds({ group = augroup, buffer = bufnr }) + vim.api.nvim_create_autocmd("BufWritePre", { + group = augroup, + buffer = bufnr, + callback = function() + vim.lsp.buf.format() + end, + }) + end + end, +} diff --git a/nvim/lsp/eslint.lua b/nvim/lsp/eslint.lua new file mode 100644 index 0000000..864a9eb --- /dev/null +++ b/nvim/lsp/eslint.lua @@ -0,0 +1,256 @@ +local function lsp_highlight_document(client) + if client.server_capabilities.document_highlight then + vim.api.nvim_create_augroup("lsp_document_highlight", { clear = true }) + + vim.api.nvim_create_autocmd("CursorHold", { + group = "lsp_document_highlight", + buffer = 0, + callback = function() + vim.lsp.buf.document_highlight() + end, + }) + + vim.api.nvim_create_autocmd("CursorMoved", { + group = "lsp_document_highlight", + buffer = 0, + callback = function() + vim.lsp.buf.clear_references() + end, + }) + end +end + +local function lsp_keymaps(bufnr) + local opts = { noremap = true, silent = true } + + vim.api.nvim_buf_set_keymap(bufnr, "n", "gd", "lua vim.lsp.buf.definition()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gD", "lua vim.lsp.buf.declaration()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gi", "lua vim.lsp.buf.implementation()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "K", "lua vim.lsp.buf.hover()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "", "lua vim.lsp.buf.signature_help()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gr", "lua vim.lsp.buf.references()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "[d", 'lua vim.diagnostic.goto_prev({border="rounded"})', opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "]d", 'lua vim.diagnostic.goto_next({border="rounded"})', opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "lr", "lua vim.lsp.buf.rename()", opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "q", "lua vim.diagnostic.setloclist()", opts) + + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "td", + "lua require 'telescope.builtin'.diagnostics()", + opts + ) + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "tr", + "lua require 'telescope.builtin'.lsp_references()", + opts + ) +end + +local status_ok, cmp_nvim_lsp = pcall(require, "cmp_nvim_lsp") +if not status_ok then + print("Failed to require cmp_nvim_lsp") + return +end + +local client_capabilities = vim.lsp.protocol.make_client_capabilities() +local capabilities = cmp_nvim_lsp.default_capabilities(client_capabilities) +capabilities.offsetEncoding = { "utf-8", "utf-16" } + +--- @brief +--- +--- https://github.com/hrsh7th/vscode-langservers-extracted +--- +--- `vscode-eslint-language-server` is a linting engine for JavaScript / Typescript. +--- It can be installed via `npm`: +--- +--- ```sh +--- npm i -g vscode-langservers-extracted +--- ``` +--- +--- `vscode-eslint-language-server` provides an `EslintFixAll` command that can be used to format a document on save: +--- ```lua +--- vim.lsp.config('eslint', { +--- --- ... +--- on_attach = function(client, bufnr) +--- vim.api.nvim_create_autocmd("BufWritePre", { +--- buffer = bufnr, +--- command = "EslintFixAll", +--- }) +--- end, +--- }) +--- ``` +--- +--- See [vscode-eslint](https://github.com/microsoft/vscode-eslint/blob/55871979d7af184bf09af491b6ea35ebd56822cf/server/src/eslintServer.ts#L216-L229) for configuration options. +--- +--- Messages handled in lspconfig: `eslint/openDoc`, `eslint/confirmESLintExecution`, `eslint/probeFailed`, `eslint/noLibrary` +--- +--- Additional messages you can handle: `eslint/noConfig` + +local lsp = vim.lsp + +return { + cmd = { 'vscode-eslint-language-server', '--stdio' }, + filetypes = { + 'javascript', + 'javascriptreact', + 'javascript.jsx', + 'typescript', + 'typescriptreact', + 'typescript.tsx', + 'vue', + 'svelte', + 'astro', + }, + on_attach = function(client, bufnr) + lsp_keymaps(bufnr) + lsp_highlight_document(client) + + vim.api.nvim_buf_create_user_command(0, 'LspEslintFixAll', function() + local bufnr = vim.api.nvim_get_current_buf() + + client:exec_cmd({ + title = 'Fix all Eslint errors for current buffer', + command = 'eslint.applyAllFixes', + arguments = { + { + uri = vim.uri_from_bufnr(bufnr), + version = lsp.util.buf_versions[bufnr], + }, + }, + }, { bufnr = bufnr }) + end, {}) + + vim.api.nvim_create_autocmd("BufWritePre", { + buffer = bufnr, + command = "LspEslintFixAll", + }) + end, + -- https://eslint.org/docs/user-guide/configuring/configuration-files#configuration-file-formats + root_dir = function(bufnr, on_dir) + local root_file_patterns = { + '.eslintrc', + '.eslintrc.js', + '.eslintrc.cjs', + '.eslintrc.yaml', + '.eslintrc.yml', + '.eslintrc.json', + 'eslint.config.js', + 'eslint.config.mjs', + 'eslint.config.cjs', + 'eslint.config.ts', + 'eslint.config.mts', + 'eslint.config.cts', + '.git', + 'package.json', + 'package-lock.json', + '.prettierrc', + } + + local fname = vim.api.nvim_buf_get_name(bufnr) + local root_dir = vim.fs.dirname(vim.fs.find(root_file_patterns, { path = fname, upward = true })[1]) + on_dir(root_dir) + end, + -- Refer to https://github.com/Microsoft/vscode-eslint#settings-options for documentation. + settings = { + validate = 'on', + packageManager = nil, + useESLintClass = false, + experimental = { + useFlatConfig = false, + }, + codeActionOnSave = { + enable = false, + mode = 'all', + }, + format = true, + quiet = false, + onIgnoredFiles = 'off', + rulesCustomizations = {}, + run = 'onType', + problems = { + shortenToSingleLine = false, + }, + -- nodePath configures the directory in which the eslint server should start its node_modules resolution. + -- This path is relative to the workspace folder (root dir) of the server instance. + nodePath = '', + -- use the workspace folder location or the file location (if no workspace folder is open) as the working directory + workingDirectory = { mode = 'location' }, + codeAction = { + disableRuleComment = { + enable = true, + location = 'separateLine', + }, + showDocumentation = { + enable = true, + }, + }, + }, + before_init = function(_, config) + -- The "workspaceFolder" is a VSCode concept. It limits how far the + -- server will traverse the file system when locating the ESLint config + -- file (e.g., .eslintrc). + local root_dir = config.root_dir + + if root_dir then + config.settings = config.settings or {} + config.settings.workspaceFolder = { + uri = root_dir, + name = vim.fn.fnamemodify(root_dir, ':t'), + } + + -- Support flat config + local flat_config_files = { + 'eslint.config.js', + 'eslint.config.mjs', + 'eslint.config.cjs', + 'eslint.config.ts', + 'eslint.config.mts', + 'eslint.config.cts', + } + + for _, file in ipairs(flat_config_files) do + if vim.fn.filereadable(root_dir .. '/' .. file) == 1 then + config.settings.experimental = config.settings.experimental or {} + config.settings.experimental.useFlatConfig = true + break + end + end + + -- Support Yarn2 (PnP) projects + local pnp_cjs = root_dir .. '/.pnp.cjs' + local pnp_js = root_dir .. '/.pnp.js' + if vim.uv.fs_stat(pnp_cjs) or vim.uv.fs_stat(pnp_js) then + local cmd = config.cmd + config.cmd = vim.list_extend({ 'yarn', 'exec' }, cmd) + end + end + end, + handlers = { + ['eslint/openDoc'] = function(_, result) + if result then + vim.ui.open(result.url) + end + return {} + end, + ['eslint/confirmESLintExecution'] = function(_, result) + if not result then + return + end + return 4 -- approved + end, + ['eslint/probeFailed'] = function() + vim.notify('[lspconfig] ESLint probe failed.', vim.log.levels.WARN) + return {} + end, + ['eslint/noLibrary'] = function() + vim.notify('[lspconfig] Unable to find ESLint library.', vim.log.levels.WARN) + return {} + end, + }, +} diff --git a/nvim/lsp/lua_ls.lua b/nvim/lsp/lua_ls.lua new file mode 100644 index 0000000..2fa7340 --- /dev/null +++ b/nvim/lsp/lua_ls.lua @@ -0,0 +1,176 @@ +local function lsp_highlight_document(client) + if client.server_capabilities.document_highlight then + vim.api.nvim_create_augroup("lsp_document_highlight", { clear = true }) + + vim.api.nvim_create_autocmd("CursorHold", { + group = "lsp_document_highlight", + buffer = 0, + callback = function() + vim.lsp.buf.document_highlight() + end, + }) + + vim.api.nvim_create_autocmd("CursorMoved", { + group = "lsp_document_highlight", + buffer = 0, + callback = function() + vim.lsp.buf.clear_references() + end, + }) + end +end + +local function lsp_keymaps(bufnr) + local opts = { noremap = true, silent = true } + + vim.api.nvim_buf_set_keymap(bufnr, "n", "gd", "lua vim.lsp.buf.definition()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gD", "lua vim.lsp.buf.declaration()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gi", "lua vim.lsp.buf.implementation()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "K", "lua vim.lsp.buf.hover()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "", "lua vim.lsp.buf.signature_help()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gr", "lua vim.lsp.buf.references()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "[d", 'lua vim.diagnostic.goto_prev({border="rounded"})', opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "]d", 'lua vim.diagnostic.goto_next({border="rounded"})', opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "lr", "lua vim.lsp.buf.rename()", opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "q", "lua vim.diagnostic.setloclist()", opts) + + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "td", + "lua require 'telescope.builtin'.diagnostics()", + opts + ) + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "tr", + "lua require 'telescope.builtin'.lsp_references()", + opts + ) +end + +local status_ok, cmp_nvim_lsp = pcall(require, "cmp_nvim_lsp") +if not status_ok then + print("Failed to require cmp_nvim_lsp") + return +end + +local client_capabilities = vim.lsp.protocol.make_client_capabilities() +local capabilities = cmp_nvim_lsp.default_capabilities(client_capabilities) +capabilities.offsetEncoding = { "utf-8", "utf-16" } +capabilities.textDocument.completion.editsNearCursor = true + +---@brief +--- +--- https://github.com/luals/lua-language-server +--- +--- Lua language server. +--- +--- `lua-language-server` can be installed by following the instructions [here](https://luals.github.io/#neovim-install). +--- +--- The default `cmd` assumes that the `lua-language-server` binary can be found in `$PATH`. +--- +--- If you primarily use `lua-language-server` for Neovim, and want to provide completions, +--- analysis, and location handling for plugins on runtime path, you can use the following +--- settings. +--- +--- ```lua +--- vim.lsp.config('lua_ls', { +--- on_init = function(client) +--- if client.workspace_folders then +--- local path = client.workspace_folders[1].name +--- if path ~= vim.fn.stdpath('config') and (vim.uv.fs_stat(path..'/.luarc.json') or vim.uv.fs_stat(path..'/.luarc.jsonc')) then +--- return +--- end +--- end +--- +--- client.config.settings.Lua = vim.tbl_deep_extend('force', client.config.settings.Lua, { +--- runtime = { +--- -- Tell the language server which version of Lua you're using +--- -- (most likely LuaJIT in the case of Neovim) +--- version = 'LuaJIT' +--- }, +--- -- Make the server aware of Neovim runtime files +--- workspace = { +--- checkThirdParty = false, +--- library = { +--- vim.env.VIMRUNTIME +--- -- Depending on the usage, you might want to add additional paths here. +--- -- "${3rd}/luv/library" +--- -- "${3rd}/busted/library", +--- } +--- -- or pull in all of 'runtimepath'. NOTE: this is a lot slower and will cause issues when working on your own configuration (see https://github.com/neovim/nvim-lspconfig/issues/3189) +--- -- library = vim.api.nvim_get_runtime_file("", true) +--- } +--- }) +--- end, +--- settings = { +--- Lua = {} +--- } +--- }) +--- ``` +--- +--- See `lua-language-server`'s [documentation](https://luals.github.io/wiki/settings/) for an explanation of the above fields: +--- * [Lua.runtime.path](https://luals.github.io/wiki/settings/#runtimepath) +--- * [Lua.workspace.library](https://luals.github.io/wiki/settings/#workspacelibrary) +--- +return { + cmd = { 'lua-language-server' }, + filetypes = { 'lua' }, + root_markers = { + '.luarc.json', + '.luarc.jsonc', + '.luacheckrc', + '.stylua.toml', + 'stylua.toml', + 'selene.toml', + 'selene.yml', + '.git', + }, + + settings = { + Lua = { + runtime = { + -- Tell the language server which version of Lua you're using + -- (most likely LuaJIT in the case of Neovim) + version = 'LuaJIT' + }, + + diagnostics = { + -- Get the language server to recognize the `vim` global + globals = { "vim" }, + }, + + -- Make the server aware of Neovim runtime files + workspace = { + checkThirdParty = false, + library = vim.api.nvim_get_runtime_file("", true) + }, + + -- Do not send telemetry data containing a randomized but unique identifier + telemetry = { + enable = false, + }, + } + }, + + capabilities = capabilities, + on_attach = function(client, bufnr) + lsp_keymaps(bufnr) + lsp_highlight_document(client) + + if client.supports_method("textDocument/formatting") then + vim.api.nvim_clear_autocmds({ group = augroup, buffer = bufnr }) + vim.api.nvim_create_autocmd("BufWritePre", { + group = augroup, + buffer = bufnr, + callback = function() + vim.lsp.buf.format() + end, + }) + end + end, +} diff --git a/nvim/lsp/mdx_analyzer.lua b/nvim/lsp/mdx_analyzer.lua new file mode 100644 index 0000000..b093e9b --- /dev/null +++ b/nvim/lsp/mdx_analyzer.lua @@ -0,0 +1,90 @@ +local function lsp_highlight_document(client) + if client.server_capabilities.document_highlight then + vim.api.nvim_create_augroup("lsp_document_highlight", { clear = true }) + + vim.api.nvim_create_autocmd("CursorHold", { + group = "lsp_document_highlight", + buffer = 0, + callback = function() + vim.lsp.buf.document_highlight() + end, + }) + + vim.api.nvim_create_autocmd("CursorMoved", { + group = "lsp_document_highlight", + buffer = 0, + callback = function() + vim.lsp.buf.clear_references() + end, + }) + end +end + +local function lsp_keymaps(bufnr) + local opts = { noremap = true, silent = true } + + vim.api.nvim_buf_set_keymap(bufnr, "n", "gd", "lua vim.lsp.buf.definition()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gD", "lua vim.lsp.buf.declaration()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gi", "lua vim.lsp.buf.implementation()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "K", "lua vim.lsp.buf.hover()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "", "lua vim.lsp.buf.signature_help()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gr", "lua vim.lsp.buf.references()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "[d", 'lua vim.diagnostic.goto_prev({border="rounded"})', opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "]d", 'lua vim.diagnostic.goto_next({border="rounded"})', opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "lr", "lua vim.lsp.buf.rename()", opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "q", "lua vim.diagnostic.setloclist()", opts) + + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "td", + "lua require 'telescope.builtin'.diagnostics()", + opts + ) + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "tr", + "lua require 'telescope.builtin'.lsp_references()", + opts + ) +end + +local status_ok, cmp_nvim_lsp = pcall(require, "cmp_nvim_lsp") +if not status_ok then + print("Failed to require cmp_nvim_lsp") + return +end + +local client_capabilities = vim.lsp.protocol.make_client_capabilities() +local capabilities = cmp_nvim_lsp.default_capabilities(client_capabilities) +capabilities.offsetEncoding = { "utf-8", "utf-16" } + +local util = require 'lspconfig.util' +return { + default_config = { + cmd = { 'mdx-language-server', '--stdio' }, + filetypes = { 'mdx', 'markdown', 'svx' }, + root_dir = util.root_pattern 'package.json', + single_file_support = true, + settings = {}, + init_options = { + typescript = {}, + }, + on_new_config = function(new_config, new_root_dir) + if vim.tbl_get(new_config.init_options, 'typescript') and not new_config.init_options.typescript.tsdk then + new_config.init_options.typescript.tsdk = util.get_typescript_server_path(new_root_dir) + end + end, + }, + commands = {}, + docs = { + description = [[ +https://github.com/mdx-js/mdx-analyzer + +`mdx-analyzer`, a language server for MDX +]], + }, +} diff --git a/nvim/lsp/svelte.lua b/nvim/lsp/svelte.lua new file mode 100644 index 0000000..70916ca --- /dev/null +++ b/nvim/lsp/svelte.lua @@ -0,0 +1,93 @@ +local function lsp_highlight_document(client) + if client.server_capabilities.document_highlight then + vim.api.nvim_create_augroup("lsp_document_highlight", { clear = true }) + + vim.api.nvim_create_autocmd("CursorHold", { + group = "lsp_document_highlight", + buffer = 0, + callback = function() + vim.lsp.buf.document_highlight() + end, + }) + + vim.api.nvim_create_autocmd("CursorMoved", { + group = "lsp_document_highlight", + buffer = 0, + callback = function() + vim.lsp.buf.clear_references() + end, + }) + end +end + +local function lsp_keymaps(bufnr) + local opts = { noremap = true, silent = true } + + vim.api.nvim_buf_set_keymap(bufnr, "n", "gd", "lua vim.lsp.buf.definition()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gD", "lua vim.lsp.buf.declaration()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gi", "lua vim.lsp.buf.implementation()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "K", "lua vim.lsp.buf.hover()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "", "lua vim.lsp.buf.signature_help()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gr", "lua vim.lsp.buf.references()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "[d", 'lua vim.diagnostic.goto_prev({border="rounded"})', opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "]d", 'lua vim.diagnostic.goto_next({border="rounded"})', opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "lr", "lua vim.lsp.buf.rename()", opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "q", "lua vim.diagnostic.setloclist()", opts) + + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "td", + "lua require 'telescope.builtin'.diagnostics()", + opts + ) + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "tr", + "lua require 'telescope.builtin'.lsp_references()", + opts + ) +end + +local status_ok, cmp_nvim_lsp = pcall(require, "cmp_nvim_lsp") +if not status_ok then + print("Failed to require cmp_nvim_lsp") + return +end + +local client_capabilities = vim.lsp.protocol.make_client_capabilities() +local capabilities = cmp_nvim_lsp.default_capabilities(client_capabilities) +capabilities.offsetEncoding = { "utf-8", "utf-16" } + + +---@brief +--- +--- https://github.com/sveltejs/language-tools/tree/master/packages/language-server +--- +--- Note: assuming that [ts_ls](#ts_ls) is setup, full JavaScript/TypeScript support (find references, rename, etc of symbols in Svelte files when working in JS/TS files) requires per-project installation and configuration of [typescript-svelte-plugin](https://github.com/sveltejs/language-tools/tree/master/packages/typescript-plugin#usage). +--- +--- `svelte-language-server` can be installed via `npm`: +--- ```sh +--- npm install -g svelte-language-server +--- ``` + +return { + cmd = { 'svelteserver', '--stdio' }, + filetypes = { 'svelte' }, + root_markers = { 'package.json', '.git' }, + capabilities = capabilities, + on_attach = function(client, bufnr) + lsp_keymaps(bufnr) + lsp_highlight_document(client) + + vim.api.nvim_buf_create_user_command(bufnr, 'LspMigrateToSvelte5', function() + client:exec_cmd({ + command = 'migrate_to_svelte_5', + arguments = { vim.uri_from_bufnr(bufnr) }, + }) + end, { desc = 'Migrate Component to Svelte 5 Syntax' }) + end, +} diff --git a/nvim/lsp/tailwindcss.lua b/nvim/lsp/tailwindcss.lua new file mode 100644 index 0000000..08723f8 --- /dev/null +++ b/nvim/lsp/tailwindcss.lua @@ -0,0 +1,192 @@ +local function lsp_highlight_document(client) + if client.server_capabilities.document_highlight then + vim.api.nvim_create_augroup("lsp_document_highlight", { clear = true }) + + vim.api.nvim_create_autocmd("CursorHold", { + group = "lsp_document_highlight", + buffer = 0, + callback = function() + vim.lsp.buf.document_highlight() + end, + }) + + vim.api.nvim_create_autocmd("CursorMoved", { + group = "lsp_document_highlight", + buffer = 0, + callback = function() + vim.lsp.buf.clear_references() + end, + }) + end +end + +local function lsp_keymaps(bufnr) + local opts = { noremap = true, silent = true } + + vim.api.nvim_buf_set_keymap(bufnr, "n", "gd", "lua vim.lsp.buf.definition()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gD", "lua vim.lsp.buf.declaration()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gi", "lua vim.lsp.buf.implementation()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "K", "lua vim.lsp.buf.hover()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "", "lua vim.lsp.buf.signature_help()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gr", "lua vim.lsp.buf.references()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "[d", 'lua vim.diagnostic.goto_prev({border="rounded"})', opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "]d", 'lua vim.diagnostic.goto_next({border="rounded"})', opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "lr", "lua vim.lsp.buf.rename()", opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "q", "lua vim.diagnostic.setloclist()", opts) + + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "td", + "lua require 'telescope.builtin'.diagnostics()", + opts + ) + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "tr", + "lua require 'telescope.builtin'.lsp_references()", + opts + ) +end + +local status_ok, cmp_nvim_lsp = pcall(require, "cmp_nvim_lsp") +if not status_ok then + print("Failed to require cmp_nvim_lsp") + return +end + +local client_capabilities = vim.lsp.protocol.make_client_capabilities() +local capabilities = cmp_nvim_lsp.default_capabilities(client_capabilities) +capabilities.offsetEncoding = { "utf-8", "utf-16" } + +---@brief +--- https://github.com/tailwindlabs/tailwindcss-intellisense +--- +--- Tailwind CSS Language Server can be installed via npm: +--- +--- npm install -g @tailwindcss/language-server + +return { + cmd = { 'tailwindcss-language-server', '--stdio' }, + -- filetypes copied and adjusted from tailwindcss-intellisense + filetypes = { + -- html + 'aspnetcorerazor', + 'astro', + 'astro-markdown', + 'blade', + 'clojure', + 'django-html', + 'htmldjango', + 'edge', + 'eelixir', -- vim ft + 'elixir', + 'ejs', + 'erb', + 'eruby', -- vim ft + 'gohtml', + 'gohtmltmpl', + 'haml', + 'handlebars', + 'hbs', + 'html', + 'htmlangular', + 'html-eex', + 'heex', + 'jade', + 'leaf', + 'liquid', + 'markdown', + 'mdx', + 'mustache', + 'njk', + 'nunjucks', + 'php', + 'razor', + 'slim', + 'twig', + -- css + 'css', + 'less', + 'postcss', + 'sass', + 'scss', + 'stylus', + 'sugarss', + -- js + 'javascript', + 'javascriptreact', + 'reason', + 'rescript', + 'typescript', + 'typescriptreact', + -- mixed + 'vue', + 'svelte', + 'templ', + }, + settings = { + tailwindCSS = { + validate = true, + lint = { + cssConflict = 'warning', + invalidApply = 'error', + invalidScreen = 'error', + invalidVariant = 'error', + invalidConfigPath = 'error', + invalidTailwindDirective = 'error', + recommendedVariantOrder = 'warning', + }, + classAttributes = { + 'class', + 'className', + 'class:list', + 'classList', + 'ngClass', + }, + includeLanguages = { + eelixir = 'html-eex', + eruby = 'erb', + templ = 'html', + htmlangular = 'html', + }, + }, + }, + before_init = function(_, config) + if not config.settings then + config.settings = {} + end + if not config.settings.editor then + config.settings.editor = {} + end + if not config.settings.editor.tabSize then + config.settings.editor.tabSize = vim.lsp.util.get_effective_tabstop() + end + end, + workspace_required = true, + root_dir = function(bufnr, on_dir) + local root_files = { + 'tailwind.config.js', + 'tailwind.config.cjs', + 'tailwind.config.mjs', + 'tailwind.config.ts', + 'postcss.config.js', + 'postcss.config.cjs', + 'postcss.config.mjs', + 'postcss.config.ts', + 'package.json', + } + local fname = vim.api.nvim_buf_get_name(bufnr) + on_dir(vim.fs.dirname(vim.fs.find(root_files, { path = fname, upward = true })[1])) + end, + + capabilities = capabilities, + + on_attach = function(client, bufnr) + lsp_keymaps(bufnr) + lsp_highlight_document(client) + end, +} diff --git a/nvim/lsp/ts_ls.lua b/nvim/lsp/ts_ls.lua new file mode 100644 index 0000000..f29eaef --- /dev/null +++ b/nvim/lsp/ts_ls.lua @@ -0,0 +1,149 @@ +local function lsp_highlight_document(client) + if client.server_capabilities.document_highlight then + vim.api.nvim_create_augroup("lsp_document_highlight", { clear = true }) + + vim.api.nvim_create_autocmd("CursorHold", { + group = "lsp_document_highlight", + buffer = 0, + callback = function() + vim.lsp.buf.document_highlight() + end, + }) + + vim.api.nvim_create_autocmd("CursorMoved", { + group = "lsp_document_highlight", + buffer = 0, + callback = function() + vim.lsp.buf.clear_references() + end, + }) + end +end + +local function lsp_keymaps(bufnr) + local opts = { noremap = true, silent = true } + + vim.api.nvim_buf_set_keymap(bufnr, "n", "gd", "lua vim.lsp.buf.definition()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gD", "lua vim.lsp.buf.declaration()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gi", "lua vim.lsp.buf.implementation()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "K", "lua vim.lsp.buf.hover()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "", "lua vim.lsp.buf.signature_help()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "gr", "lua vim.lsp.buf.references()", opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "[d", 'lua vim.diagnostic.goto_prev({border="rounded"})', opts) + vim.api.nvim_buf_set_keymap(bufnr, "n", "]d", 'lua vim.diagnostic.goto_next({border="rounded"})', opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "lr", "lua vim.lsp.buf.rename()", opts) + + vim.api.nvim_buf_set_keymap(bufnr, "n", "q", "lua vim.diagnostic.setloclist()", opts) + + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "td", + "lua require 'telescope.builtin'.diagnostics()", + opts + ) + vim.api.nvim_buf_set_keymap( + bufnr, + "n", + "tr", + "lua require 'telescope.builtin'.lsp_references()", + opts + ) +end + +local status_ok, cmp_nvim_lsp = pcall(require, "cmp_nvim_lsp") +if not status_ok then + print("Failed to require cmp_nvim_lsp") + return +end + +local client_capabilities = vim.lsp.protocol.make_client_capabilities() +local capabilities = cmp_nvim_lsp.default_capabilities(client_capabilities) +capabilities.offsetEncoding = { "utf-8", "utf-16" } +---@brief +--- +--- https://github.com/typescript-language-server/typescript-language-server +--- +--- `ts_ls`, aka `typescript-language-server`, is a Language Server Protocol implementation for TypeScript wrapping `tsserver`. Note that `ts_ls` is not `tsserver`. +--- +--- `typescript-language-server` depends on `typescript`. Both packages can be installed via `npm`: +--- ```sh +--- npm install -g typescript typescript-language-server +--- ``` +--- +--- To configure typescript language server, add a +--- [`tsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) or +--- [`jsconfig.json`](https://code.visualstudio.com/docs/languages/jsconfig) to the root of your +--- project. +--- +--- Here's an example that disables type checking in JavaScript files. +--- +--- ```json +--- { +--- "compilerOptions": { +--- "module": "commonjs", +--- "target": "es6", +--- "checkJs": false +--- }, +--- "exclude": [ +--- "node_modules" +--- ] +--- } +--- ``` +--- +--- ### Vue support +--- +--- As of 2.0.0, Volar no longer supports TypeScript itself. Instead, a plugin +--- adds Vue support to this language server. +--- +--- *IMPORTANT*: It is crucial to ensure that `@vue/typescript-plugin` and `volar `are of identical versions. +--- +--- ```lua +--- vim.lsp.config('ts_ls', { +--- init_options = { +--- plugins = { +--- { +--- name = "@vue/typescript-plugin", +--- location = "/usr/local/lib/node_modules/@vue/typescript-plugin", +--- languages = {"javascript", "typescript", "vue"}, +--- }, +--- }, +--- }, +--- filetypes = { +--- "javascript", +--- "typescript", +--- "vue", +--- }, +--- }) +--- +--- -- You must make sure volar is setup +--- -- e.g. require'lspconfig'.volar.setup{} +--- -- See volar's section for more information +--- ``` +--- +--- `location` MUST be defined. If the plugin is installed in `node_modules`, +--- `location` can have any value. +--- +--- `languages` must include `vue` even if it is listed in `filetypes`. +--- +--- `filetypes` is extended here to include Vue SFC. + +return { + init_options = { hostInfo = 'neovim' }, + cmd = { 'typescript-language-server', '--stdio' }, + filetypes = { + 'javascript', + 'javascriptreact', + 'javascript.jsx', + 'typescript', + 'typescriptreact', + 'typescript.tsx', + }, + root_markers = { 'tsconfig.json', 'jsconfig.json', 'package.json', '.git' }, + capabilities = capabilities, + on_attach = function(client, bufnr) + lsp_keymaps(bufnr) + lsp_highlight_document(client) + end, +} diff --git a/nvim/lua/_alpha.lua b/nvim/lua/_alpha.lua new file mode 100644 index 0000000..eef2d2f --- /dev/null +++ b/nvim/lua/_alpha.lua @@ -0,0 +1,12 @@ +local status_ok, alpha = pcall(require, "alpha") +if not status_ok then + return +end + +local dashboard = require("alpha.themes.dashboard") +dashboard.section.header.val = {} +dashboard.section.buttons.val = {} +dashboard.section.footer.val = "An idiot admires complexity, a genius admires simplicity. -- Terry A. Davis" +dashboard.opts.opts.noautocmd = true + +alpha.setup(dashboard.opts) diff --git a/nvim/lua/_autopairs.lua b/nvim/lua/_autopairs.lua new file mode 100644 index 0000000..5121307 --- /dev/null +++ b/nvim/lua/_autopairs.lua @@ -0,0 +1,36 @@ +local status_ok, npairs = pcall(require, "nvim-autopairs") +if not status_ok then + return +end + +npairs.setup { + check_ts = true, + ts_config = { + lua = { "string", "source" }, + javascript = { "string","template_string"}, + java = false, + }, + + disable_filetype = { "TelescopePrompt", "spectre_panel" }, + fast_wrap = { + map = "", + chars = { "{", "[", "(", '"', "'" }, + pattern = string.gsub([[ [%'%"%)%>%]%)%}%,] ]], "%s+", ""), + offset = 0, -- Offset from pattern match + end_key = "$", + keys = "qwertyuiopzxcvbnmasdfghjkl", + check_comma = true, + highlight = "PmenuSel", + highlight_grey = "LineNr", + }, + +} + +local cmp_autopairs = require("nvim-autopairs.completion.cmp") +local cmp_status_ok, cmp = pcall(require, "cmp") + +if not cmp_status_ok then + return +end + +cmp.event:on("confirm_done", cmp_autopairs.on_confirm_done() ) diff --git a/nvim/lua/_cmp.lua b/nvim/lua/_cmp.lua new file mode 100644 index 0000000..5db15a8 --- /dev/null +++ b/nvim/lua/_cmp.lua @@ -0,0 +1,133 @@ +local cmp = require 'cmp' + +local snip_status_ok, luasnip = pcall(require, "luasnip") +if not snip_status_ok then + return +end + +require("luasnip/loaders/from_vscode").lazy_load() + +local check_backspace = function() + local col = vim.fn.col "." - 1 + return col == 0 or vim.fn.getline("."):sub(col, col):match "%s" +end + +local kind_icons = { + Text = "", + Method = "󰆧", + Function = "󰊕", + Constructor = "", + Field = "󰇽", + Variable = "󰂡", + Class = "󰠱", + Interface = "", + Module = "", + Property = "󰜢", + Unit = "", + Value = "󰎠", + Enum = "", + Keyword = "󰌋", + Snippet = "", + Color = "󰏘", + File = "󰈙", + Reference = "", + Folder = "󰉋", + EnumMember = "", + Constant = "󰏿", + Struct = "", + Event = "", + Operator = "󰆕", + TypeParameter = "󰅲", +} + +-- find more here: https://www.nerdfonts.com/cheat-sheet +-- +cmp.setup { + snippet = { + expand = function(args) + luasnip.lsp_expand(args.body) -- For `luasnip` users. + end, + }, + mapping = { + [""] = cmp.mapping.select_prev_item(), + [""] = cmp.mapping.select_next_item(), + [""] = cmp.mapping(cmp.mapping.scroll_docs(-1), { "i", "c" }), + [""] = cmp.mapping(cmp.mapping.scroll_docs(1), { "i", "c" }), + [""] = cmp.mapping(cmp.mapping.complete(), { "i", "c" }), + [""] = cmp.config.disable, -- Specify `cmp.config.disable` if you want to remove the default `` mapping. + [""] = cmp.mapping { + i = cmp.mapping.abort(), + c = cmp.mapping.close(), + }, + -- Accept currently selected item. If none selected, `select` first item. + -- Set `select` to `false` to only confirm explicitly selected items. + [""] = cmp.mapping.confirm { select = false }, + [""] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_next_item() + elseif luasnip.expandable() then + luasnip.expand() + elseif luasnip.expand_or_jumpable() then + luasnip.expand_or_jump() + elseif check_backspace() then + fallback() + else + fallback() + end + end, { + "i", + "s", + }), + [""] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_prev_item() + elseif luasnip.jumpable(-1) then + luasnip.jump(-1) + else + fallback() + end + end, { + "i", + "s", + }), + }, + formatting = { + fields = { "kind", "abbr", "menu" }, + format = function(entry, vim_item) + -- Kind icons + -- vim_item.kind = string.format("%s", kind_icons[vim_item.kind] or vim_item.kind) + vim_item.kind = string.format('%s', kind_icons[vim_item.kind] or vim_item.kind) + vim_item.menu = ({ + nvim_lsp = "[LSP]", + nvim_lua = "[NVIM_LUA]", + luasnip = "[Snippet]", + buffer = "[Buffer]", + path = "[Path]", + })[entry.source.name] + return vim_item + end, + }, + sources = { + { name = "nvim_lsp" }, + { name = "nvim_lua" }, + { name = "luasnip" }, + { name = "buffer" }, + { name = "path" }, + }, + confirm_opts = { + behavior = cmp.ConfirmBehavior.Replace, + select = false, + }, + window = { + documentation = cmp.config.window.bordered(), + completion = cmp.config.window.bordered(), + }, + experimental = { + ghost_text = true, + native_menu = false, + }, +} + +local cmp_autopairs = require('nvim-autopairs.completion.cmp') + +cmp.event:on('confirm_done', cmp_autopairs.on_confirm_done()) diff --git a/nvim/lua/_gitsigns.lua b/nvim/lua/_gitsigns.lua new file mode 100644 index 0000000..87b3eed --- /dev/null +++ b/nvim/lua/_gitsigns.lua @@ -0,0 +1,55 @@ +local status_ok, gitsigns = pcall(require, "gitsigns") +if not status_ok then + return +end + +gitsigns.setup { + signs = { + add = { text = '┃' }, + change = { text = '┃' }, + delete = { text = '_' }, + topdelete = { text = '‾' }, + changedelete = { text = '~' }, + untracked = { text = '┆' }, + }, + signs_staged = { + add = { text = '┃' }, + change = { text = '┃' }, + delete = { text = '_' }, + topdelete = { text = '‾' }, + changedelete = { text = '~' }, + untracked = { text = '┆' }, + }, + signs_staged_enable = true, + signcolumn = true, -- Toggle with `:Gitsigns toggle_signs` + numhl = false, -- Toggle with `:Gitsigns toggle_numhl` + linehl = false, -- Toggle with `:Gitsigns toggle_linehl` + word_diff = false, -- Toggle with `:Gitsigns toggle_word_diff` + watch_gitdir = { + follow_files = true + }, + auto_attach = true, + attach_to_untracked = false, + current_line_blame = true, -- Toggle with `:Gitsigns toggle_current_line_blame` + current_line_blame_opts = { + virt_text = true, + virt_text_pos = 'eol', -- 'eol' | 'overlay' | 'right_align' + delay = 1000, + ignore_whitespace = false, + virt_text_priority = 100, + use_focus = true, + }, + current_line_blame_formatter = ', - ', + sign_priority = 6, + update_debounce = 100, + status_formatter = nil, -- Use default + max_file_length = 40000, -- Disable if file is longer than this (in lines) + preview_config = { + -- Options passed to nvim_open_win + border = 'single', + style = 'minimal', + relative = 'cursor', + row = 0, + col = 1 + }, +} diff --git a/nvim/lua/_gruvbox.lua b/nvim/lua/_gruvbox.lua new file mode 100644 index 0000000..300a466 --- /dev/null +++ b/nvim/lua/_gruvbox.lua @@ -0,0 +1,8 @@ +require("gruvbox").setup({ + overrides = { + SignColumn = { bg = "#282828" } + }, + transparent_mode = false, +}) +vim.o.background = "dark" +vim.cmd([[colorscheme gruvbox]]) diff --git a/nvim/lua/_indentline.lua b/nvim/lua/_indentline.lua new file mode 100644 index 0000000..6da9419 --- /dev/null +++ b/nvim/lua/_indentline.lua @@ -0,0 +1,3 @@ +local hooks = require "ibl.hooks" +hooks.register(hooks.type.WHITESPACE, hooks.builtin.hide_first_space_indent_level) +require("ibl").setup() diff --git a/nvim/lua/_keymaps.lua b/nvim/lua/_keymaps.lua new file mode 100644 index 0000000..c05d3cb --- /dev/null +++ b/nvim/lua/_keymaps.lua @@ -0,0 +1,142 @@ +local opts = { noremap = true, silent = true } +local term_opts = { silent = true } +local keymap = vim.api.nvim_set_keymap + +-- Set leader to space +keymap("", "", "", opts) +vim.g.mapleader = " " +vim.g.maplocalleader = " " + +keymap("n", "e", "NvimTreeToggle", opts) + +-- Old config... + +ZenActive = true + +local function toggle_zen() + if not ZenActive then + ZenActive = true + + vim.cmd("set nonumber") + vim.cmd("set norelativenumber") + vim.lsp.inlay_hint.enable(false) + else + ZenActive = false + + vim.cmd("set relativenumber") + vim.cmd("set number") + vim.lsp.inlay_hint.enable(true) + end +end + +vim.api.nvim_create_user_command("ToggleZen", toggle_zen, {}) + +keymap("n", "", "ToggleZen", opts) +keymap("n", "h", "nohl", opts) + +local function format_with_prettier() + vim.fn.system('pnpm exec prettier --write ' .. vim.fn.expand('%:p')) + vim.cmd('edit') -- Reload the buffer after formatting +end +vim.api.nvim_create_user_command("FormatWithPrettier", format_with_prettier, {}) +keymap("n", "pr", "writeFormatWithPrettier", opts) + +-- Modes +-- normal_mode = "n", +-- insert_mode = "i", +-- visual_mode = "v", +-- visual_block_mode = "x", +-- term_mode = "t", +-- command_mode = "c", + +keymap("n", "", "h", opts) +keymap("n", "", "j", opts) +keymap("n", "", "k", opts) +keymap("n", "", "l", opts) +keymap("n", "", "%bd|e#|bd#", opts) + + +keymap("n", "", ":resize +2", opts) +keymap("n", "", ":resize -2", opts) +keymap("n", "", ":vertical resize -2", opts) +keymap("n", "", ":vertical resize +2", opts) + +-- Navigate buffers +keymap("n", "", ":bnext", opts) +keymap("n", "", ":bprevious", opts) + +-- Visual -- +-- Stay in indent mode +keymap("v", "<", "", ">gv", opts) +keymap("v", "p", '"_dP', opts) + +-- Move text up and down +keymap("x", "", ":move '>+1gv-gv", opts) +keymap("x", "", ":move '<-2gv-gv", opts) + +keymap( + "n", + "tm", + "lua require 'telescope.builtin'.lsp_document_symbols({ symbols = { 'method', 'function' } })", + opts +) + +keymap( + "n", + "f", + "lua require'telescope.builtin'.find_files(require('telescope.themes').get_dropdown({ previewer = false }))", + opts +) +keymap("n", "tg", "Telescope live_grep", opts) + + +keymap("n", "w", "lua vim.lsp.buf.format({async = false})w", opts) +keymap("n", "c", "bdelete", opts) + +keymap( + "n", + "", + [[set so=999 /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/jjj^0 nohl set so=6]], + opts +) + +keymap( + "n", + "", + [[set so=999 ?\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/nnjjj^0 nohl set so=6]], + opts +) + +vim.g.font_size = 10 +vim.o.guifont = "JetbrainsMono Nerd Font:h" .. vim.g.font_size + +keymap("n", "", "5", opts) + +vim.keymap.set( + "n", + "", + [[lua vim.g.font_size = vim.g.font_size - 1lua vim.o.guifont='JetbrainsMono Nerd Font:h'..vim.g.font_size]] +) + +vim.keymap.set( + "n", + "", + [[lua vim.g.font_size = vim.g.font_size + 1lua vim.o.guifont='JetbrainsMono Nerd Font:h'..vim.g.font_size]] +) +keymap("n", "\\", "ToggleTerm", opts) +keymap("t", "\\", "ToggleTerm", opts) + +vim.api.nvim_set_keymap( + "v", + "re", + [[ lua require('refactoring').refactor('Extract Function')]], + { noremap = true, silent = true, expr = false } +) + +vim.api.nvim_set_keymap( + "v", + "rf", + [[ lua require('refactoring').refactor('Extract Function To File')]], + { noremap = true, silent = true, expr = false } +) diff --git a/nvim/lua/_lsp.lua b/nvim/lua/_lsp.lua new file mode 100644 index 0000000..bfd134b --- /dev/null +++ b/nvim/lua/_lsp.lua @@ -0,0 +1,120 @@ +local function supported_by_prettier(filetype) + local filetypes = { + 'javascript', + 'javascriptreact', + 'javascript.jsx', + 'typescript', + 'typescriptreact', + 'typescript.tsx', + 'vue', + 'svelte', + 'astro', + -- html + 'aspnetcorerazor', + 'astro', + 'astro-markdown', + 'blade', + 'clojure', + 'django-html', + 'htmldjango', + 'edge', + 'eelixir', -- vim ft + 'elixir', + 'ejs', + 'erb', + 'eruby', -- vim ft + 'gohtml', + 'gohtmltmpl', + 'haml', + 'handlebars', + 'hbs', + 'html', + 'htmlangular', + 'html-eex', + 'heex', + 'jade', + 'leaf', + 'liquid', + 'markdown', + 'mdx', + 'mustache', + 'njk', + 'nunjucks', + 'php', + 'razor', + 'slim', + 'twig', + -- css + 'css', + 'less', + 'postcss', + 'sass', + 'scss', + 'stylus', + 'sugarss', + -- js + 'javascript', + 'javascriptreact', + 'reason', + 'rescript', + 'typescript', + 'typescriptreact', + -- mixed + 'vue', + 'svelte', + 'templ', + } + + for _, v in ipairs(filetypes) do + if v == filetype then + return true + end + end + return false +end + +local config = { + virtual_text = true, + signs = { + text = { + [vim.diagnostic.severity.ERROR] = '', + [vim.diagnostic.severity.WARN] = '', + [vim.diagnostic.severity.INFO] = '', + [vim.diagnostic.severity.HINT] = '', + } + }, + update_in_insert = true, + underline = true, + severity_sort = true, + float = { + focusable = false, + style = "normal", + border = "rounded", + source = "always", + header = "", + prefix = "", + }, +} + +vim.filetype.add({ + extension = { + svx = "markdown", + } +}) + +vim.diagnostic.config(config) + +vim.lsp.buf.hover({ border = "rounded" }) +vim.lsp.buf.signature_help({ border = "rounded" }) +vim.lsp.enable({ + 'clangd', + 'luals', + + 'svelte', + 'tailwindcss', + "ts_ls", + "cssls", + "eslint", + "mdx_analyzer", +}) + diff --git a/nvim/lua/_lualine.lua b/nvim/lua/_lualine.lua new file mode 100644 index 0000000..f455fc9 --- /dev/null +++ b/nvim/lua/_lualine.lua @@ -0,0 +1,103 @@ +local status_ok, lualine = pcall(require, "lualine") +if not status_ok then + return +end + +local branch = { + "branch", + icons_enabled = true, + icon = "", +} + +local diff = { + "diff", + colored = false, + symbols = { added = " ", modified = " ", removed = " " }, -- changes diff symbols +} + +local location = { + "location", + padding = 0, +} + +local colors = { + blue = "#458588", + green = "#98971a", + purple = "#b16286", + cyan = "#83a598", + red1 = "#cc241d", + yellow = "#d79921", + fg = "#ebdbb2", + bg = "#282828", + gray1 = "#928374", + gray2 = "#7c6f64", + gray3 = "#665c54", +} + +local gruvbox = { + normal = { + a = { fg = colors.bg, bg = colors.blue, gui = "bold" }, + c = { fg = colors.bg, bg = colors.blue, gui = "bold" }, + z = { fg = colors.bg, bg = colors.blue, gui = "bold" }, + }, + command = { + a = { fg = colors.bg, bg = colors.yellow, gui = "bold" }, + c = { fg = colors.bg, bg = colors.yellow, gui = "bold" }, + z = { fg = colors.bg, bg = colors.yellow, gui = "bold" }, + }, + insert = { + a = { fg = colors.bg, bg = colors.green, gui = "bold" }, + c = { fg = colors.bg, bg = colors.green, gui = "bold" }, + z = { fg = colors.bg, bg = colors.green, gui = "bold" }, + }, + visual = { + a = { fg = colors.bg, bg = colors.purple, gui = "bold" }, + c = { fg = colors.bg, bg = colors.purple, gui = "bold" }, + z = { fg = colors.bg, bg = colors.purple, gui = "bold" }, + }, + terminal = { + a = { fg = colors.bg, bg = colors.cyan, gui = "bold" }, + c = { fg = colors.bg, bg = colors.cyan, gui = "bold" }, + z = { fg = colors.bg, bg = colors.cyan, gui = "bold" }, + }, + replace = { + a = { fg = colors.bg, bg = colors.red1, gui = "bold" }, + c = { fg = colors.bg, bg = colors.red1, gui = "bold" }, + z = { fg = colors.bg, bg = colors.red1, gui = "bold" }, + }, + inactive = { + a = { fg = colors.gray1, bg = colors.bg, gui = "bold" }, + c = { fg = colors.gray1, bg = colors.bg, gui = "bold" }, + z = { fg = colors.gray1, bg = colors.bg, gui = "bold" }, + }, +} + +lualine.setup({ + options = { + icons_enabled = true, + theme = gruvbox, + component_separators = { left = "", right = "" }, + section_separators = { left = "", right = "" }, + disabled_filetypes = { "dashboard", "NvimTree", "Outline" }, + always_divide_middle = true, + }, + sections = { + lualine_a = { "filename" }, + lualine_b = { { "diagnostics", colored = false }}, + lualine_c = {}, + lualine_x = {branch, diff}, + lualine_y = { }, + lualine_z = { }, + }, + inactive_sections = { + lualine_a = { "filename" }, + lualine_b = {}, + lualine_c = {}, + lualine_x = {}, + lualine_y = {}, + lualine_z = {}, + }, + tabline = {}, + extensions = {}, +}) + diff --git a/nvim/lua/_nvim_tree.lua b/nvim/lua/_nvim_tree.lua new file mode 100644 index 0000000..a1ab8b4 --- /dev/null +++ b/nvim/lua/_nvim_tree.lua @@ -0,0 +1,75 @@ +local status_ok, nvim_tree = pcall(require, "nvim-tree") +if not status_ok then + return +end + +local function my_on_attach(bufnr) + local api = require "nvim-tree.api" + + local function opts(desc) + return { desc = "nvim-tree: " .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true } + end + + -- default mappings + api.config.mappings.default_on_attach(bufnr) + + -- custom mappings + vim.keymap.set('n', '', api.tree.change_root_to_parent, opts('Up')) + vim.keymap.set('n', '?', api.tree.toggle_help, opts('Help')) +end + +nvim_tree.setup({ + on_attach = my_on_attach, + actions = { + open_file = { + quit_on_open = true, + }, + }, + + update_focused_file = { + enable = true, + update_cwd = false, + }, + renderer = { + root_folder_modifier = ":t", + icons = { + glyphs = { + default = "", + symlink = "", + folder = { + arrow_open = "", + arrow_closed = "", + default = "", + open = "", + empty = "", + empty_open = "", + symlink = "", + symlink_open = "", + }, + git = { + unstaged = "", + staged = "S", + unmerged = "", + renamed = "➜", + untracked = "U", + deleted = "", + ignored = "◌", + }, + }, + }, + }, + diagnostics = { + enable = false, + show_on_dirs = true, + icons = { + hint = "", + info = "", + warning = "", + error = "", + }, + }, + view = { + width = 36, + side = "right", + }, +}) diff --git a/nvim/lua/_options.lua b/nvim/lua/_options.lua new file mode 100644 index 0000000..d125501 --- /dev/null +++ b/nvim/lua/_options.lua @@ -0,0 +1,41 @@ +vim.g.loaded_netrw = 1 +vim.g.loaded_netrwPlugin = 1 +vim.opt.clipboard = "unnamedplus" +vim.opt.completeopt = "menuone,noselect" +vim.opt.fileencoding = "utf-32" +vim.opt.ignorecase = true +vim.opt.pumheight = 12 +vim.opt.splitbelow = true +vim.opt.splitright = true +vim.opt.swapfile = false +vim.opt.termguicolors = true +vim.opt.undofile = true +vim.opt.updatetime = 300 +vim.opt.signcolumn = "yes" +vim.opt.wrap = false +vim.opt.scrolloff = 6 +vim.opt.sidescrolloff = 6 +vim.opt.showmode = false +vim.opt.colorcolumn = "100" +vim.opt.expandtab = true +vim.opt.shiftwidth = 4 +vim.opt.tabstop = 4 +vim.opt.autoindent = true +vim.opt.showtabline = 0 +vim.opt.cursorline = false +vim.opt.numberwidth = 4 +vim.opt.shortmess:append("c") +vim.opt.laststatus = 1 +vim.cmd('let g:neovide_cursor_vfx_mode = "pixiedust"') +vim.cmd("let g:neovide_cursor_vfx_particle_density = 32.0") + +-- lastplace +vim.api.nvim_create_autocmd('BufReadPost', { + callback = function() + local mark = vim.api.nvim_buf_get_mark(0, '"') + local lcount = vim.api.nvim_buf_line_count(0) + if mark[1] > 0 and mark[1] <= lcount then + vim.api.nvim_win_set_cursor(0, mark) + end + end +}) diff --git a/nvim/lua/_plugins.lua b/nvim/lua/_plugins.lua new file mode 100644 index 0000000..98992ea --- /dev/null +++ b/nvim/lua/_plugins.lua @@ -0,0 +1,38 @@ +require("_plugins_bootstrap") +require("lazy").setup({ + spec = { + -- Core + { 'nvim-lua/plenary.nvim' }, + + -- Navigation + { "kyazdani42/nvim-tree.lua" }, + { 'nvim-telescope/telescope.nvim' }, + { "slarwise/telescope-args.nvim" }, + + -- Aesthetics + { "lukas-reineke/indent-blankline.nvim" }, + { "nvim-treesitter/nvim-treesitter", }, + { "kyazdani42/nvim-web-devicons" }, + { "nvim-lualine/lualine.nvim" }, + { "ellisonleao/gruvbox.nvim" }, + { "lewis6991/gitsigns.nvim" }, + { "goolord/alpha-nvim" }, + { "xiyaowong/transparent.nvim" }, + + -- Auto-complete + { "hrsh7th/nvim-cmp" }, + { "hrsh7th/cmp-nvim-lsp" }, + { "hrsh7th/cmp-nvim-lua" }, + { "hrsh7th/cmp-buffer" }, + { "hrsh7th/cmp-path" }, + { "hrsh7th/cmp-cmdline" }, + { "saadparwaiz1/cmp_luasnip" }, + { "windwp/nvim-autopairs" }, + { "L3MON4D3/LuaSnip" }, + + -- Lsp + { "neovim/nvim-lspconfig" }, + }, + install = { colorscheme = { "gruvbox" } }, + checker = { enabled = true }, +}) diff --git a/nvim/lua/_plugins_bootstrap.lua b/nvim/lua/_plugins_bootstrap.lua new file mode 100644 index 0000000..59dc9f0 --- /dev/null +++ b/nvim/lua/_plugins_bootstrap.lua @@ -0,0 +1,17 @@ +local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" +if not (vim.uv or vim.loop).fs_stat(lazypath) then + local lazyrepo = "https://github.com/folke/lazy.nvim.git" + local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) + if vim.v.shell_error ~= 0 then + vim.api.nvim_echo({ + { "Failed to clone lazy.nvim:\n", "ErrorMsg" }, + { out, "WarningMsg" }, + { "\nPress any key to exit..." }, + }, true, {}) + vim.fn.getchar() + os.exit(1) + end +end +vim.opt.rtp:prepend(lazypath) +vim.g.mapleader = " " +vim.g.maplocalleader = "\\" diff --git a/nvim/lua/_telescope.lua b/nvim/lua/_telescope.lua new file mode 100644 index 0000000..d595ae0 --- /dev/null +++ b/nvim/lua/_telescope.lua @@ -0,0 +1,98 @@ +local status_ok, telescope = pcall(require, "telescope") +if not status_ok then + return +end + +telescope.load_extension("args") +local actions = require("telescope.actions") + +telescope.setup({ + defaults = { + + file_ignore_patterns = { "doxygen", "^build", "^tests/assets", ".*\\.png$" }, + prompt_prefix = " ", + selection_caret = " ", + path_display = { "truncate" }, + + mappings = { + i = { + [""] = actions.cycle_history_next, + [""] = actions.cycle_history_prev, + + [""] = actions.move_selection_next, + [""] = actions.move_selection_previous, + + [""] = actions.close, + + [""] = actions.move_selection_next, + [""] = actions.move_selection_previous, + + [""] = actions.select_default, + [""] = actions.select_horizontal, + [""] = actions.select_vertical, + [""] = actions.select_tab, + + [""] = actions.preview_scrolling_up, + [""] = actions.preview_scrolling_down, + + [""] = actions.results_scrolling_up, + [""] = actions.results_scrolling_down, + + [""] = actions.toggle_selection + actions.move_selection_worse, + [""] = actions.toggle_selection + actions.move_selection_better, + [""] = actions.send_to_qflist + actions.open_qflist, + [""] = actions.send_selected_to_qflist + actions.open_qflist, + [""] = actions.complete_tag, + [""] = actions.which_key, -- keys from pressing + }, + + n = { + [""] = actions.close, + [""] = actions.select_default, + [""] = actions.select_horizontal, + [""] = actions.select_vertical, + [""] = actions.select_tab, + + [""] = actions.toggle_selection + actions.move_selection_worse, + [""] = actions.toggle_selection + actions.move_selection_better, + [""] = actions.send_to_qflist + actions.open_qflist, + [""] = actions.send_selected_to_qflist + actions.open_qflist, + + ["j"] = actions.move_selection_next, + ["k"] = actions.move_selection_previous, + ["H"] = actions.move_to_top, + ["M"] = actions.move_to_middle, + ["L"] = actions.move_to_bottom, + + [""] = actions.move_selection_next, + [""] = actions.move_selection_previous, + ["gg"] = actions.move_to_top, + ["G"] = actions.move_to_bottom, + + [""] = actions.preview_scrolling_up, + [""] = actions.preview_scrolling_down, + + [""] = actions.results_scrolling_up, + [""] = actions.results_scrolling_down, + + ["?"] = actions.which_key, + }, + }, + }, + pickers = { + -- Default configuration for builtin pickers goes here: + -- picker_name = { + -- picker_config_key = value, + -- ... + -- } + -- Now the picker_config_key will be applied every time you call this + -- builtin picker + }, + extensions = { + -- Your extension configuration goes here: + -- extension_name = { + -- extension_config_key = value, + -- } + -- please take a look at the readme of the extension you want to configure + }, +}) diff --git a/nvim/lua/_treesitter.lua b/nvim/lua/_treesitter.lua new file mode 100644 index 0000000..4c4853b --- /dev/null +++ b/nvim/lua/_treesitter.lua @@ -0,0 +1,20 @@ +local configs = require("nvim-treesitter.configs") + +configs.setup({ + ensure_installed = "all", + sync_install = false, + ignore_install = { "" }, + autopairs = { + enable = true, + }, + context_commenting = { + enable = true, + enable_autocmd = false, + }, + highlight = { + enable = true, + disable = { "" }, + additional_vim_regex_highlighting = true, + }, + -- indent = { enable = true, disable = { "yaml" } }, +}) diff --git a/nvim/spell/en.utf-8.add b/nvim/spell/en.utf-8.add new file mode 100644 index 0000000..106310c --- /dev/null +++ b/nvim/spell/en.utf-8.add @@ -0,0 +1,28 @@ +intranquility +uv +shader +rasterizer +rasterization +applesthepi +rasterize +#OLINR +NOLINT +NOLINR/! +glm +mat4 +skybox +TransformComponent +param +swapchain +struct +readonly +writeonly +samplerCueb +samplerCube +Vulkan +accessor +const +cmd +str +RDB +Rasterized diff --git a/nvim/spell/en.utf-8.add.spl b/nvim/spell/en.utf-8.add.spl new file mode 100644 index 0000000..206b0fb Binary files /dev/null and b/nvim/spell/en.utf-8.add.spl differ